github.com/prebid/prebid-server/v2@v2.18.0/modules/modules_test.go (about) 1 package modules 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "math" 9 "net/http" 10 "testing" 11 12 "github.com/prebid/prebid-server/v2/config" 13 "github.com/prebid/prebid-server/v2/hooks" 14 "github.com/prebid/prebid-server/v2/hooks/hookstage" 15 "github.com/prebid/prebid-server/v2/modules/moduledeps" 16 "github.com/stretchr/testify/assert" 17 ) 18 19 func TestModuleBuilderBuild(t *testing.T) { 20 vendor := "acme" 21 moduleName := "foobar" 22 defaultModulesConfig := map[string]map[string]interface{}{vendor: {moduleName: map[string]interface{}{"enabled": true}}} 23 defaultHookRepository, err := hooks.NewHookRepository(map[string]interface{}{vendor + "." + moduleName: module{}}) 24 if err != nil { 25 t.Fatalf("Failed to init default hook repository: %s", err) 26 } 27 emptyHookRepository, err := hooks.NewHookRepository(map[string]interface{}{}) 28 if err != nil { 29 t.Fatalf("Failed to init empty hook repository: %s", err) 30 } 31 32 testCases := map[string]struct { 33 givenModule interface{} 34 givenConfig config.Modules 35 givenHookBuilderErr error 36 expectedHookRepo hooks.HookRepository 37 expectedModulesStages map[string][]string 38 expectedErr error 39 }{ 40 "Can build module with config": { 41 givenModule: module{}, 42 givenConfig: defaultModulesConfig, 43 expectedModulesStages: map[string][]string{vendor + "_" + moduleName: {hooks.StageEntrypoint.String(), hooks.StageAuctionResponse.String()}}, 44 expectedHookRepo: defaultHookRepository, 45 expectedErr: nil, 46 }, 47 "Module is not added to hook repository if it's disabled": { 48 givenModule: module{}, 49 givenConfig: map[string]map[string]interface{}{vendor: {moduleName: map[string]interface{}{"enabled": false, "attr": "val"}}}, 50 expectedModulesStages: map[string][]string{}, 51 expectedHookRepo: emptyHookRepository, 52 expectedErr: nil, 53 }, 54 "Module considered disabled if status property not defined in module config": { 55 givenModule: module{}, 56 givenConfig: map[string]map[string]interface{}{vendor: {moduleName: map[string]interface{}{"foo": "bar"}}}, 57 expectedHookRepo: emptyHookRepository, 58 expectedModulesStages: map[string][]string{}, 59 expectedErr: nil, 60 }, 61 "Module considered disabled if its config not provided and as a result skipped from execution": { 62 givenModule: module{}, 63 givenConfig: nil, 64 expectedHookRepo: emptyHookRepository, 65 expectedModulesStages: map[string][]string{}, 66 expectedErr: nil, 67 }, 68 "Fails if module does not implement any hook interface": { 69 givenModule: struct{}{}, 70 givenConfig: defaultModulesConfig, 71 expectedHookRepo: nil, 72 expectedModulesStages: nil, 73 expectedErr: fmt.Errorf(`hook "%s.%s" does not implement any supported hook interface`, vendor, moduleName), 74 }, 75 "Fails if module builder function returns error": { 76 givenModule: module{}, 77 givenConfig: defaultModulesConfig, 78 givenHookBuilderErr: errors.New("failed to build module"), 79 expectedHookRepo: nil, 80 expectedModulesStages: nil, 81 expectedErr: fmt.Errorf(`failed to init "%s.%s" module: %s`, vendor, moduleName, "failed to build module"), 82 }, 83 "Fails if config marshaling returns error": { 84 givenModule: module{}, 85 givenConfig: map[string]map[string]interface{}{vendor: {moduleName: math.Inf(1)}}, 86 expectedHookRepo: nil, 87 expectedModulesStages: nil, 88 expectedErr: fmt.Errorf(`failed to marshal "%s.%s" module config: unsupported value: +Inf`, vendor, moduleName), 89 }, 90 } 91 92 for name, test := range testCases { 93 t.Run(name, func(t *testing.T) { 94 builder := &builder{ 95 builders: ModuleBuilders{ 96 vendor: { 97 moduleName: func(cfg json.RawMessage, deps moduledeps.ModuleDeps) (interface{}, error) { 98 return test.givenModule, test.givenHookBuilderErr 99 }, 100 }, 101 }, 102 } 103 104 repo, modulesStages, err := builder.Build(test.givenConfig, moduledeps.ModuleDeps{HTTPClient: http.DefaultClient}) 105 assert.Equal(t, test.expectedErr, err) 106 assert.Equal(t, test.expectedModulesStages, modulesStages) 107 assert.Equal(t, test.expectedHookRepo, repo) 108 }) 109 } 110 } 111 112 type module struct{} 113 114 func (h module) HandleEntrypointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.EntrypointPayload) (hookstage.HookResult[hookstage.EntrypointPayload], error) { 115 return hookstage.HookResult[hookstage.EntrypointPayload]{}, nil 116 } 117 118 func (h module) HandleAuctionResponseHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.AuctionResponsePayload) (hookstage.HookResult[hookstage.AuctionResponsePayload], error) { 119 return hookstage.HookResult[hookstage.AuctionResponsePayload]{}, nil 120 }