prebid.js 9.53.2 → 9.53.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/33acrossAnalyticsAdapter.js +1 -1
- package/dist/33acrossBidAdapter.js +1 -1
- package/dist/33acrossIdSystem.js +1 -1
- package/dist/BTBidAdapter.js +1 -1
- package/dist/adagioAnalyticsAdapter.js +1 -1
- package/dist/adagioBidAdapter.js +1 -1
- package/dist/adagioRtdProvider.js +1 -1
- package/dist/adagioUtils.js +1 -1
- package/dist/addefendBidAdapter.js +1 -1
- package/dist/adgenerationBidAdapter.js +1 -1
- package/dist/adlooxRtdProvider.js +1 -1
- package/dist/adqueryBidAdapter.js +1 -1
- package/dist/adrelevantisBidAdapter.js +1 -1
- package/dist/adstirBidAdapter.js +1 -1
- package/dist/adtrgtmeBidAdapter.js +1 -1
- package/dist/adxcgAnalyticsAdapter.js +1 -1
- package/dist/adxcgBidAdapter.js +1 -1
- package/dist/adyoulikeBidAdapter.js +1 -1
- package/dist/agmaAnalyticsAdapter.js +1 -1
- package/dist/ajaBidAdapter.js +1 -1
- package/dist/amxBidAdapter.js +1 -1
- package/dist/amxIdSystem.js +1 -1
- package/dist/aniviewBidAdapter.js +1 -1
- package/dist/appierAnalyticsAdapter.js +1 -1
- package/dist/appnexusBidAdapter.js +1 -1
- package/dist/asoBidAdapter.js +1 -1
- package/dist/axonixBidAdapter.js +1 -1
- package/dist/beopBidAdapter.js +1 -1
- package/dist/bidderTimeoutUtils.js +1 -0
- package/dist/bidglassBidAdapter.js +1 -1
- package/dist/big-richmediaBidAdapter.js +1 -1
- package/dist/bitmediaBidAdapter.js +1 -1
- package/dist/bridBidAdapter.js +1 -1
- package/dist/bridgeuppBidAdapter.js +1 -1
- package/dist/bridgewellBidAdapter.js +1 -1
- package/dist/brightMountainMediaBidAdapter.js +1 -1
- package/dist/carodaBidAdapter.js +1 -1
- package/dist/chtnwBidAdapter.js +1 -1
- package/dist/chunk-core.js +1 -1
- package/dist/concertBidAdapter.js +1 -1
- package/dist/connectadBidAdapter.js +1 -1
- package/dist/consumableBidAdapter.js +1 -1
- package/dist/contxtfulBidAdapter.js +1 -1
- package/dist/conversantAnalyticsAdapter.js +1 -1
- package/dist/conversantBidAdapter.js +1 -1
- package/dist/craftBidAdapter.js +1 -1
- package/dist/criteoBidAdapter.js +1 -1
- package/dist/cwireBidAdapter.js +1 -1
- package/dist/dailymotionBidAdapter.js +1 -1
- package/dist/debugging-standalone.js +1 -1
- package/dist/dependencies.json +10 -1
- package/dist/dspxBidAdapter.js +1 -1
- package/dist/dxkultureBidAdapter.js +1 -1
- package/dist/eplanningBidAdapter.js +1 -1
- package/dist/equativBidAdapter.js +1 -1
- package/dist/eskimiBidAdapter.js +1 -1
- package/dist/euidIdSystem.js +1 -1
- package/dist/exadsBidAdapter.js +1 -1
- package/dist/excoBidAdapter.js +1 -1
- package/dist/feedadBidAdapter.js +1 -1
- package/dist/finativeBidAdapter.js +1 -1
- package/dist/freewheel-sspBidAdapter.js +1 -1
- package/dist/fwsspBidAdapter.js +1 -1
- package/dist/gmosspBidAdapter.js +1 -1
- package/dist/greenbidsAnalyticsAdapter.js +1 -1
- package/dist/greenbidsBidAdapter.js +1 -1
- package/dist/greenbidsRtdProvider.js +1 -1
- package/dist/gridBidAdapter.js +1 -1
- package/dist/gumgumBidAdapter.js +1 -1
- package/dist/h12mediaBidAdapter.js +1 -1
- package/dist/hypelabBidAdapter.js +1 -1
- package/dist/id5AnalyticsAdapter.js +1 -1
- package/dist/id5IdSystem.js +1 -1
- package/dist/imdsBidAdapter.js +1 -1
- package/dist/improvedigitalBidAdapter.js +1 -1
- package/dist/inmobiBidAdapter.js +1 -1
- package/dist/insticatorBidAdapter.js +1 -1
- package/dist/intentIqAnalyticsAdapter.js +1 -1
- package/dist/ixBidAdapter.js +1 -1
- package/dist/jixieBidAdapter.js +1 -1
- package/dist/justpremiumBidAdapter.js +1 -1
- package/dist/kargoBidAdapter.js +1 -1
- package/dist/kimberliteBidAdapter.js +1 -1
- package/dist/konduitAnalyticsAdapter.js +1 -1
- package/dist/kueezBidAdapter.js +1 -1
- package/dist/lassoBidAdapter.js +1 -1
- package/dist/lifestreetBidAdapter.js +1 -1
- package/dist/liveIntentId.js +1 -1
- package/dist/logicadBidAdapter.js +1 -1
- package/dist/loglyliftBidAdapter.js +1 -1
- package/dist/luceadBidAdapter.js +1 -1
- package/dist/mabidderBidAdapter.js +1 -1
- package/dist/madsenseBidAdapter.js +1 -1
- package/dist/magniteAnalyticsAdapter.js +1 -1
- package/dist/malltvAnalyticsAdapter.js +1 -1
- package/dist/marsmediaBidAdapter.js +1 -1
- package/dist/mediafuseBidAdapter.js +1 -1
- package/dist/medianetBidAdapter.js +1 -1
- package/dist/medianetUtils.js +1 -1
- package/dist/mediasquareBidAdapter.js +1 -1
- package/dist/mgidBidAdapter.js +1 -1
- package/dist/missenaBidAdapter.js +1 -1
- package/dist/mobilefuseBidAdapter.js +1 -1
- package/dist/nextMillenniumBidAdapter.js +1 -1
- package/dist/nexx360Utils.js +1 -1
- package/dist/nobidAnalyticsAdapter.js +1 -1
- package/dist/nobidBidAdapter.js +1 -1
- package/dist/nodalsAiRtdProvider.js +1 -1
- package/dist/not-for-prod/prebid.js +178 -175
- package/dist/objectGuard.js +1 -1
- package/dist/oguryBidAdapter.js +1 -1
- package/dist/onetagBidAdapter.js +1 -1
- package/dist/ooloAnalyticsAdapter.js +1 -1
- package/dist/openxBidAdapter.js +1 -1
- package/dist/optableRtdProvider.js +1 -1
- package/dist/optidigitalBidAdapter.js +1 -1
- package/dist/orbidderBidAdapter.js +1 -1
- package/dist/outbrainBidAdapter.js +1 -1
- package/dist/pixfutureBidAdapter.js +1 -1
- package/dist/publinkIdSystem.js +1 -1
- package/dist/pubmaticAnalyticsAdapter.js +1 -1
- package/dist/pubmaticBidAdapter.js +1 -1
- package/dist/pubmaticIdSystem.js +1 -1
- package/dist/pubmaticRtdProvider.js +1 -1
- package/dist/pubmaticUtils.js +1 -0
- package/dist/pubwiseAnalyticsAdapter.js +1 -1
- package/dist/pubxaiAnalyticsAdapter.js +1 -1
- package/dist/pxyzBidAdapter.js +1 -1
- package/dist/quantcastBidAdapter.js +1 -1
- package/dist/readpeakBidAdapter.js +1 -1
- package/dist/relaidoBidAdapter.js +1 -1
- package/dist/retailspotBidAdapter.js +1 -1
- package/dist/rhythmoneBidAdapter.js +1 -1
- package/dist/riseUtils.js +1 -1
- package/dist/rtdModule.js +1 -1
- package/dist/rubiconBidAdapter.js +1 -1
- package/dist/seedingAllianceBidAdapter.js +1 -1
- package/dist/seedtagBidAdapter.js +1 -1
- package/dist/sevioBidAdapter.js +1 -0
- package/dist/sharethroughAnalyticsAdapter.js +1 -1
- package/dist/sharethroughBidAdapter.js +1 -1
- package/dist/showheroes-bsBidAdapter.js +1 -1
- package/dist/smaatoBidAdapter.js +1 -1
- package/dist/smartadserverBidAdapter.js +1 -1
- package/dist/smartxBidAdapter.js +1 -1
- package/dist/smilewantedBidAdapter.js +1 -1
- package/dist/snigelBidAdapter.js +1 -1
- package/dist/sonobiBidAdapter.js +1 -1
- package/dist/sovrnBidAdapter.js +1 -1
- package/dist/sparteoBidAdapter.js +1 -1
- package/dist/sspBCBidAdapter.js +1 -1
- package/dist/stvBidAdapter.js +1 -1
- package/dist/sublimeBidAdapter.js +1 -1
- package/dist/taboolaBidAdapter.js +1 -1
- package/dist/tappxBidAdapter.js +1 -1
- package/dist/targetVideoBidAdapter.js +1 -1
- package/dist/teadsBidAdapter.js +1 -1
- package/dist/terceptAnalyticsAdapter.js +1 -1
- package/dist/themoneytizerBidAdapter.js +1 -1
- package/dist/timeoutRtdProvider.js +1 -1
- package/dist/trionBidAdapter.js +1 -1
- package/dist/tripleliftBidAdapter.js +1 -1
- package/dist/ttdBidAdapter.js +1 -1
- package/dist/ucfunnelAnalyticsAdapter.js +1 -1
- package/dist/uid2IdSystem.js +1 -1
- package/dist/underdogmediaBidAdapter.js +1 -1
- package/dist/undertoneBidAdapter.js +1 -1
- package/dist/unrulyBidAdapter.js +1 -1
- package/dist/userId.js +1 -1
- package/dist/vidazooUtils.js +1 -1
- package/dist/videobyteBidAdapter.js +1 -1
- package/dist/visxBidAdapter.js +1 -1
- package/dist/vuukleBidAdapter.js +1 -1
- package/dist/widespaceBidAdapter.js +1 -1
- package/dist/winrBidAdapter.js +1 -1
- package/dist/yahooAdsBidAdapter.js +1 -1
- package/dist/yandexBidAdapter.js +1 -1
- package/dist/yieldmoBidAdapter.js +1 -1
- package/dist/yieldoneAnalyticsAdapter.js +1 -1
- package/integrationExamples/gpt/pubmaticRtdProvider_Example.html +161 -0
- package/libraries/bidderTimeoutUtils/bidderTimeoutUtils.js +119 -0
- package/libraries/objectGuard/objectGuard.js +170 -48
- package/libraries/objectGuard/ortbGuard.js +33 -43
- package/libraries/pubmaticUtils/plugins/dynamicTimeout.js +209 -0
- package/libraries/pubmaticUtils/plugins/floorProvider.js +168 -0
- package/libraries/pubmaticUtils/plugins/pluginManager.js +106 -0
- package/libraries/pubmaticUtils/plugins/unifiedPricingRule.js +375 -0
- package/libraries/pubmaticUtils/pubmaticUtils.js +76 -0
- package/modules/adagioAnalyticsAdapter.js +6 -1
- package/modules/adagioBidAdapter.js +12 -5
- package/modules/adagioRtdProvider.js +41 -35
- package/modules/fwsspBidAdapter.js +134 -69
- package/modules/fwsspBidAdapter.md +121 -26
- package/modules/optableRtdProvider.js +33 -12
- package/modules/pubmaticAnalyticsAdapter.js +315 -587
- package/modules/pubmaticBidAdapter.js +71 -8
- package/modules/pubmaticIdSystem.js +4 -4
- package/modules/pubmaticRtdProvider.js +105 -613
- package/modules/rtdModule/index.js +23 -6
- package/modules/sevioBidAdapter.js +413 -0
- package/modules/sevioBidAdapter.md +29 -0
- package/modules/sparteoBidAdapter.js +122 -10
- package/modules/timeoutRtdProvider.js +2 -105
- package/modules/ttdBidAdapter.js +0 -5
- package/modules/userId/eids.js +1 -1
- package/modules/userId/index.js +32 -1
- package/package.json +1 -1
- package/src/auction.js +3 -0
- package/test/spec/activities/objectGuard_spec.js +189 -32
- package/test/spec/activities/ortbGuard_spec.js +10 -15
- package/test/spec/libraries/bidderTimeoutUtils/bidderTimeoutUtils_spec.js +213 -0
- package/test/spec/libraries/pubmaticUtils/plugins/dynamicTimeout_spec.js +746 -0
- package/test/spec/libraries/pubmaticUtils/plugins/floorProvider_spec.js +184 -0
- package/test/spec/libraries/pubmaticUtils/plugins/pluginManager_spec.js +489 -0
- package/test/spec/libraries/pubmaticUtils/plugins/unifiedPricingRule_spec.js +359 -0
- package/test/spec/libraries/pubmaticUtils/pubmaticUtils_spec.js +236 -0
- package/test/spec/modules/adagioAnalyticsAdapter_spec.js +94 -24
- package/test/spec/modules/adagioRtdProvider_spec.js +17 -17
- package/test/spec/modules/fwsspBidAdapter_spec.js +513 -78
- package/test/spec/modules/optableRtdProvider_spec.js +55 -5
- package/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +634 -916
- package/test/spec/modules/pubmaticBidAdapter_spec.js +260 -1
- package/test/spec/modules/pubmaticRtdProvider_spec.js +252 -1505
- package/test/spec/modules/realTimeDataModule_spec.js +58 -8
- package/test/spec/modules/sevioBidAdapter_spec.js +513 -0
- package/test/spec/modules/sparteoBidAdapter_spec.js +528 -43
- package/test/spec/modules/timeoutRtdProvider_spec.js +1 -201
- package/test/spec/modules/ttdBidAdapter_spec.js +0 -33
- package/test/spec/modules/userId_spec.js +115 -1
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
import sinon from 'sinon';
|
|
2
|
+
import { expect } from 'chai';
|
|
3
|
+
import * as utils from '../../../../../src/utils.js';
|
|
4
|
+
import * as prebidGlobal from '../../../../../src/prebidGlobal.js';
|
|
5
|
+
import * as dynamicTimeout from '../../../../../libraries/pubmaticUtils/plugins/dynamicTimeout.js';
|
|
6
|
+
import { bidderTimeoutFunctions } from '../../../../../libraries/bidderTimeoutUtils/bidderTimeoutUtils.js';
|
|
7
|
+
import * as pubmaticUtils from '../../../../../libraries/pubmaticUtils/pubmaticUtils.js';
|
|
8
|
+
|
|
9
|
+
describe('DynamicTimeout Plugin', () => {
|
|
10
|
+
let sandbox;
|
|
11
|
+
|
|
12
|
+
// Sample configuration objects
|
|
13
|
+
const enabledConfig = {
|
|
14
|
+
enabled: true,
|
|
15
|
+
config: {
|
|
16
|
+
skipRate: 20,
|
|
17
|
+
bidderTimeout: 1000,
|
|
18
|
+
timeoutRules: {
|
|
19
|
+
includesVideo: {
|
|
20
|
+
'true': 200,
|
|
21
|
+
'false': 50
|
|
22
|
+
},
|
|
23
|
+
numAdUnits: {
|
|
24
|
+
'1-5': 100,
|
|
25
|
+
'6-10': 200
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const configWithData = {
|
|
32
|
+
enabled: true,
|
|
33
|
+
config: {
|
|
34
|
+
skipRate: 20,
|
|
35
|
+
bidderTimeout: 1000
|
|
36
|
+
},
|
|
37
|
+
data: {
|
|
38
|
+
includesVideo: {
|
|
39
|
+
'true': 300,
|
|
40
|
+
'false': 100
|
|
41
|
+
},
|
|
42
|
+
deviceType: {
|
|
43
|
+
'2': 50,
|
|
44
|
+
'4': 150
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const disabledConfig = {
|
|
50
|
+
enabled: false,
|
|
51
|
+
config: {
|
|
52
|
+
skipRate: 0
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
beforeEach(() => {
|
|
57
|
+
sandbox = sinon.createSandbox();
|
|
58
|
+
|
|
59
|
+
// Reset dynamic timeout config before each test
|
|
60
|
+
dynamicTimeout.setDynamicTimeoutConfig(null);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
afterEach(() => {
|
|
64
|
+
sandbox.restore();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('init', () => {
|
|
68
|
+
it('should initialize successfully with valid config', async () => {
|
|
69
|
+
const configJsonManager = {
|
|
70
|
+
getConfigByName: sandbox.stub().returns(enabledConfig)
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const logInfoStub = sandbox.stub(utils, 'logInfo');
|
|
74
|
+
|
|
75
|
+
const result = await dynamicTimeout.init('dynamicTimeout', configJsonManager);
|
|
76
|
+
|
|
77
|
+
expect(result).to.be.true;
|
|
78
|
+
expect(dynamicTimeout.getDynamicTimeoutConfig()).to.deep.equal(enabledConfig);
|
|
79
|
+
expect(logInfoStub.called).to.be.false;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should return false if config is not found', async () => {
|
|
83
|
+
const configJsonManager = {
|
|
84
|
+
getConfigByName: sandbox.stub().returns(null)
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const logInfoStub = sandbox.stub(utils, 'logInfo');
|
|
88
|
+
|
|
89
|
+
const result = await dynamicTimeout.init('dynamicTimeout', configJsonManager);
|
|
90
|
+
|
|
91
|
+
expect(result).to.be.false;
|
|
92
|
+
expect(logInfoStub.calledOnce).to.be.true;
|
|
93
|
+
expect(logInfoStub.firstCall.args[0]).to.include('Dynamic Timeout configuration not found');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should return false if config is disabled', async () => {
|
|
97
|
+
const configJsonManager = {
|
|
98
|
+
getConfigByName: sandbox.stub().returns(disabledConfig)
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const logInfoStub = sandbox.stub(utils, 'logInfo');
|
|
102
|
+
|
|
103
|
+
const result = await dynamicTimeout.init('dynamicTimeout', configJsonManager);
|
|
104
|
+
|
|
105
|
+
expect(result).to.be.false;
|
|
106
|
+
expect(logInfoStub.calledOnce).to.be.true;
|
|
107
|
+
expect(logInfoStub.firstCall.args[0]).to.include('Dynamic Timeout configuration is disabled');
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('processBidRequest', () => {
|
|
112
|
+
let logInfoStub;
|
|
113
|
+
let getGlobalStub;
|
|
114
|
+
let calculateTimeoutModifierStub;
|
|
115
|
+
let shouldThrottleStub;
|
|
116
|
+
|
|
117
|
+
beforeEach(() => {
|
|
118
|
+
logInfoStub = sandbox.stub(utils, 'logInfo');
|
|
119
|
+
getGlobalStub = sandbox.stub(prebidGlobal, 'getGlobal').returns({
|
|
120
|
+
getConfig: sandbox.stub().returns(800),
|
|
121
|
+
adUnits: [{ code: 'test-div' }]
|
|
122
|
+
});
|
|
123
|
+
calculateTimeoutModifierStub = sandbox.stub(bidderTimeoutFunctions, 'calculateTimeoutModifier').returns(150);
|
|
124
|
+
shouldThrottleStub = sandbox.stub(pubmaticUtils, 'shouldThrottle');
|
|
125
|
+
|
|
126
|
+
// Set up default config for most tests
|
|
127
|
+
dynamicTimeout.setDynamicTimeoutConfig(enabledConfig);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should skip processing if throttled by skipRate', async () => {
|
|
131
|
+
shouldThrottleStub.returns(true);
|
|
132
|
+
|
|
133
|
+
const reqBidsConfigObj = { timeout: 800 };
|
|
134
|
+
const result = await dynamicTimeout.processBidRequest(reqBidsConfigObj);
|
|
135
|
+
|
|
136
|
+
expect(result).to.equal(reqBidsConfigObj);
|
|
137
|
+
expect(logInfoStub.calledOnce).to.be.true;
|
|
138
|
+
expect(logInfoStub.firstCall.args[0]).to.include('Dynamic timeout is skipped');
|
|
139
|
+
expect(calculateTimeoutModifierStub.called).to.be.false;
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should apply timeout adjustment when not throttled', async () => {
|
|
143
|
+
shouldThrottleStub.returns(false);
|
|
144
|
+
|
|
145
|
+
const reqBidsConfigObj = { timeout: 800 };
|
|
146
|
+
const result = await dynamicTimeout.processBidRequest(reqBidsConfigObj);
|
|
147
|
+
|
|
148
|
+
// The actual code uses the bidderTimeout from config (1000) + additionalTimeout (150)
|
|
149
|
+
expect(result.timeout).to.equal(1150);
|
|
150
|
+
expect(logInfoStub.called).to.be.true;
|
|
151
|
+
expect(calculateTimeoutModifierStub.calledOnce).to.be.true;
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should use adUnits from reqBidsConfigObj if available', async () => {
|
|
155
|
+
shouldThrottleStub.returns(false);
|
|
156
|
+
|
|
157
|
+
const reqBidsConfigObj = {
|
|
158
|
+
timeout: 800,
|
|
159
|
+
adUnits: [
|
|
160
|
+
{ code: 'div1' },
|
|
161
|
+
{ code: 'div2' }
|
|
162
|
+
]
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
await dynamicTimeout.processBidRequest(reqBidsConfigObj);
|
|
166
|
+
|
|
167
|
+
expect(calculateTimeoutModifierStub.calledOnce).to.be.true;
|
|
168
|
+
expect(calculateTimeoutModifierStub.firstCall.args[0]).to.deep.equal(reqBidsConfigObj.adUnits);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should use adUnits from global if not in reqBidsConfigObj', async () => {
|
|
172
|
+
shouldThrottleStub.returns(false);
|
|
173
|
+
|
|
174
|
+
const globalAdUnits = [{ code: 'global-div' }];
|
|
175
|
+
getGlobalStub.returns({
|
|
176
|
+
getConfig: sandbox.stub().returns(800),
|
|
177
|
+
adUnits: globalAdUnits
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const reqBidsConfigObj = { timeout: 800 };
|
|
181
|
+
await dynamicTimeout.processBidRequest(reqBidsConfigObj);
|
|
182
|
+
|
|
183
|
+
expect(calculateTimeoutModifierStub.calledOnce).to.be.true;
|
|
184
|
+
expect(calculateTimeoutModifierStub.firstCall.args[0]).to.deep.equal(globalAdUnits);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should use bidderTimeout from config if available', async () => {
|
|
188
|
+
shouldThrottleStub.returns(false);
|
|
189
|
+
|
|
190
|
+
const reqBidsConfigObj = {};
|
|
191
|
+
await dynamicTimeout.processBidRequest(reqBidsConfigObj);
|
|
192
|
+
|
|
193
|
+
// Should use the bidderTimeout from config (1000) not the global one (800)
|
|
194
|
+
expect(reqBidsConfigObj.timeout).to.equal(1150); // 1000 + 150
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should use timeout from reqBidsConfigObj if available and no config bidderTimeout', async () => {
|
|
198
|
+
shouldThrottleStub.returns(false);
|
|
199
|
+
|
|
200
|
+
// Remove bidderTimeout from config
|
|
201
|
+
const configWithoutBidderTimeout = {
|
|
202
|
+
...enabledConfig,
|
|
203
|
+
config: { ...enabledConfig.config }
|
|
204
|
+
};
|
|
205
|
+
delete configWithoutBidderTimeout.config.bidderTimeout;
|
|
206
|
+
dynamicTimeout.setDynamicTimeoutConfig(configWithoutBidderTimeout);
|
|
207
|
+
|
|
208
|
+
const reqBidsConfigObj = { timeout: 900 };
|
|
209
|
+
await dynamicTimeout.processBidRequest(reqBidsConfigObj);
|
|
210
|
+
|
|
211
|
+
expect(reqBidsConfigObj.timeout).to.equal(1050); // 900 + 150
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should fall back to global bidderTimeout if needed', async () => {
|
|
215
|
+
shouldThrottleStub.returns(false);
|
|
216
|
+
|
|
217
|
+
// Remove bidderTimeout from config
|
|
218
|
+
const configWithoutBidderTimeout = {
|
|
219
|
+
...enabledConfig,
|
|
220
|
+
config: { ...enabledConfig.config }
|
|
221
|
+
};
|
|
222
|
+
delete configWithoutBidderTimeout.config.bidderTimeout;
|
|
223
|
+
dynamicTimeout.setDynamicTimeoutConfig(configWithoutBidderTimeout);
|
|
224
|
+
|
|
225
|
+
const reqBidsConfigObj = {};
|
|
226
|
+
await dynamicTimeout.processBidRequest(reqBidsConfigObj);
|
|
227
|
+
|
|
228
|
+
expect(reqBidsConfigObj.timeout).to.equal(950); // 800 + 150
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('should use skipRate 0 when explicitly set to 0', async () => {
|
|
232
|
+
// Set a config with skipRate explicitly set to 0
|
|
233
|
+
const configWithZeroSkipRate = {
|
|
234
|
+
enabled: true,
|
|
235
|
+
config: {
|
|
236
|
+
skipRate: 0,
|
|
237
|
+
bidderTimeout: 1000
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
dynamicTimeout.setDynamicTimeoutConfig(configWithZeroSkipRate);
|
|
241
|
+
|
|
242
|
+
const reqBidsConfigObj = { timeout: 800 };
|
|
243
|
+
await dynamicTimeout.processBidRequest(reqBidsConfigObj);
|
|
244
|
+
|
|
245
|
+
// Verify shouldThrottle was called with skipRate=0, not the default value
|
|
246
|
+
expect(shouldThrottleStub.calledOnce).to.be.true;
|
|
247
|
+
expect(shouldThrottleStub.firstCall.args[0]).to.equal(0);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('should use default skipRate when skipRate is not present in config', async () => {
|
|
251
|
+
// Set a config without skipRate
|
|
252
|
+
const configWithoutSkipRate = {
|
|
253
|
+
enabled: true,
|
|
254
|
+
config: {
|
|
255
|
+
bidderTimeout: 1000
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
dynamicTimeout.setDynamicTimeoutConfig(configWithoutSkipRate);
|
|
259
|
+
|
|
260
|
+
const reqBidsConfigObj = { timeout: 800 };
|
|
261
|
+
await dynamicTimeout.processBidRequest(reqBidsConfigObj);
|
|
262
|
+
|
|
263
|
+
// Verify shouldThrottle was called with the default skipRate
|
|
264
|
+
expect(shouldThrottleStub.calledOnce).to.be.true;
|
|
265
|
+
expect(shouldThrottleStub.firstCall.args[0]).to.equal(dynamicTimeout.CONSTANTS.DEFAULT_SKIP_RATE);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe('getBidderTimeout', () => {
|
|
270
|
+
let getGlobalStub;
|
|
271
|
+
|
|
272
|
+
beforeEach(() => {
|
|
273
|
+
getGlobalStub = sandbox.stub(prebidGlobal, 'getGlobal').returns({
|
|
274
|
+
getConfig: sandbox.stub().returns(800)
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should return bidderTimeout from config if available', () => {
|
|
279
|
+
dynamicTimeout.setDynamicTimeoutConfig(enabledConfig);
|
|
280
|
+
|
|
281
|
+
const result = dynamicTimeout.getBidderTimeout({});
|
|
282
|
+
|
|
283
|
+
expect(result).to.equal(1000);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it('should return timeout from reqBidsConfigObj if no config bidderTimeout', () => {
|
|
287
|
+
const configWithoutBidderTimeout = {
|
|
288
|
+
...enabledConfig,
|
|
289
|
+
config: { ...enabledConfig.config }
|
|
290
|
+
};
|
|
291
|
+
delete configWithoutBidderTimeout.config.bidderTimeout;
|
|
292
|
+
dynamicTimeout.setDynamicTimeoutConfig(configWithoutBidderTimeout);
|
|
293
|
+
|
|
294
|
+
const result = dynamicTimeout.getBidderTimeout({ timeout: 900 });
|
|
295
|
+
|
|
296
|
+
expect(result).to.equal(900);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('should fall back to global bidderTimeout if needed', () => {
|
|
300
|
+
const configWithoutBidderTimeout = {
|
|
301
|
+
...enabledConfig,
|
|
302
|
+
config: { ...enabledConfig.config }
|
|
303
|
+
};
|
|
304
|
+
delete configWithoutBidderTimeout.config.bidderTimeout;
|
|
305
|
+
dynamicTimeout.setDynamicTimeoutConfig(configWithoutBidderTimeout);
|
|
306
|
+
|
|
307
|
+
const result = dynamicTimeout.getBidderTimeout({});
|
|
308
|
+
|
|
309
|
+
expect(result).to.equal(800);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
describe('getFinalTimeout', () => {
|
|
314
|
+
let logInfoStub;
|
|
315
|
+
|
|
316
|
+
beforeEach(() => {
|
|
317
|
+
logInfoStub = sandbox.stub(utils, 'logInfo');
|
|
318
|
+
// Set up a default config for getFinalTimeout tests
|
|
319
|
+
dynamicTimeout.setDynamicTimeoutConfig({
|
|
320
|
+
enabled: true,
|
|
321
|
+
config: {
|
|
322
|
+
thresholdTimeout: 500
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it('should return calculated timeout when above threshold', () => {
|
|
328
|
+
const bidderTimeout = 1000;
|
|
329
|
+
const additionalTimeout = 200;
|
|
330
|
+
|
|
331
|
+
const result = dynamicTimeout.getFinalTimeout(bidderTimeout, additionalTimeout);
|
|
332
|
+
|
|
333
|
+
expect(result).to.equal(1200); // 1000 + 200
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it('should return threshold timeout when calculated timeout is below threshold', () => {
|
|
337
|
+
const bidderTimeout = 300;
|
|
338
|
+
const additionalTimeout = 100;
|
|
339
|
+
|
|
340
|
+
const result = dynamicTimeout.getFinalTimeout(bidderTimeout, additionalTimeout);
|
|
341
|
+
|
|
342
|
+
expect(result).to.equal(500); // threshold timeout
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('should handle negative additional timeout gracefully', () => {
|
|
346
|
+
const bidderTimeout = 1000;
|
|
347
|
+
const additionalTimeout = -600; // Results in 400ms, below threshold
|
|
348
|
+
|
|
349
|
+
const result = dynamicTimeout.getFinalTimeout(bidderTimeout, additionalTimeout);
|
|
350
|
+
|
|
351
|
+
expect(result).to.equal(500); // threshold timeout
|
|
352
|
+
expect(logInfoStub.calledOnce).to.be.true;
|
|
353
|
+
expect(logInfoStub.firstCall.args[0]).to.include('Calculated timeout (400ms) below threshold');
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('should handle negative bidder timeout gracefully', () => {
|
|
357
|
+
const bidderTimeout = -200;
|
|
358
|
+
const additionalTimeout = 100;
|
|
359
|
+
|
|
360
|
+
const result = dynamicTimeout.getFinalTimeout(bidderTimeout, additionalTimeout);
|
|
361
|
+
|
|
362
|
+
expect(result).to.equal(500); // threshold timeout (since -200 + 100 = -100 < 500)
|
|
363
|
+
expect(logInfoStub.calledOnce).to.be.true;
|
|
364
|
+
expect(logInfoStub.firstCall.args[0]).to.include('Warning: Negative timeout calculated (-100ms)');
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('should handle both negative values gracefully', () => {
|
|
368
|
+
const bidderTimeout = -300;
|
|
369
|
+
const additionalTimeout = -200;
|
|
370
|
+
|
|
371
|
+
const result = dynamicTimeout.getFinalTimeout(bidderTimeout, additionalTimeout);
|
|
372
|
+
|
|
373
|
+
expect(result).to.equal(500); // threshold timeout (since -300 + -200 = -500 < 500)
|
|
374
|
+
expect(logInfoStub.calledOnce).to.be.true;
|
|
375
|
+
expect(logInfoStub.firstCall.args[0]).to.include('Warning: Negative timeout calculated (-500ms)');
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it('should use default threshold when not configured', () => {
|
|
379
|
+
// Remove threshold from config
|
|
380
|
+
dynamicTimeout.setDynamicTimeoutConfig({
|
|
381
|
+
enabled: true,
|
|
382
|
+
config: {}
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
const bidderTimeout = 200;
|
|
386
|
+
const additionalTimeout = 100;
|
|
387
|
+
|
|
388
|
+
const result = dynamicTimeout.getFinalTimeout(bidderTimeout, additionalTimeout);
|
|
389
|
+
|
|
390
|
+
expect(result).to.equal(500); // default threshold (500ms)
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('should handle zero values', () => {
|
|
394
|
+
const bidderTimeout = 0;
|
|
395
|
+
const additionalTimeout = 0;
|
|
396
|
+
|
|
397
|
+
const result = dynamicTimeout.getFinalTimeout(bidderTimeout, additionalTimeout);
|
|
398
|
+
|
|
399
|
+
expect(result).to.equal(500); // threshold timeout
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it('should handle large timeout values', () => {
|
|
403
|
+
const bidderTimeout = 5000;
|
|
404
|
+
const additionalTimeout = 2000;
|
|
405
|
+
|
|
406
|
+
const result = dynamicTimeout.getFinalTimeout(bidderTimeout, additionalTimeout);
|
|
407
|
+
|
|
408
|
+
expect(result).to.equal(7000); // 5000 + 2000
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
it('should handle custom threshold timeout', () => {
|
|
412
|
+
// Set custom threshold
|
|
413
|
+
dynamicTimeout.setDynamicTimeoutConfig({
|
|
414
|
+
enabled: true,
|
|
415
|
+
config: {
|
|
416
|
+
thresholdTimeout: 1000
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
const bidderTimeout = 800;
|
|
421
|
+
const additionalTimeout = 100;
|
|
422
|
+
|
|
423
|
+
const result = dynamicTimeout.getFinalTimeout(bidderTimeout, additionalTimeout);
|
|
424
|
+
|
|
425
|
+
expect(result).to.equal(1000); // custom threshold (since 800 + 100 = 900 < 1000)
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
it('should handle exactly threshold value', () => {
|
|
429
|
+
const bidderTimeout = 400;
|
|
430
|
+
const additionalTimeout = 100;
|
|
431
|
+
|
|
432
|
+
const result = dynamicTimeout.getFinalTimeout(bidderTimeout, additionalTimeout);
|
|
433
|
+
|
|
434
|
+
expect(result).to.equal(500); // exactly at threshold, should return calculated value
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it('should handle no config gracefully', () => {
|
|
438
|
+
dynamicTimeout.setDynamicTimeoutConfig(null);
|
|
439
|
+
|
|
440
|
+
const bidderTimeout = 300;
|
|
441
|
+
const additionalTimeout = 100;
|
|
442
|
+
|
|
443
|
+
const result = dynamicTimeout.getFinalTimeout(bidderTimeout, additionalTimeout);
|
|
444
|
+
|
|
445
|
+
expect(result).to.equal(500); // default threshold (500ms)
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
it('should handle very large negative additional timeout', () => {
|
|
449
|
+
const bidderTimeout = 1000;
|
|
450
|
+
const additionalTimeout = -2000; // Results in -1000ms, well below threshold
|
|
451
|
+
|
|
452
|
+
const result = dynamicTimeout.getFinalTimeout(bidderTimeout, additionalTimeout);
|
|
453
|
+
|
|
454
|
+
expect(result).to.equal(500); // threshold timeout
|
|
455
|
+
});
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
describe('getRules', () => {
|
|
459
|
+
it('should return data rules if available', () => {
|
|
460
|
+
dynamicTimeout.setDynamicTimeoutConfig(configWithData);
|
|
461
|
+
|
|
462
|
+
const result = dynamicTimeout.getRules(1000);
|
|
463
|
+
|
|
464
|
+
expect(result).to.deep.equal(configWithData.data);
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
it('should return config timeoutRules if no data rules', () => {
|
|
468
|
+
dynamicTimeout.setDynamicTimeoutConfig(enabledConfig);
|
|
469
|
+
|
|
470
|
+
const result = dynamicTimeout.getRules(1000);
|
|
471
|
+
|
|
472
|
+
expect(result).to.deep.equal(enabledConfig.config.timeoutRules);
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
it('should create dynamic rules if no data or config rules', () => {
|
|
476
|
+
const configWithoutRules = {
|
|
477
|
+
enabled: true,
|
|
478
|
+
config: {
|
|
479
|
+
skipRate: 20,
|
|
480
|
+
bidderTimeout: 1000
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
dynamicTimeout.setDynamicTimeoutConfig(configWithoutRules);
|
|
484
|
+
|
|
485
|
+
const result = dynamicTimeout.getRules(1000);
|
|
486
|
+
|
|
487
|
+
expect(result).to.deep.equal(dynamicTimeout.createDynamicRules(dynamicTimeout.RULES_PERCENTAGE, 1000));
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
describe('createDynamicRules', () => {
|
|
492
|
+
let logInfoStub;
|
|
493
|
+
|
|
494
|
+
beforeEach(() => {
|
|
495
|
+
logInfoStub = sandbox.stub(utils, 'logInfo');
|
|
496
|
+
});
|
|
497
|
+
it('should convert percentage rules to millisecond values', () => {
|
|
498
|
+
const percentageRules = {
|
|
499
|
+
includesVideo: {
|
|
500
|
+
'true': 20, // 20% of bidderTimeout
|
|
501
|
+
'false': 5 // 5% of bidderTimeout
|
|
502
|
+
},
|
|
503
|
+
numAdUnits: {
|
|
504
|
+
'1-5': 10, // 10% of bidderTimeout
|
|
505
|
+
'6-10': 20 // 20% of bidderTimeout
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
const bidderTimeout = 1000;
|
|
510
|
+
const result = dynamicTimeout.createDynamicRules(percentageRules, bidderTimeout);
|
|
511
|
+
|
|
512
|
+
expect(result).to.deep.equal({
|
|
513
|
+
includesVideo: {
|
|
514
|
+
'true': 200, // 20% of 1000
|
|
515
|
+
'false': 50 // 5% of 1000
|
|
516
|
+
},
|
|
517
|
+
numAdUnits: {
|
|
518
|
+
'1-5': 100, // 10% of 1000
|
|
519
|
+
'6-10': 200 // 20% of 1000
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
it('should handle invalid percentage values', () => {
|
|
525
|
+
const percentageRules = {
|
|
526
|
+
includesVideo: {
|
|
527
|
+
'true': 'invalid',
|
|
528
|
+
'false': 5
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
const bidderTimeout = 1000;
|
|
533
|
+
const result = dynamicTimeout.createDynamicRules(percentageRules, bidderTimeout);
|
|
534
|
+
|
|
535
|
+
expect(result).to.deep.equal({
|
|
536
|
+
includesVideo: {
|
|
537
|
+
'false': 50
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
it('should return empty object for invalid inputs', () => {
|
|
543
|
+
expect(dynamicTimeout.createDynamicRules(null, 1000)).to.deep.equal({});
|
|
544
|
+
expect(dynamicTimeout.createDynamicRules({}, 0)).to.deep.equal({});
|
|
545
|
+
expect(dynamicTimeout.createDynamicRules('invalid', 1000)).to.deep.equal({});
|
|
546
|
+
expect(dynamicTimeout.createDynamicRules({}, -10)).to.deep.equal({});
|
|
547
|
+
|
|
548
|
+
// Verify logging for invalid inputs
|
|
549
|
+
expect(logInfoStub.callCount).to.equal(4);
|
|
550
|
+
expect(logInfoStub.getCall(0).args[0]).to.include('Invalid percentage rules provided');
|
|
551
|
+
expect(logInfoStub.getCall(1).args[0]).to.include('Invalid bidderTimeout (0ms)');
|
|
552
|
+
expect(logInfoStub.getCall(2).args[0]).to.include('Invalid percentage rules provided');
|
|
553
|
+
expect(logInfoStub.getCall(3).args[0]).to.include('Invalid bidderTimeout (-10ms)');
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it('should skip non-object rule categories', () => {
|
|
557
|
+
const percentageRules = {
|
|
558
|
+
includesVideo: {
|
|
559
|
+
'true': 20
|
|
560
|
+
},
|
|
561
|
+
numAdUnits: 'invalid'
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
const bidderTimeout = 1000;
|
|
565
|
+
const result = dynamicTimeout.createDynamicRules(percentageRules, bidderTimeout);
|
|
566
|
+
|
|
567
|
+
expect(result).to.deep.equal({
|
|
568
|
+
includesVideo: {
|
|
569
|
+
'true': 200
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
expect(logInfoStub.calledOnce).to.be.true;
|
|
573
|
+
expect(logInfoStub.firstCall.args[0]).to.include('Skipping invalid rule category: numAdUnits');
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
it('should handle negative bidderTimeout gracefully', () => {
|
|
577
|
+
const percentageRules = {
|
|
578
|
+
includesVideo: {
|
|
579
|
+
'true': 20,
|
|
580
|
+
'false': 5
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
const result = dynamicTimeout.createDynamicRules(percentageRules, -500);
|
|
585
|
+
expect(result).to.deep.equal({});
|
|
586
|
+
expect(logInfoStub.calledOnce).to.be.true;
|
|
587
|
+
expect(logInfoStub.firstCall.args[0]).to.include('Invalid bidderTimeout (-500ms)');
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
it('should handle zero percentage values', () => {
|
|
591
|
+
const percentageRules = {
|
|
592
|
+
includesVideo: {
|
|
593
|
+
'true': 0,
|
|
594
|
+
'false': 5
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
const bidderTimeout = 1000;
|
|
599
|
+
const result = dynamicTimeout.createDynamicRules(percentageRules, bidderTimeout);
|
|
600
|
+
|
|
601
|
+
expect(result).to.deep.equal({
|
|
602
|
+
includesVideo: {
|
|
603
|
+
'false': 50
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
it('should handle negative percentage values', () => {
|
|
609
|
+
const percentageRules = {
|
|
610
|
+
includesVideo: {
|
|
611
|
+
'true': -20,
|
|
612
|
+
'false': 5
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
const bidderTimeout = 1000;
|
|
617
|
+
const result = dynamicTimeout.createDynamicRules(percentageRules, bidderTimeout);
|
|
618
|
+
|
|
619
|
+
expect(result).to.deep.equal({
|
|
620
|
+
includesVideo: {
|
|
621
|
+
'true': -200,
|
|
622
|
+
'false': 50
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
expect(logInfoStub.calledOnce).to.be.true;
|
|
626
|
+
expect(logInfoStub.firstCall.args[0]).to.include('Warning: Negative timeout calculated for includesVideo.true: -200ms');
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
it('should handle very large percentage values', () => {
|
|
630
|
+
const percentageRules = {
|
|
631
|
+
includesVideo: {
|
|
632
|
+
'true': 500, // 500% of bidderTimeout
|
|
633
|
+
'false': 5
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
const bidderTimeout = 1000;
|
|
638
|
+
const result = dynamicTimeout.createDynamicRules(percentageRules, bidderTimeout);
|
|
639
|
+
|
|
640
|
+
expect(result).to.deep.equal({
|
|
641
|
+
includesVideo: {
|
|
642
|
+
'true': 5000, // 500% of 1000
|
|
643
|
+
'false': 50
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
it('should handle decimal percentage values', () => {
|
|
649
|
+
const percentageRules = {
|
|
650
|
+
includesVideo: {
|
|
651
|
+
'true': 2.5,
|
|
652
|
+
'false': 7.8
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
const bidderTimeout = 1000;
|
|
657
|
+
const result = dynamicTimeout.createDynamicRules(percentageRules, bidderTimeout);
|
|
658
|
+
|
|
659
|
+
expect(result).to.deep.equal({
|
|
660
|
+
includesVideo: {
|
|
661
|
+
'true': 25, // Math.floor(1000 * 2.5 / 100)
|
|
662
|
+
'false': 78 // Math.floor(1000 * 7.8 / 100)
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
it('should handle empty percentage rules object', () => {
|
|
668
|
+
const percentageRules = {};
|
|
669
|
+
const bidderTimeout = 1000;
|
|
670
|
+
const result = dynamicTimeout.createDynamicRules(percentageRules, bidderTimeout);
|
|
671
|
+
|
|
672
|
+
expect(result).to.deep.equal({});
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
it('should handle categories with empty rule objects', () => {
|
|
676
|
+
const percentageRules = {
|
|
677
|
+
includesVideo: {},
|
|
678
|
+
numAdUnits: {
|
|
679
|
+
'1-5': 10
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
const bidderTimeout = 1000;
|
|
684
|
+
const result = dynamicTimeout.createDynamicRules(percentageRules, bidderTimeout);
|
|
685
|
+
|
|
686
|
+
expect(result).to.deep.equal({
|
|
687
|
+
includesVideo: {},
|
|
688
|
+
numAdUnits: {
|
|
689
|
+
'1-5': 100
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
});
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
describe('getTargeting', () => {
|
|
696
|
+
it('should return undefined', () => {
|
|
697
|
+
expect(dynamicTimeout.getTargeting()).to.be.undefined;
|
|
698
|
+
});
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
describe('CONSTANTS', () => {
|
|
702
|
+
it('should have the correct LOG_PRE_FIX value', () => {
|
|
703
|
+
expect(dynamicTimeout.CONSTANTS.LOG_PRE_FIX).to.equal('PubMatic-Dynamic-Timeout: ');
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
it('should have the correct rule type constants', () => {
|
|
707
|
+
expect(dynamicTimeout.CONSTANTS.INCLUDES_VIDEOS).to.equal('includesVideo');
|
|
708
|
+
expect(dynamicTimeout.CONSTANTS.NUM_AD_UNITS).to.equal('numAdUnits');
|
|
709
|
+
expect(dynamicTimeout.CONSTANTS.DEVICE_TYPE).to.equal('deviceType');
|
|
710
|
+
expect(dynamicTimeout.CONSTANTS.CONNECTION_SPEED).to.equal('connectionSpeed');
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
it('should be frozen', () => {
|
|
714
|
+
expect(Object.isFrozen(dynamicTimeout.CONSTANTS)).to.be.true;
|
|
715
|
+
});
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
describe('RULES_PERCENTAGE', () => {
|
|
719
|
+
it('should have the correct percentage values', () => {
|
|
720
|
+
expect(dynamicTimeout.RULES_PERCENTAGE[dynamicTimeout.CONSTANTS.INCLUDES_VIDEOS]['true']).to.equal(20);
|
|
721
|
+
expect(dynamicTimeout.RULES_PERCENTAGE[dynamicTimeout.CONSTANTS.INCLUDES_VIDEOS]['false']).to.equal(5);
|
|
722
|
+
|
|
723
|
+
expect(dynamicTimeout.RULES_PERCENTAGE[dynamicTimeout.CONSTANTS.NUM_AD_UNITS]['1-5']).to.equal(10);
|
|
724
|
+
expect(dynamicTimeout.RULES_PERCENTAGE[dynamicTimeout.CONSTANTS.NUM_AD_UNITS]['6-10']).to.equal(20);
|
|
725
|
+
expect(dynamicTimeout.RULES_PERCENTAGE[dynamicTimeout.CONSTANTS.NUM_AD_UNITS]['11-15']).to.equal(30);
|
|
726
|
+
|
|
727
|
+
expect(dynamicTimeout.RULES_PERCENTAGE[dynamicTimeout.CONSTANTS.DEVICE_TYPE]['2']).to.equal(5);
|
|
728
|
+
expect(dynamicTimeout.RULES_PERCENTAGE[dynamicTimeout.CONSTANTS.DEVICE_TYPE]['4']).to.equal(10);
|
|
729
|
+
expect(dynamicTimeout.RULES_PERCENTAGE[dynamicTimeout.CONSTANTS.DEVICE_TYPE]['5']).to.equal(20);
|
|
730
|
+
|
|
731
|
+
expect(dynamicTimeout.RULES_PERCENTAGE[dynamicTimeout.CONSTANTS.CONNECTION_SPEED]['slow']).to.equal(20);
|
|
732
|
+
expect(dynamicTimeout.RULES_PERCENTAGE[dynamicTimeout.CONSTANTS.CONNECTION_SPEED]['medium']).to.equal(10);
|
|
733
|
+
expect(dynamicTimeout.RULES_PERCENTAGE[dynamicTimeout.CONSTANTS.CONNECTION_SPEED]['fast']).to.equal(5);
|
|
734
|
+
expect(dynamicTimeout.RULES_PERCENTAGE[dynamicTimeout.CONSTANTS.CONNECTION_SPEED]['unknown']).to.equal(1);
|
|
735
|
+
});
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
describe('DynamicTimeout export', () => {
|
|
739
|
+
it('should export the correct interface', () => {
|
|
740
|
+
expect(dynamicTimeout.DynamicTimeout).to.be.an('object');
|
|
741
|
+
expect(dynamicTimeout.DynamicTimeout.init).to.be.a('function');
|
|
742
|
+
expect(dynamicTimeout.DynamicTimeout.processBidRequest).to.be.a('function');
|
|
743
|
+
expect(dynamicTimeout.DynamicTimeout.getTargeting).to.be.a('function');
|
|
744
|
+
});
|
|
745
|
+
});
|
|
746
|
+
});
|