Skip to content

Commit

Permalink
Use Json compacter in the bidders/params endpoint (#3395)
Browse files Browse the repository at this point in the history
  • Loading branch information
guscarreon authored Feb 28, 2024
1 parent fd92015 commit e8267b8
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 1 deletion.
6 changes: 6 additions & 0 deletions endpoints/openrtb2/auction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"time"

"github.com/buger/jsonparser"
jsoniter "github.com/json-iterator/go"
"github.com/julienschmidt/httprouter"
"github.com/prebid/openrtb/v20/native1"
nativeRequests "github.com/prebid/openrtb/v20/native1/request"
Expand All @@ -43,6 +44,11 @@ import (

const jsonFileExtension string = ".json"

func TestMain(m *testing.M) {
jsoniter.RegisterExtension(&jsonutil.RawMessageExtension{})
os.Exit(m.Run())
}

func TestJsonSampleRequests(t *testing.T) {
testSuites := []struct {
description string
Expand Down
3 changes: 3 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import (
"runtime"
"time"

jsoniter "github.com/json-iterator/go"
"github.com/prebid/prebid-server/v2/config"
"github.com/prebid/prebid-server/v2/currency"
"github.com/prebid/prebid-server/v2/openrtb_ext"
"github.com/prebid/prebid-server/v2/router"
"github.com/prebid/prebid-server/v2/server"
"github.com/prebid/prebid-server/v2/util/jsonutil"
"github.com/prebid/prebid-server/v2/util/task"

"github.com/golang/glog"
Expand All @@ -21,6 +23,7 @@ import (

func init() {
rand.Seed(time.Now().UnixNano())
jsoniter.RegisterExtension(&jsonutil.RawMessageExtension{})
}

func main() {
Expand Down
1 change: 1 addition & 0 deletions openrtb_ext/bidders.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,7 @@ func NewBidderParamsValidator(schemaDirectory string) (BidderParamValidator, err
if _, ok := bidderMap[bidderName]; !ok {
return nil, fmt.Errorf("File %s/%s does not match a valid BidderName.", schemaDirectory, fileInfo.Name())
}

toOpen, err := paramsValidator.abs(filepath.Join(schemaDirectory, fileInfo.Name()))
if err != nil {
return nil, fmt.Errorf("Failed to get an absolute representation of the path: %s, %v", toOpen, err)
Expand Down
27 changes: 27 additions & 0 deletions router/bidder_params_tests/appnexus.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Sample schema",
"description": "A sample schema to test the bidder/params endpoint",
"type": "object",
"properties": {
"integer_param": {
"type": "integer",
"minimum": 1,
"description": "A customer id"
},
"string_param_1": {
"type": "string",
"minLength": 1,
"description": "Text with blanks in between"
},
"string_param_2": {
"type": "string",
"minLength": 1,
"description": "Text_with_no_blanks_in_between"
}
},
"required": [
"integer_param",
"string_param_2"
]
}
2 changes: 1 addition & 1 deletion router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func newJsonDirectoryServer(schemaDirectory string, validator openrtb_ext.Bidder
data[aliasName] = bidderData
}

response, err := json.Marshal(data)
response, err := jsonutil.Marshal(data)
if err != nil {
glog.Fatalf("Failed to marshal bidder param JSON-schema: %v", err)
}
Expand Down
26 changes: 26 additions & 0 deletions router/router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"testing"

jsoniter "github.com/json-iterator/go"
"github.com/prebid/prebid-server/v2/config"
"github.com/prebid/prebid-server/v2/openrtb_ext"
"github.com/prebid/prebid-server/v2/util/jsonutil"
Expand All @@ -18,6 +19,11 @@ const adapterDirectory = "../adapters"

type testValidator struct{}

func TestMain(m *testing.M) {
jsoniter.RegisterExtension(&jsonutil.RawMessageExtension{})
os.Exit(m.Run())
}

func (validator *testValidator) Validate(name openrtb_ext.BidderName, ext json.RawMessage) error {
return nil
}
Expand Down Expand Up @@ -275,3 +281,23 @@ func TestValidateDefaultAliases(t *testing.T) {
}
}
}

func TestBidderParamsCompactedOutput(t *testing.T) {
expectedFormattedResponse := `{"appnexus":{"$schema":"http://json-schema.org/draft-04/schema#","title":"Sample schema","description":"A sample schema to test the bidder/params endpoint","type":"object","properties":{"integer_param":{"type":"integer","minimum":1,"description":"A customer id"},"string_param_1":{"type":"string","minLength":1,"description":"Text with blanks in between"},"string_param_2":{"type":"string","minLength":1,"description":"Text_with_no_blanks_in_between"}},"required":["integer_param","string_param_2"]}}`

// Setup
inSchemaDirectory := "bidder_params_tests"
paramsValidator, err := openrtb_ext.NewBidderParamsValidator(inSchemaDirectory)
assert.NoError(t, err, "Error initialing validator")

handler := newJsonDirectoryServer(inSchemaDirectory, paramsValidator, nil, nil)
recorder := httptest.NewRecorder()
request, err := http.NewRequest("GET", "/bidder/params", nil)
assert.NoError(t, err, "Error creating request")

// Run
handler(recorder, request, nil)

// Assertions
assert.Equal(t, expectedFormattedResponse, recorder.Body.String())
}
37 changes: 37 additions & 0 deletions util/jsonutil/jsonutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import (
"encoding/json"
"io"
"strings"
"unsafe"

jsoniter "github.com/json-iterator/go"
"github.com/modern-go/reflect2"
"github.com/prebid/prebid-server/v2/errortypes"
)

Expand Down Expand Up @@ -211,3 +213,38 @@ func tryExtractErrorMessage(err error) string {
func isLikelyDetailedErrorMessage(msg string) bool {
return !strings.HasPrefix(msg, "request.")
}

// RawMessageExtension will call json.Compact() on every json.RawMessage field when getting marshalled.
type RawMessageExtension struct {
jsoniter.DummyExtension
}

// CreateEncoder substitutes the default jsoniter encoder of the json.RawMessage type with ours, that
// calls json.Compact() before writting to the stream
func (e *RawMessageExtension) CreateEncoder(typ reflect2.Type) jsoniter.ValEncoder {
if typ == jsonRawMessageType {
return &rawMessageCodec{}
}
return nil
}

var jsonRawMessageType = reflect2.TypeOfPtr(&json.RawMessage{}).Elem()

// rawMessageCodec implements jsoniter.ValEncoder interface so we can override the default json.RawMessage Encode()
// function with our implementation
type rawMessageCodec struct{}

func (codec *rawMessageCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
if ptr != nil {
jsonRawMsg := *(*[]byte)(ptr)

dst := bytes.NewBuffer(make([]byte, 0, len(jsonRawMsg)))
if err := json.Compact(dst, jsonRawMsg); err == nil {
stream.Write(dst.Bytes())
}
}
}

func (codec *rawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool {
return ptr == nil || len(*((*json.RawMessage)(ptr))) == 0
}
82 changes: 82 additions & 0 deletions util/jsonutil/jsonutil_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package jsonutil

import (
"bytes"
"encoding/json"
"errors"
"strings"
"testing"
"unsafe"

jsoniter "github.com/json-iterator/go"
"github.com/modern-go/reflect2"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -240,3 +245,80 @@ func TestTryExtractErrorMessage(t *testing.T) {
})
}
}

func TestCreateEncoder(t *testing.T) {
testCases := []struct {
desc string
inType reflect2.Type
expectedValEncoder jsoniter.ValEncoder
}{
{
desc: "With_extension",
inType: reflect2.TypeOfPtr((*jsoniter.Any)(nil)).Elem(),
expectedValEncoder: nil,
},
{
desc: "No_extension",
inType: reflect2.TypeOfPtr(&json.RawMessage{}).Elem(),
expectedValEncoder: &rawMessageCodec{},
},
}

for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
extension := &RawMessageExtension{}
encoder := extension.CreateEncoder(tc.inType)
assert.IsType(t, encoder, tc.expectedValEncoder)
})
}
}

func TestEncode(t *testing.T) {
jsonBlob := json.RawMessage(`{
"properties": {
"string": "Blanks spaces in between words to not be removed if compacted",
"integer": 5,
"string_array": [
"string array elem one",
"string array elem two"
]
}
}`)

t.Run(
"Nil_pointer",
func(t *testing.T) {
// set test
encoder := &rawMessageCodec{}
output := bytes.NewBuffer([]byte{})
stream := jsoniter.NewStream(jsonConfigValidationOn, output, len(jsonBlob))

// run
encoder.Encode(nil, stream)

// assertions
assert.Equal(t, "", output.String())
assert.Equal(t, true, encoder.IsEmpty(nil))
},
)
t.Run(
"json.RawMessage_compact_JSON",
func(t *testing.T) {
// set test
encoder := &rawMessageCodec{}
output := bytes.NewBuffer([]byte{})
stream := jsoniter.NewStream(jsonConfigValidationOn, output, len(jsonBlob))

// run
encoder.Encode(unsafe.Pointer(&jsonBlob), stream)

// assertions
assert.Equal(
t,
`{"properties":{"string":"Blanks spaces in between words to not be removed if compacted","integer":5,"string_array":["string array elem one","string array elem two"]}}`,
output.String(),
)
assert.Equal(t, false, encoder.IsEmpty(unsafe.Pointer(&jsonBlob)))
},
)
}

0 comments on commit e8267b8

Please sign in to comment.