1
1
/**
2
- * Copyright 2016, 2018 Optimizely
2
+ * Copyright 2016, 2018-2019 Optimizely
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
15
15
*/
16
16
var audienceEvaluator = require ( './' ) ;
17
17
var chai = require ( 'chai' ) ;
18
+ var sprintf = require ( 'sprintf-js' ) . sprintf ;
18
19
var conditionTreeEvaluator = require ( '../condition_tree_evaluator' ) ;
19
20
var customAttributeConditionEvaluator = require ( '../custom_attribute_condition_evaluator' ) ;
20
21
var sinon = require ( 'sinon' ) ;
21
-
22
22
var assert = chai . assert ;
23
+ var logger = require ( '../../plugins/logger' ) ;
24
+ var enums = require ( '../../utils/enums' ) ;
25
+ var LOG_LEVEL = enums . LOG_LEVEL ;
23
26
24
27
var chromeUserAudience = {
25
28
conditions : [ 'and' , {
@@ -52,12 +55,22 @@ var audiencesById = {
52
55
describe ( 'lib/core/audience_evaluator' , function ( ) {
53
56
describe ( 'APIs' , function ( ) {
54
57
describe ( 'evaluate' , function ( ) {
58
+ var mockLogger = logger . createLogger ( { logLevel : LOG_LEVEL . INFO } ) ;
59
+
60
+ beforeEach ( function ( ) {
61
+ sinon . stub ( mockLogger , 'log' ) ;
62
+ } ) ;
63
+
64
+ afterEach ( function ( ) {
65
+ mockLogger . log . restore ( ) ;
66
+ } ) ;
67
+
55
68
it ( 'should return true if there are no audiences' , function ( ) {
56
- assert . isTrue ( audienceEvaluator . evaluate ( [ ] , audiencesById , { } ) ) ;
69
+ assert . isTrue ( audienceEvaluator . evaluate ( [ ] , audiencesById , { } , mockLogger ) ) ;
57
70
} ) ;
58
71
59
72
it ( 'should return false if there are audiences but no attributes' , function ( ) {
60
- assert . isFalse ( audienceEvaluator . evaluate ( [ '0' ] , audiencesById , { } ) ) ;
73
+ assert . isFalse ( audienceEvaluator . evaluate ( [ '0' ] , audiencesById , { } , mockLogger ) ) ;
61
74
} ) ;
62
75
63
76
it ( 'should return true if any of the audience conditions are met' , function ( ) {
@@ -74,9 +87,9 @@ describe('lib/core/audience_evaluator', function() {
74
87
'device_model' : 'iphone' ,
75
88
} ;
76
89
77
- assert . isTrue ( audienceEvaluator . evaluate ( [ '0' , '1' ] , audiencesById , iphoneUsers ) ) ;
78
- assert . isTrue ( audienceEvaluator . evaluate ( [ '0' , '1' ] , audiencesById , chromeUsers ) ) ;
79
- assert . isTrue ( audienceEvaluator . evaluate ( [ '0' , '1' ] , audiencesById , iphoneChromeUsers ) ) ;
90
+ assert . isTrue ( audienceEvaluator . evaluate ( [ '0' , '1' ] , audiencesById , iphoneUsers , mockLogger ) ) ;
91
+ assert . isTrue ( audienceEvaluator . evaluate ( [ '0' , '1' ] , audiencesById , chromeUsers , mockLogger ) ) ;
92
+ assert . isTrue ( audienceEvaluator . evaluate ( [ '0' , '1' ] , audiencesById , iphoneChromeUsers , mockLogger ) ) ;
80
93
} ) ;
81
94
82
95
it ( 'should return false if none of the audience conditions are met' , function ( ) {
@@ -93,21 +106,22 @@ describe('lib/core/audience_evaluator', function() {
93
106
'device_model' : 'nexus5' ,
94
107
} ;
95
108
96
- assert . isFalse ( audienceEvaluator . evaluate ( [ '0' , '1' ] , audiencesById , nexusUsers ) ) ;
97
- assert . isFalse ( audienceEvaluator . evaluate ( [ '0' , '1' ] , audiencesById , safariUsers ) ) ;
98
- assert . isFalse ( audienceEvaluator . evaluate ( [ '0' , '1' ] , audiencesById , nexusSafariUsers ) ) ;
109
+ assert . isFalse ( audienceEvaluator . evaluate ( [ '0' , '1' ] , audiencesById , nexusUsers , mockLogger ) ) ;
110
+ assert . isFalse ( audienceEvaluator . evaluate ( [ '0' , '1' ] , audiencesById , safariUsers , mockLogger ) ) ;
111
+ assert . isFalse ( audienceEvaluator . evaluate ( [ '0' , '1' ] , audiencesById , nexusSafariUsers , mockLogger ) ) ;
99
112
} ) ;
100
113
101
114
it ( 'should return true if no attributes are passed and the audience conditions evaluate to true in the absence of attributes' , function ( ) {
102
- assert . isTrue ( audienceEvaluator . evaluate ( [ '2' ] , audiencesById ) ) ;
115
+ assert . isTrue ( audienceEvaluator . evaluate ( [ '2' ] , audiencesById , null , mockLogger ) ) ;
103
116
} ) ;
104
117
105
118
describe ( 'complex audience conditions' , function ( ) {
106
119
it ( 'should return true if any of the audiences in an "OR" condition pass' , function ( ) {
107
120
var result = audienceEvaluator . evaluate (
108
121
[ 'or' , '0' , '1' ] ,
109
122
audiencesById ,
110
- { browser_type : 'chrome' }
123
+ { browser_type : 'chrome' } ,
124
+ mockLogger
111
125
) ;
112
126
assert . isTrue ( result ) ;
113
127
} ) ;
@@ -116,7 +130,8 @@ describe('lib/core/audience_evaluator', function() {
116
130
var result = audienceEvaluator . evaluate (
117
131
[ 'and' , '0' , '1' ] ,
118
132
audiencesById ,
119
- { browser_type : 'chrome' , device_model : 'iphone' }
133
+ { browser_type : 'chrome' , device_model : 'iphone' } ,
134
+ mockLogger
120
135
) ;
121
136
assert . isTrue ( result ) ;
122
137
} ) ;
@@ -125,7 +140,8 @@ describe('lib/core/audience_evaluator', function() {
125
140
var result = audienceEvaluator . evaluate (
126
141
[ 'not' , '1' ] ,
127
142
audiencesById ,
128
- { device_model : 'android' }
143
+ { device_model : 'android' } ,
144
+ mockLogger
129
145
) ;
130
146
assert . isTrue ( result ) ;
131
147
} ) ;
@@ -149,7 +165,8 @@ describe('lib/core/audience_evaluator', function() {
149
165
var result = audienceEvaluator . evaluate (
150
166
[ 'or' , '0' , '1' ] ,
151
167
audiencesById ,
152
- { browser_type : 'chrome' }
168
+ { browser_type : 'chrome' } ,
169
+ mockLogger
153
170
) ;
154
171
assert . isTrue ( result ) ;
155
172
} ) ;
@@ -159,7 +176,8 @@ describe('lib/core/audience_evaluator', function() {
159
176
var result = audienceEvaluator . evaluate (
160
177
[ 'or' , '0' , '1' ] ,
161
178
audiencesById ,
162
- { browser_type : 'safari' }
179
+ { browser_type : 'safari' } ,
180
+ mockLogger
163
181
) ;
164
182
assert . isFalse ( result ) ;
165
183
} ) ;
@@ -169,7 +187,8 @@ describe('lib/core/audience_evaluator', function() {
169
187
var result = audienceEvaluator . evaluate (
170
188
[ 'or' , '0' , '1' ] ,
171
189
audiencesById ,
172
- { state : 'California' }
190
+ { state : 'California' } ,
191
+ mockLogger
173
192
) ;
174
193
assert . isFalse ( result ) ;
175
194
} ) ;
@@ -180,10 +199,68 @@ describe('lib/core/audience_evaluator', function() {
180
199
} ) ;
181
200
customAttributeConditionEvaluator . evaluate . returns ( false ) ;
182
201
var userAttributes = { device_model : 'android' } ;
183
- var result = audienceEvaluator . evaluate ( [ 'or' , '1' ] , audiencesById , userAttributes ) ;
202
+ var result = audienceEvaluator . evaluate ( [ 'or' , '1' ] , audiencesById , userAttributes , mockLogger ) ;
203
+ sinon . assert . calledOnce ( customAttributeConditionEvaluator . evaluate ) ;
204
+ sinon . assert . calledWithExactly ( customAttributeConditionEvaluator . evaluate , iphoneUserAudience . conditions [ 1 ] , userAttributes , mockLogger ) ;
205
+ assert . isFalse ( result ) ;
206
+ } ) ;
207
+ } ) ;
208
+
209
+ describe ( 'Audience evaluation logging' , function ( ) {
210
+ var sandbox = sinon . sandbox . create ( ) ;
211
+
212
+ beforeEach ( function ( ) {
213
+ sandbox . stub ( conditionTreeEvaluator , 'evaluate' ) ;
214
+ sandbox . stub ( customAttributeConditionEvaluator , 'evaluate' ) ;
215
+ } ) ;
216
+
217
+ afterEach ( function ( ) {
218
+ sandbox . restore ( ) ;
219
+ } ) ;
220
+
221
+ it ( 'logs correctly when conditionTreeEvaluator.evaluate returns null' , function ( ) {
222
+ conditionTreeEvaluator . evaluate . callsFake ( function ( conditions , leafEvaluator ) {
223
+ return leafEvaluator ( conditions [ 1 ] ) ;
224
+ } ) ;
225
+ customAttributeConditionEvaluator . evaluate . returns ( null ) ;
226
+ var userAttributes = { device_model : 5.5 } ;
227
+ var result = audienceEvaluator . evaluate ( [ 'or' , '1' ] , audiencesById , userAttributes , mockLogger ) ;
228
+ sinon . assert . calledOnce ( customAttributeConditionEvaluator . evaluate ) ;
229
+ sinon . assert . calledWithExactly ( customAttributeConditionEvaluator . evaluate , iphoneUserAudience . conditions [ 1 ] , userAttributes , mockLogger ) ;
230
+ assert . isFalse ( result ) ;
231
+ assert . strictEqual ( 2 , mockLogger . log . callCount ) ;
232
+ assert . strictEqual ( mockLogger . log . args [ 0 ] [ 1 ] , 'AUDIENCE_EVALUATOR: Starting to evaluate audience "1" with conditions: ["and",{"name":"device_model","value":"iphone","type":"custom_attribute"}].' ) ;
233
+ assert . strictEqual ( mockLogger . log . args [ 1 ] [ 1 ] , 'AUDIENCE_EVALUATOR: Audience "1" evaluated to UNKNOWN.' ) ;
234
+ } ) ;
235
+
236
+ it ( 'logs correctly when conditionTreeEvaluator.evaluate returns true' , function ( ) {
237
+ conditionTreeEvaluator . evaluate . callsFake ( function ( conditions , leafEvaluator ) {
238
+ return leafEvaluator ( conditions [ 1 ] ) ;
239
+ } ) ;
240
+ customAttributeConditionEvaluator . evaluate . returns ( true ) ;
241
+ var userAttributes = { device_model : 'iphone' } ;
242
+ var result = audienceEvaluator . evaluate ( [ 'or' , '1' ] , audiencesById , userAttributes , mockLogger ) ;
243
+ sinon . assert . calledOnce ( customAttributeConditionEvaluator . evaluate ) ;
244
+ sinon . assert . calledWithExactly ( customAttributeConditionEvaluator . evaluate , iphoneUserAudience . conditions [ 1 ] , userAttributes , mockLogger ) ;
245
+ assert . isTrue ( result ) ;
246
+ assert . strictEqual ( 2 , mockLogger . log . callCount ) ;
247
+ assert . strictEqual ( mockLogger . log . args [ 0 ] [ 1 ] , 'AUDIENCE_EVALUATOR: Starting to evaluate audience "1" with conditions: ["and",{"name":"device_model","value":"iphone","type":"custom_attribute"}].' ) ;
248
+ assert . strictEqual ( mockLogger . log . args [ 1 ] [ 1 ] , 'AUDIENCE_EVALUATOR: Audience "1" evaluated to TRUE.' ) ;
249
+ } ) ;
250
+
251
+ it ( 'logs correctly when conditionTreeEvaluator.evaluate returns false' , function ( ) {
252
+ conditionTreeEvaluator . evaluate . callsFake ( function ( conditions , leafEvaluator ) {
253
+ return leafEvaluator ( conditions [ 1 ] ) ;
254
+ } ) ;
255
+ customAttributeConditionEvaluator . evaluate . returns ( false ) ;
256
+ var userAttributes = { device_model : 'android' } ;
257
+ var result = audienceEvaluator . evaluate ( [ 'or' , '1' ] , audiencesById , userAttributes , mockLogger ) ;
184
258
sinon . assert . calledOnce ( customAttributeConditionEvaluator . evaluate ) ;
185
- sinon . assert . calledWithExactly ( customAttributeConditionEvaluator . evaluate , iphoneUserAudience . conditions [ 1 ] , userAttributes ) ;
259
+ sinon . assert . calledWithExactly ( customAttributeConditionEvaluator . evaluate , iphoneUserAudience . conditions [ 1 ] , userAttributes , mockLogger ) ;
186
260
assert . isFalse ( result ) ;
261
+ assert . strictEqual ( 2 , mockLogger . log . callCount ) ;
262
+ assert . strictEqual ( mockLogger . log . args [ 0 ] [ 1 ] , 'AUDIENCE_EVALUATOR: Starting to evaluate audience "1" with conditions: ["and",{"name":"device_model","value":"iphone","type":"custom_attribute"}].' ) ;
263
+ assert . strictEqual ( mockLogger . log . args [ 1 ] [ 1 ] , 'AUDIENCE_EVALUATOR: Audience "1" evaluated to FALSE.' ) ;
187
264
} ) ;
188
265
} ) ;
189
266
} ) ;
0 commit comments