diff --git a/src/assignment-logger.spec.ts b/src/assignment-logger.spec.ts index 88ea82c..2f4e0a9 100644 --- a/src/assignment-logger.spec.ts +++ b/src/assignment-logger.spec.ts @@ -1,4 +1,5 @@ import { IAssignmentEvent } from './assignment-logger'; +import { AllocationEvaluationCode } from './flag-evaluation-details-builder'; describe('IAssignmentEvent', () => { it('should allow adding arbitrary fields', () => { @@ -11,6 +12,22 @@ describe('IAssignmentEvent', () => { timestamp: new Date().toISOString(), subjectAttributes: { age: 25, country: 'USA' }, holdoutKey: 'holdout_key_123', + details: { + variationKey: 'variationKey', + variationValue: 'variation_123', + flagEvaluationCode: 'MATCH', + flagEvaluationDescription: '', + configFetchedAt: new Date().toISOString(), + configPublishedAt: new Date().toISOString(), + matchedRule: null, + matchedAllocation: { + key: 'allocation_123', + allocationEvaluationCode: AllocationEvaluationCode.MATCH, + orderPosition: 1, + }, + unmatchedAllocations: [], + unevaluatedAllocations: [], + }, }; expect(event.holdoutKey).toBe('holdout_key_123'); diff --git a/src/assignment-logger.ts b/src/assignment-logger.ts index bda5c8e..019c876 100644 --- a/src/assignment-logger.ts +++ b/src/assignment-logger.ts @@ -1,3 +1,5 @@ +import { IFlagEvaluationDetails } from './flag-evaluation-details-builder'; + export enum HoldoutVariationEnum { STATUS_QUO = 'status_quo', ALL_SHIPPED = 'all_shipped_variants', @@ -46,6 +48,11 @@ export interface IAssignmentEvent { [propName: string]: unknown; metaData?: Record; + + /** + * The flag evaluation details + */ + details: IFlagEvaluationDetails; } /** diff --git a/src/client/eppo-client-assignment-details.spec.ts b/src/client/eppo-client-assignment-details.spec.ts index 7c973a6..2661f7b 100644 --- a/src/client/eppo-client-assignment-details.spec.ts +++ b/src/client/eppo-client-assignment-details.spec.ts @@ -15,7 +15,7 @@ import FetchHttpClient from '../http-client'; import { Flag, ObfuscatedFlag, VariationType } from '../interfaces'; import { OperatorType } from '../rules'; -import EppoClient, { AssignmentDetails } from './eppo-client'; +import EppoClient, { IAssignmentDetails } from './eppo-client'; async function init(configurationStore: IConfigurationStore) { const apiEndpoints = new ApiEndpoints({ @@ -57,7 +57,7 @@ describe('EppoClient get*AssignmentDetails', () => { subjectAttributes, 0, ); - const expected: AssignmentDetails = { + const expected: IAssignmentDetails = { value: 3, variationKey: 'three', variationValue: 3, @@ -92,7 +92,7 @@ describe('EppoClient get*AssignmentDetails', () => { expect(result).toMatchObject(expected); }); - it('should set the details for a matched split', () => { + it.only('should set the details for a matched split', () => { const client = new EppoClient(storage); client.setIsGracefulFailureMode(false); const subjectAttributes = { email: 'alice@mycompany.com', country: 'Brazil' }; @@ -102,7 +102,7 @@ describe('EppoClient get*AssignmentDetails', () => { subjectAttributes, 0, ); - const expected: AssignmentDetails = { + const expected: IAssignmentDetails = { value: 2, variationKey: 'two', variationValue: 2, @@ -115,13 +115,13 @@ describe('EppoClient get*AssignmentDetails', () => { matchedAllocation: { key: '50/50 split', allocationEvaluationCode: AllocationEvaluationCode.MATCH, - orderPosition: 1, + orderPosition: 2, }, unmatchedAllocations: [ { key: 'targeted allocation', allocationEvaluationCode: AllocationEvaluationCode.FAILING_RULE, - orderPosition: 0, + orderPosition: 1, }, ], unevaluatedAllocations: [], @@ -139,7 +139,7 @@ describe('EppoClient get*AssignmentDetails', () => { subjectAttributes, '', ); - const expected: AssignmentDetails = { + const expected: IAssignmentDetails = { value: 'control', flagEvaluationCode: 'MATCH', flagEvaluationDescription: @@ -201,7 +201,7 @@ describe('EppoClient get*AssignmentDetails', () => { matchedAllocation: null, unmatchedAllocations: [], unevaluatedAllocations: [], - } as AssignmentDetails); + } as IAssignmentDetails); }); describe('UFC General Test Cases', () => { diff --git a/src/client/eppo-client.spec.ts b/src/client/eppo-client.spec.ts index ca32102..0104f57 100644 --- a/src/client/eppo-client.spec.ts +++ b/src/client/eppo-client.spec.ts @@ -6,11 +6,9 @@ import { MOCK_UFC_RESPONSE_FILE, OBFUSCATED_MOCK_UFC_RESPONSE_FILE, SubjectTestCase, - getTestAssignmentDetails, getTestAssignments, readAssignmentTestData, readMockUFCResponse, - validateTestAssignmentDetails, validateTestAssignments, } from '../../test/testHelpers'; import ApiEndpoints from '../api-endpoints'; @@ -19,16 +17,10 @@ import { IConfigurationStore } from '../configuration-store/configuration-store' import { MemoryOnlyConfigurationStore } from '../configuration-store/memory.store'; import { MAX_EVENT_QUEUE_SIZE, POLL_INTERVAL_MS, POLL_JITTER_PCT } from '../constants'; import FlagConfigurationRequestor from '../flag-configuration-requestor'; -import { AllocationEvaluationCode } from '../flag-evaluation-details-builder'; import FetchHttpClient from '../http-client'; import { Flag, ObfuscatedFlag, VariationType } from '../interfaces'; -import { OperatorType } from '../rules'; -import EppoClient, { - AssignmentDetails, - FlagConfigurationRequestParameters, - checkTypeMatch, -} from './eppo-client'; +import EppoClient, { FlagConfigurationRequestParameters, checkTypeMatch } from './eppo-client'; export async function init(configurationStore: IConfigurationStore) { const apiEndpoints = new ApiEndpoints({ diff --git a/src/client/eppo-client.ts b/src/client/eppo-client.ts index 3080b21..b19c3ea 100644 --- a/src/client/eppo-client.ts +++ b/src/client/eppo-client.ts @@ -19,7 +19,7 @@ import { EppoValue } from '../eppo_value'; import { Evaluator, FlagEvaluation, noneResult } from '../evaluator'; import FlagConfigurationRequestor from '../flag-configuration-requestor'; import { - FlagEvaluationDetails, + IFlagEvaluationDetails, FlagEvaluationDetailsBuilder, } from '../flag-evaluation-details-builder'; import FetchHttpClient from '../http-client'; @@ -31,7 +31,7 @@ import { validateNotBlank } from '../validation'; import { LIB_VERSION } from '../version'; export interface IAssignmentDetails - extends FlagEvaluationDetails { + extends IFlagEvaluationDetails { value: T; } @@ -400,7 +400,7 @@ export default class EppoClient { subjectAttributes: Record, defaultValue: EppoValue, expectedVariationType: VariationType, - ): { eppoValue: EppoValue; flagEvaluationDetails: FlagEvaluationDetails } { + ): { eppoValue: EppoValue; flagEvaluationDetails: IFlagEvaluationDetails } { try { const result = this.getAssignmentDetail( flagKey, @@ -622,6 +622,7 @@ export default class EppoClient { sdkLanguage: 'javascript', sdkLibVersion: LIB_VERSION, }, + details: result.flagEvaluationDetails, }; if (variation && allocationKey) { diff --git a/src/evaluator.ts b/src/evaluator.ts index cd13b86..a270120 100644 --- a/src/evaluator.ts +++ b/src/evaluator.ts @@ -1,7 +1,7 @@ import { AllocationEvaluation, AllocationEvaluationCode, - FlagEvaluationDetails, + IFlagEvaluationDetails, FlagEvaluationDetailsBuilder, } from './flag-evaluation-details-builder'; import { Flag, Shard, Range, Variation, Allocation, Split, VariationType } from './interfaces'; @@ -17,7 +17,7 @@ export interface FlagEvaluation { variation: Variation | null; extraLogging: Record; doLog: boolean; - flagEvaluationDetails: FlagEvaluationDetails; + flagEvaluationDetails: IFlagEvaluationDetails; } export class Evaluator { @@ -166,7 +166,7 @@ export function noneResult( flagKey: string, subjectKey: string, subjectAttributes: SubjectAttributes, - flagEvaluationDetails: FlagEvaluationDetails, + flagEvaluationDetails: IFlagEvaluationDetails, ): FlagEvaluation { return { flagKey, diff --git a/src/flag-evaluation-details-builder.ts b/src/flag-evaluation-details-builder.ts index 0c978df..b785dd8 100644 --- a/src/flag-evaluation-details-builder.ts +++ b/src/flag-evaluation-details-builder.ts @@ -26,7 +26,7 @@ export interface AllocationEvaluation { orderPosition: number; } -export interface FlagEvaluationDetails { +export interface IFlagEvaluationDetails { variationKey: string | null; variationValue: Variation['value'] | null; flagEvaluationCode: FlagEvaluationCode; @@ -40,12 +40,12 @@ export interface FlagEvaluationDetails { } export class FlagEvaluationDetailsBuilder { - private variationKey: FlagEvaluationDetails['variationKey']; - private variationValue: FlagEvaluationDetails['variationValue']; - private matchedRule: FlagEvaluationDetails['matchedRule']; - private matchedAllocation: FlagEvaluationDetails['matchedAllocation']; - private unmatchedAllocations: FlagEvaluationDetails['unmatchedAllocations']; - private unevaluatedAllocations: FlagEvaluationDetails['unevaluatedAllocations']; + private variationKey: IFlagEvaluationDetails['variationKey']; + private variationValue: IFlagEvaluationDetails['variationValue']; + private matchedRule: IFlagEvaluationDetails['matchedRule']; + private matchedAllocation: IFlagEvaluationDetails['matchedAllocation']; + private unmatchedAllocations: IFlagEvaluationDetails['unmatchedAllocations']; + private unevaluatedAllocations: IFlagEvaluationDetails['unevaluatedAllocations']; constructor( private readonly allocations: Allocation[], @@ -122,12 +122,12 @@ export class FlagEvaluationDetailsBuilder { buildForNoneResult = ( flagEvaluationCode: FlagEvaluationCode, flagEvaluationDescription: string, - ): FlagEvaluationDetails => this.setNone().build(flagEvaluationCode, flagEvaluationDescription); + ): IFlagEvaluationDetails => this.setNone().build(flagEvaluationCode, flagEvaluationDescription); build = ( flagEvaluationCode: FlagEvaluationCode, flagEvaluationDescription: string, - ): FlagEvaluationDetails => ({ + ): IFlagEvaluationDetails => ({ flagEvaluationCode, flagEvaluationDescription, variationKey: this.variationKey, diff --git a/test/testHelpers.ts b/test/testHelpers.ts index 7ef0c0d..b810473 100644 --- a/test/testHelpers.ts +++ b/test/testHelpers.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; -import { AssignmentDetails } from '../src/client/eppo-client'; +import { IAssignmentDetails } from '../src/client/eppo-client'; import { Flag, VariationType } from '../src/interfaces'; import { AttributeType } from '../src/types'; @@ -13,7 +13,7 @@ export interface SubjectTestCase { subjectKey: string; subjectAttributes: Record; assignment: string | number | boolean | object; - assignmentDetails: AssignmentDetails; + assignmentDetails: IAssignmentDetails; } export interface IAssignmentTestCase { @@ -70,7 +70,7 @@ export function getTestAssignmentDetails( ) => never, ): { subject: SubjectTestCase; - assignmentDetails: AssignmentDetails; + assignmentDetails: IAssignmentDetails; }[] { return testCase.subjects.map((subject) => ({ subject, @@ -108,7 +108,7 @@ export function validateTestAssignments( export function validateTestAssignmentDetails( assignments: { subject: SubjectTestCase; - assignmentDetails: AssignmentDetails; + assignmentDetails: IAssignmentDetails; }[], flag: string, ) {