Skip to content

Commit 6b8e782

Browse files
committed
test in place
1 parent 90dabbc commit 6b8e782

File tree

1 file changed

+126
-2
lines changed

1 file changed

+126
-2
lines changed

src/client/eppo-client-with-bandits.spec.ts

Lines changed: 126 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ import {
88
} from '../../test/testHelpers';
99
import ApiEndpoints from '../api-endpoints';
1010
import { IAssignmentEvent, IAssignmentLogger } from '../assignment-logger';
11-
import { BanditEvaluator } from '../bandit-evaluator';
11+
import { BanditEvaluation, BanditEvaluator } from '../bandit-evaluator';
1212
import { IBanditEvent, IBanditLogger } from '../bandit-logger';
1313
import ConfigurationRequestor from '../configuration-requestor';
1414
import { MemoryOnlyConfigurationStore } from '../configuration-store/memory.store';
15+
import { Evaluator, FlagEvaluation } from '../evaluator';
1516
import {
1617
AllocationEvaluationCode,
1718
IFlagEvaluationDetails,
@@ -20,7 +21,7 @@ import FetchHttpClient from '../http-client';
2021
import { BanditVariation, BanditParameters, Flag } from '../interfaces';
2122
import { Attributes, ContextAttributes } from '../types';
2223

23-
import EppoClient from './eppo-client';
24+
import EppoClient, { IAssignmentDetails } from './eppo-client';
2425

2526
describe('EppoClient Bandits E2E test', () => {
2627
const flagStore = new MemoryOnlyConfigurationStore<Flag>();
@@ -429,5 +430,128 @@ describe('EppoClient Bandits E2E test', () => {
429430
expect(mockLogBanditAction.mock.calls[1][0].actionProbability).toBeCloseTo(0.256);
430431
});
431432
});
433+
434+
describe('Assignment logging deduplication', () => {
435+
let mockEvaluateFlag: jest.SpyInstance;
436+
let mockEvaluateBandit: jest.SpyInstance;
437+
let variationToReturn: string;
438+
let actionToReturn: string | null;
439+
440+
// Convenience method for repeatedly making the exact same assignment call
441+
function requestClientBanditAction(): Omit<IAssignmentDetails<string>, 'evaluationDetails'> {
442+
return client.getBanditAction(flagKey, subjectKey, subjectAttributes, ['toyota', 'honda'], 'control');
443+
}
444+
445+
beforeAll(() => {
446+
mockEvaluateFlag = jest
447+
.spyOn(Evaluator.prototype, 'evaluateFlag')
448+
.mockImplementation(() => {
449+
return {
450+
flagKey,
451+
subjectKey,
452+
subjectAttributes,
453+
allocationKey: 'mock-allocation',
454+
variation: { key: variationToReturn, value: variationToReturn },
455+
extraLogging: {},
456+
doLog: true,
457+
flagEvaluationDetails: {
458+
flagEvaluationCode: 'MATCH',
459+
flagEvaluationDescription: 'Mocked evaluation',
460+
},
461+
} as FlagEvaluation;
462+
});
463+
464+
mockEvaluateBandit = jest
465+
.spyOn(BanditEvaluator.prototype, 'evaluateBandit')
466+
.mockImplementation(() => {
467+
return {
468+
flagKey,
469+
subjectKey,
470+
subjectAttributes: { numericAttributes: {}, categoricalAttributes: {} },
471+
actionKey: actionToReturn,
472+
actionAttributes: { numericAttributes: {}, categoricalAttributes: {} },
473+
actionScore: 10,
474+
actionWeight: 0.5,
475+
gamma: 1.0,
476+
optimalityGap: 5,
477+
} as BanditEvaluation;
478+
});
479+
});
480+
481+
beforeEach(() => {
482+
client.useNonExpiringInMemoryAssignmentCache();
483+
});
484+
485+
afterEach(() => {
486+
client.disableAssignmentCache();
487+
});
488+
489+
afterAll(() => {
490+
mockEvaluateFlag.mockClear();
491+
mockEvaluateBandit.mockClear();
492+
});
493+
494+
it('handles bandit actions appropriately', async () => {
495+
// First assign to non-bandit variation
496+
variationToReturn = 'non-bandit';
497+
actionToReturn = null;
498+
const firstNonBanditAssignment = requestClientBanditAction();
499+
500+
expect(firstNonBanditAssignment.variation).toBe('non-bandit');
501+
expect(firstNonBanditAssignment.action).toBeNull();
502+
expect(mockLogAssignment).toHaveBeenCalledTimes(1);
503+
expect(mockLogBanditAction).not.toHaveBeenCalled();
504+
505+
// Assign bandit action
506+
variationToReturn = 'banner_bandit';
507+
actionToReturn = 'toyota';
508+
const firstBanditAssignment = requestClientBanditAction();
509+
510+
expect(firstBanditAssignment.variation).toBe('banner_bandit');
511+
expect(firstBanditAssignment.action).toBe('toyota');
512+
expect(mockLogAssignment).toHaveBeenCalledTimes(2);
513+
expect(mockLogBanditAction).toHaveBeenCalledTimes(1);
514+
515+
// Repeat bandit action assignment
516+
variationToReturn = 'banner_bandit';
517+
actionToReturn = 'toyota';
518+
const secondBanditAssignment = requestClientBanditAction();
519+
520+
expect(secondBanditAssignment.variation).toBe('banner_bandit');
521+
expect(secondBanditAssignment.action).toBe('toyota');
522+
expect(mockLogAssignment).toHaveBeenCalledTimes(2);
523+
expect(mockLogBanditAction).toHaveBeenCalledTimes(1);
524+
525+
// New bandit action assignment
526+
variationToReturn = 'banner_bandit';
527+
actionToReturn = 'honda';
528+
const thirdBanditAssignment = requestClientBanditAction();
529+
530+
expect(thirdBanditAssignment.variation).toBe('banner_bandit');
531+
expect(thirdBanditAssignment.action).toBe('honda');
532+
expect(mockLogAssignment).toHaveBeenCalledTimes(2);
533+
expect(mockLogBanditAction).toHaveBeenCalledTimes(2);
534+
535+
// Flip-flop to an earlier action assignment
536+
variationToReturn = 'banner_bandit';
537+
actionToReturn = 'toyota';
538+
const fourthBanditAssignment = requestClientBanditAction();
539+
540+
expect(fourthBanditAssignment.variation).toBe('banner_bandit');
541+
expect(thirdBanditAssignment.action).toBe('toyota');
542+
expect(mockLogAssignment).toHaveBeenCalledTimes(2);
543+
expect(mockLogBanditAction).toHaveBeenCalledTimes(3);
544+
545+
// Flip-flop back to non-bandit assignment
546+
variationToReturn = 'non-bandit';
547+
actionToReturn = null;
548+
const secondNonBanditAssignment = requestClientBanditAction();
549+
550+
expect(secondNonBanditAssignment.variation).toBe('non-bandit');
551+
expect(secondNonBanditAssignment.action).toBeNull();
552+
expect(mockLogAssignment).toHaveBeenCalledTimes(3);
553+
expect(mockLogBanditAction).toHaveBeenCalledTimes(3);
554+
});
555+
});
432556
});
433557
});

0 commit comments

Comments
 (0)