1818class MigratorTest extends \PHPUnit \Framework \TestCase
1919{
2020 private MigratorBuilder $ builder ;
21+ private MockEventProcessor $ eventProcessor ;
2122
2223 public function setUp (): void
2324 {
@@ -27,9 +28,10 @@ public function setUp(): void
2728 $ requester ->addFlag ($ this ->makeOffFlagWithValue ($ stage ->value , $ stage ->value ));
2829 }
2930
31+ $ this ->eventProcessor = new MockEventProcessor ();
3032 $ options = [
3133 'feature_requester ' => $ requester ,
32- 'event_processor ' => new MockEventProcessor ()
34+ 'event_processor ' => $ this -> eventProcessor ,
3335 ];
3436
3537 $ client = new LDClient ("someKey " , $ options );
@@ -138,23 +140,77 @@ public function readStageOriginProvider(): array
138140 */
139141 public function testTrackingInvokedForReads (Stage $ stage , array $ origins ): void
140142 {
141- $ this ->markTestSkipped ('skipped until sc-219378 ' );
143+ /** @var Migrator */
144+ $ migrator = $ this ->builder ->build ()->value ;
145+ $ migrator ->read ($ stage ->value , LDContext::create ('user-key ' ), Stage::LIVE );
146+
147+ $ events = $ this ->eventProcessor ->getEvents ();
148+
149+ $ this ->assertCount (2 , $ events );
150+
151+ $ event = $ events [1 ]; // First event is evaluation result
152+ $ invoked = $ event ['measurements ' ][0 ];
153+
154+ $ this ->assertEquals ('invoked ' , $ invoked ['key ' ]);
155+
156+ array_map (fn ($ origin ) => $ this ->assertTrue ($ invoked ['values ' ][$ origin ->value ]), $ origins );
142157 }
143158
144159 /**
145160 * @dataProvider readStageOriginProvider
146161 */
147162 public function testTrackingLatencyForReads (Stage $ stage , array $ origins ): void
148163 {
149- $ this ->markTestSkipped ('skipped until sc-219378 ' );
164+ $ delayed = function (mixed $ payload ): Result {
165+ return Result::success (null );
166+ };
167+
168+ $ this ->builder ->read ($ delayed , $ delayed );
169+ $ this ->builder ->trackLatency (true );
170+
171+ /** @var Migrator */
172+ $ migrator = $ this ->builder ->build ()->value ;
173+ $ migrator ->read ($ stage ->value , LDContext::create ('user-key ' ), Stage::LIVE );
174+
175+ $ events = $ this ->eventProcessor ->getEvents ();
176+
177+ $ this ->assertCount (2 , $ events );
178+
179+ $ event = $ events [1 ]; // First event is evaluation result
180+ $ latencies = $ event ['measurements ' ][1 ]; // First measurement is invoked
181+
182+ $ this ->assertEquals ('latency_ms ' , $ latencies ['key ' ]);
183+ foreach ($ origins as $ origin ) {
184+ $ this ->assertGreaterThanOrEqual ($ latencies ['values ' ][$ origin ->value ], 100 );
185+ }
150186 }
151187
152188 /**
153189 * @dataProvider readStageOriginProvider
154190 */
155191 public function testTrackingErrorsForReads (Stage $ stage , array $ origins ): void
156192 {
157- $ this ->markTestSkipped ('skipped until sc-219378 ' );
193+ $ this ->builder ->read (
194+ fn () => throw new Exception ("old write " ),
195+ fn () => throw new Exception ("new write " ),
196+ );
197+ $ this ->builder ->trackErrors (true );
198+
199+ /** @var Migrator */
200+ $ migrator = $ this ->builder ->build ()->value ;
201+ $ migrator ->read ($ stage ->value , LDContext::create ('user-key ' ), Stage::LIVE );
202+
203+ $ events = $ this ->eventProcessor ->getEvents ();
204+
205+ $ this ->assertCount (2 , $ events );
206+
207+ $ event = $ events [1 ]; // First event is evaluation result
208+ $ errors = $ event ['measurements ' ][1 ]; // First measurement is invoked
209+
210+ $ this ->assertEquals ('error ' , $ errors ['key ' ]);
211+ foreach ($ origins as $ origin ) {
212+ $ this ->assertTrue ($ errors ['values ' ][$ origin ->value ]);
213+ }
158214 }
159215
160216 public function writeStageOriginProvider (): array
@@ -174,28 +230,172 @@ public function writeStageOriginProvider(): array
174230 */
175231 public function testTrackingInvokedForWrites (Stage $ stage , array $ origins ): void
176232 {
177- $ this ->markTestSkipped ('skipped until sc-219377 ' );
233+ /** @var Migrator */
234+ $ migrator = $ this ->builder ->build ()->value ;
235+ $ migrator ->write ($ stage ->value , LDContext::create ('user-key ' ), Stage::LIVE );
236+
237+ $ events = $ this ->eventProcessor ->getEvents ();
238+
239+ $ this ->assertCount (2 , $ events );
240+
241+ $ event = $ events [1 ]; // First event is evaluation result
242+ $ invoked = $ event ['measurements ' ][0 ];
243+
244+ $ this ->assertEquals ('invoked ' , $ invoked ['key ' ]);
245+
246+ array_map (fn ($ origin ) => $ this ->assertTrue ($ invoked ['values ' ][$ origin ->value ]), $ origins );
178247 }
179248
180249 /**
181250 * @dataProvider writeStageOriginProvider
182251 */
183252 public function testTrackingLatencyForWrites (Stage $ stage , array $ origins ): void
184253 {
185- $ this ->markTestSkipped ('skipped until sc-219377 ' );
254+ $ delayed = function (mixed $ payload ): Result {
255+ return Result::success (null );
256+ };
257+
258+ $ this ->builder ->write ($ delayed , $ delayed );
259+ $ this ->builder ->trackLatency (true );
260+
261+ /** @var Migrator */
262+ $ migrator = $ this ->builder ->build ()->value ;
263+ $ migrator ->write ($ stage ->value , LDContext::create ('user-key ' ), Stage::LIVE );
264+
265+ $ events = $ this ->eventProcessor ->getEvents ();
266+
267+ $ this ->assertCount (2 , $ events );
268+
269+ $ event = $ events [1 ]; // First event is evaluation result
270+ $ latencies = $ event ['measurements ' ][1 ]; // First measurement is invoked
271+
272+ $ this ->assertEquals ('latency_ms ' , $ latencies ['key ' ]);
273+ foreach ($ origins as $ origin ) {
274+ $ this ->assertGreaterThanOrEqual ($ latencies ['values ' ][$ origin ->value ], 100 );
275+ }
276+ }
277+
278+ public function authoritativeWriteStageOriginProvider (): array
279+ {
280+ return [
281+ [Stage::OFF , Origin::OLD ],
282+ [Stage::DUALWRITE , Origin::OLD ],
283+ [Stage::SHADOW , Origin::OLD ],
284+ [Stage::LIVE , Origin::NEW ],
285+ [Stage::RAMPDOWN , Origin::NEW ],
286+ [Stage::COMPLETE , Origin::NEW ],
287+ ];
186288 }
187289
188290 /**
189- * @dataProvider writeStageOriginProvider
291+ * @dataProvider authoritativeWriteStageOriginProvider
190292 */
191- public function testTrackingErrorsForWrites (Stage $ stage , array $ origins ): void
293+ public function testTrackingErrorsForAuthoritativeWrites (Stage $ stage , Origin $ origin ): void
192294 {
193- $ this ->markTestSkipped ('skipped until sc-219377 ' );
295+ $ this ->builder ->write (
296+ fn () => throw new Exception ("old write " ),
297+ fn () => throw new Exception ("new write " ),
298+ );
299+ $ this ->builder ->trackErrors (true );
300+
301+ /** @var Migrator */
302+ $ migrator = $ this ->builder ->build ()->value ;
303+ $ migrator ->write ($ stage ->value , LDContext::create ('user-key ' ), Stage::LIVE );
304+
305+ $ events = $ this ->eventProcessor ->getEvents ();
306+
307+ $ this ->assertCount (2 , $ events );
308+
309+ $ event = $ events [1 ]; // First event is evaluation result
310+ $ errors = $ event ['measurements ' ][1 ]; // First measurement is invoked
311+
312+ $ this ->assertEquals ('error ' , $ errors ['key ' ]);
313+ $ this ->assertTrue ($ errors ['values ' ][$ origin ->value ]);
314+ }
315+
316+ public function nonauthoritativeWriteStageOriginProvider (): array
317+ {
318+ return [
319+ // Off and Complete only run authoritative writes so there is nothing to test
320+ [Stage::DUALWRITE , Origin::OLD , Origin::NEW ],
321+ [Stage::SHADOW , Origin::OLD , Origin::NEW ],
322+ [Stage::LIVE , Origin::NEW , Origin::OLD ],
323+ [Stage::RAMPDOWN , Origin::NEW , Origin::OLD ],
324+ ];
325+ }
326+
327+ /**
328+ * @dataProvider nonauthoritativeWriteStageOriginProvider
329+ */
330+ public function testTrackingErrorsForNonAuthoritativeWrites (Stage $ stage , Origin $ authoritative , Origin $ nonauthoritative ): void
331+ {
332+ if ($ authoritative == Origin::OLD ) {
333+ $ this ->builder ->write (
334+ fn () => Result::success (null ),
335+ fn () => throw new Exception ("new write " ),
336+ );
337+ } else {
338+ $ this ->builder ->write (
339+ fn () => throw new Exception ("old write " ),
340+ fn () => Result::success (null ),
341+ );
342+ }
343+ $ this ->builder ->trackErrors (true );
344+
345+ /** @var Migrator */
346+ $ migrator = $ this ->builder ->build ()->value ;
347+ $ migrator ->write ($ stage ->value , LDContext::create ('user-key ' ), Stage::LIVE );
348+
349+ $ events = $ this ->eventProcessor ->getEvents ();
350+
351+ $ this ->assertCount (2 , $ events );
352+
353+ $ event = $ events [1 ]; // First event is evaluation result
354+ $ errors = $ event ['measurements ' ][1 ]; // First measurement is invoked
355+
356+ $ this ->assertEquals ('error ' , $ errors ['key ' ]);
357+ $ this ->assertTrue ($ errors ['values ' ][$ nonauthoritative ->value ]);
194358 }
195359
196- public function testTrackingConsistency (): void
360+ public function trackingConsistencyProvider (): array
197361 {
198- $ this ->markTestSkipped ('skipped until sc-219377 ' );
362+ return [
363+ // SHADOW and LIVE are the only stages that run both reads and as a
364+ // result, can produce consistency values.
365+ [Stage::SHADOW , "same " , "same " , true ],
366+ [Stage::LIVE , "same " , "same " , true ],
367+
368+ [Stage::SHADOW , "different " , "same " , false ],
369+ [Stage::LIVE , "different " , "same " , false ],
370+ ];
371+ }
372+
373+ /**
374+ * @dataProvider trackingConsistencyProvider
375+ */
376+ public function testTrackingConsistency (Stage $ stage , string $ old , string $ new , bool $ shouldMatch ): void
377+ {
378+ $ this ->builder ->read (
379+ fn () => Result::success ($ old ),
380+ fn () => Result::success ($ new ),
381+ fn ($ lhs , $ rhs ) => $ lhs == $ rhs ,
382+ );
383+
384+ /** @var Migrator */
385+ $ migrator = $ this ->builder ->build ()->value ;
386+ $ migrator ->read ($ stage ->value , LDContext::create ('user-key ' ), Stage::LIVE );
387+
388+ $ events = $ this ->eventProcessor ->getEvents ();
389+
390+ $ this ->assertCount (2 , $ events );
391+
392+ $ event = $ events [1 ]; // First event is evaluation result
393+ $ consistency = $ event ['measurements ' ][1 ]; // First measurement is invoked
394+
395+ $ this ->assertEquals ('consistent ' , $ consistency ['key ' ]);
396+ $ this ->assertEquals ($ shouldMatch , $ consistency ['value ' ]);
397+
398+ // TODO(sc-219378): Add sampling tests
199399 }
200400
201401 public function readHandlerExceptionProvider (): array
0 commit comments