forked from prebid/prebid-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpubstack_module_test.go
More file actions
209 lines (189 loc) · 7 KB
/
Copy pathpubstack_module_test.go
File metadata and controls
209 lines (189 loc) · 7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
package pubstack
import (
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
"github.com/benbjohnson/clock"
"github.com/prebid/prebid-server/v4/analytics"
"github.com/prebid/prebid-server/v4/openrtb_ext"
"github.com/stretchr/testify/assert"
)
func TestNewModuleErrors(t *testing.T) {
tests := []struct {
description string
refreshDelay string
maxByteSize string
maxTime string
}{
{
description: "refresh delay is in an invalid format",
refreshDelay: "1invalid",
maxByteSize: "90MB",
maxTime: "15m",
},
{
description: "max byte size is in an invalid format",
refreshDelay: "1h",
maxByteSize: "90invalid",
maxTime: "15m",
},
{
description: "max time is in an invalid format",
refreshDelay: "1h",
maxByteSize: "90MB",
maxTime: "15invalid",
},
}
for _, tt := range tests {
_, err := NewModule(&http.Client{}, "scope", "http://example.com", tt.refreshDelay, 100, tt.maxByteSize, tt.maxTime, clock.NewMock())
assert.Error(t, err, tt.description)
}
}
func TestNewModuleSuccess(t *testing.T) {
tests := []struct {
description string
feature string
logObject func(analytics.Module)
}{
{
description: "auction events are only published when logging an auction object with auction feature on",
feature: auction,
logObject: func(module analytics.Module) {
module.LogAuctionObject(&analytics.AuctionObject{Status: http.StatusOK})
},
},
{
description: "AMP events are only published when logging an AMP object with AMP feature on",
feature: amp,
logObject: func(module analytics.Module) {
module.LogAmpObject(&analytics.AmpObject{Status: http.StatusOK})
},
},
{
description: "video events are only published when logging a video object with video feature on",
feature: video,
logObject: func(module analytics.Module) {
module.LogVideoObject(&analytics.VideoObject{Status: http.StatusOK})
},
},
{
description: "cookie events are only published when logging a cookie object with cookie feature on",
feature: cookieSync,
logObject: func(module analytics.Module) {
module.LogCookieSyncObject(&analytics.CookieSyncObject{Status: http.StatusOK})
},
},
{
description: "setUID events are only published when logging a setUID object with setUID feature on",
feature: setUID,
logObject: func(module analytics.Module) {
module.LogSetUIDObject(&analytics.SetUIDObject{Status: http.StatusOK})
},
},
{
description: "Ignore excluded fields from marshal",
feature: auction,
logObject: func(module analytics.Module) {
module.LogAuctionObject(&analytics.AuctionObject{
RequestWrapper: &openrtb_ext.RequestWrapper{},
SeatNonBid: []openrtb_ext.SeatNonBid{
{
NonBid: []openrtb_ext.NonBid{
{
ImpId: "123",
StatusCode: 34,
Ext: &openrtb_ext.NonBidExt{Prebid: openrtb_ext.ExtResponseNonBidPrebid{Bid: openrtb_ext.NonBidObject{}}},
},
},
},
},
})
},
},
}
for _, tt := range tests {
// original config with the feature disabled so no events should be sent
origConfig := &Configuration{
Features: map[string]bool{
tt.feature: false,
},
}
// updated config with the feature enabled so events should be sent
updatedConfig := &Configuration{
Features: map[string]bool{
tt.feature: true,
},
}
// create server with an intake endpoint that PBS hits when events are sent
mux := http.NewServeMux()
intakeChannel := make(chan int)
mux.HandleFunc("/intake/"+tt.feature+"/", func(res http.ResponseWriter, req *http.Request) {
intakeChannel <- 1
})
server := httptest.NewServer(mux)
client := server.Client()
// set the event server url on each of the configs
origConfig.Endpoint = server.URL
updatedConfig.Endpoint = server.URL
// instantiate module with a manual config update task
clockMock := clock.NewMock()
configTask := fakeConfigUpdateTask{}
module, err := NewModuleWithConfigTask(client, "scope", server.URL, 100, "1B", "1s", &configTask, clockMock)
assert.NoError(t, err, tt.description)
pubstack, _ := module.(*PubstackModule)
// original config
configTask.Push(origConfig)
time.Sleep(10 * time.Millisecond) // allow time for the module to load the original config
tt.logObject(pubstack) // attempt to log; no event channel created because feature is disabled in original config
clockMock.Add(1 * time.Second) // trigger event channel sending
assertChanNone(t, intakeChannel, tt.description+":original") // verify no event was received
// updated config
configTask.Push(updatedConfig)
time.Sleep(10 * time.Millisecond) // allow time for the server to start serving the updated config
tt.logObject(pubstack) // attempt to log; event channel should be created because feature is enabled in updated config
clockMock.Add(1 * time.Second) // trigger event channel sending
assertChanOne(t, intakeChannel, tt.description+":updated") // verify an event was received
// no config change
configTask.Push(updatedConfig)
time.Sleep(10 * time.Millisecond) // allow time for the server to determine no config change
tt.logObject(pubstack) // attempt to log; event channel should still be created from loading updated config
clockMock.Add(1 * time.Second) // trigger event channel sending
assertChanOne(t, intakeChannel, tt.description+":no_change") // verify an event was received
// shutdown
pubstack.sigTermCh <- os.Kill // simulate os shutdown signal
time.Sleep(10 * time.Millisecond) // allow time for the server to switch to shutdown generated config
tt.logObject(pubstack) // attempt to log; event channel should be closed from the os kill signal
clockMock.Add(1 * time.Second) // trigger event channel sending
assertChanNone(t, intakeChannel, tt.description+":shutdown") // verify no event was received
}
}
func assertChanNone(t *testing.T, c <-chan int, msgAndArgs ...interface{}) bool {
t.Helper()
select {
case <-c:
return assert.Fail(t, "Should NOT receive an event, but did", msgAndArgs...)
case <-time.After(100 * time.Millisecond):
return true
}
}
func assertChanOne(t *testing.T, c <-chan int, msgAndArgs ...interface{}) bool {
t.Helper()
select {
case <-c:
return true
case <-time.After(200 * time.Millisecond):
return assert.Fail(t, "Should receive an event, but did NOT", msgAndArgs...)
}
}
type fakeConfigUpdateTask struct {
configChan chan *Configuration
}
func (f *fakeConfigUpdateTask) Start(stop <-chan struct{}) <-chan *Configuration {
f.configChan = make(chan *Configuration)
return f.configChan
}
func (f *fakeConfigUpdateTask) Push(c *Configuration) {
f.configChan <- c
}