Path: blob/main/extensions/copilot/src/lib/vscode-node/test/simpleExperimentationService.spec.ts
13399 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { describe, expect, it } from 'vitest';6import { DefaultsOnlyConfigurationService } from '../../../platform/configuration/common/defaultsOnlyConfigurationService';7import { SimpleExperimentationService } from '../../node/chatLibMain';89describe('SimpleExperimentationService', () => {10it('should initialize with no treatment variables', async () => {11const service = new SimpleExperimentationService(false, new DefaultsOnlyConfigurationService());12await service.hasTreatments();1314expect(service.getTreatmentVariable('nonexistent')).toBeUndefined();1516service.dispose();17});1819it('should update multiple treatment variables at once', () => {20const service = new SimpleExperimentationService(false, new DefaultsOnlyConfigurationService());21const variables: Record<string, boolean | number | string> = {22'feature-a': true,23'feature-b': false,24'max-count': 100,25'experiment-id': 'exp-123'26};2728service.updateTreatmentVariables(variables);2930expect(service.getTreatmentVariable<boolean>('feature-a')).toBe(true);31expect(service.getTreatmentVariable<boolean>('feature-b')).toBe(false);32expect(service.getTreatmentVariable<number>('max-count')).toBe(100);33expect(service.getTreatmentVariable<string>('experiment-id')).toBe('exp-123');3435service.dispose();36});3738it('should fire onDidTreatmentsChange event with all changed variables', () => {39const service = new SimpleExperimentationService(false, new DefaultsOnlyConfigurationService());40const events: string[][] = [];4142service.onDidTreatmentsChange((event) => {43events.push(event.affectedTreatmentVariables);44});4546const variables: Record<string, boolean | number | string> = {47'feature-a': true,48'feature-b': 50,49'feature-c': 'test'50};51service.updateTreatmentVariables(variables);5253expect(events).toHaveLength(1);54expect(events[0]).toHaveLength(3);55expect(events[0]).toContain('feature-a');56expect(events[0]).toContain('feature-b');57expect(events[0]).toContain('feature-c');5859service.dispose();60});6162it('should not fire onDidTreatmentsChange event when no variables change', () => {63const service = new SimpleExperimentationService(false, new DefaultsOnlyConfigurationService());64const events: string[][] = [];6566// Set initial value67const variables1: Record<string, boolean | number | string> = {68'feature-flag': true69};70service.updateTreatmentVariables(variables1);7172service.onDidTreatmentsChange((event) => {73events.push(event.affectedTreatmentVariables);74});7576// Update with same value77const variables2: Record<string, boolean | number | string> = {78'feature-flag': true79};80service.updateTreatmentVariables(variables2);8182expect(events).toHaveLength(0);8384service.dispose();85});8687it('should fire onDidTreatmentsChange event only for changed variables', () => {88const service = new SimpleExperimentationService(false, new DefaultsOnlyConfigurationService());8990// Set initial values91const variables1: Record<string, boolean | number | string> = {92'feature-a': true,93'feature-b': 5094};95service.updateTreatmentVariables(variables1);9697const events: string[][] = [];98service.onDidTreatmentsChange((event) => {99events.push(event.affectedTreatmentVariables);100});101102// Update with one changed value and one unchanged103const variables2: Record<string, boolean | number | string> = {104'feature-a': true, // unchanged105'feature-b': 100 // changed106};107service.updateTreatmentVariables(variables2);108109expect(events).toHaveLength(1);110expect(events[0]).toEqual(['feature-b']);111112service.dispose();113});114115it('should overwrite existing treatment variables', () => {116const service = new SimpleExperimentationService(false, new DefaultsOnlyConfigurationService());117118const variables1: Record<string, boolean | number | string> = {119'feature-flag': true120};121service.updateTreatmentVariables(variables1);122123expect(service.getTreatmentVariable<boolean>('feature-flag')).toBe(true);124125const variables2: Record<string, boolean | number | string> = {126'feature-flag': false127};128service.updateTreatmentVariables(variables2);129130expect(service.getTreatmentVariable<boolean>('feature-flag')).toBe(false);131132service.dispose();133});134135it('should wait for treatment variables when waitForTreatmentVariables = true', async () => {136const service = new SimpleExperimentationService(true, new DefaultsOnlyConfigurationService());137138// hasTreatments() should not resolve until updateTreatmentVariables() is called139let hasTreatmentsResolved = false;140const hasTreatmentsPromise = service.hasTreatments().then(() => {141hasTreatmentsResolved = true;142});143144// Give a bit of time to ensure promise doesn't resolve immediately145await new Promise(resolve => setTimeout(resolve, 10));146expect(hasTreatmentsResolved).toBe(false);147148// Now update treatment variables149const variables: Record<string, boolean | number | string> = {150'test-feature': true151};152service.updateTreatmentVariables(variables);153154// Wait for hasTreatments to resolve155await hasTreatmentsPromise;156expect(hasTreatmentsResolved).toBe(true);157expect(service.getTreatmentVariable<boolean>('test-feature')).toBe(true);158159service.dispose();160});161162it('should remove treatment variable when omitted from update', () => {163const service = new SimpleExperimentationService(false, new DefaultsOnlyConfigurationService());164165// Set initial variables166const variables1: Record<string, boolean | number | string> = {167'feature-a': true,168'feature-b': 50,169'feature-c': 'test'170};171service.updateTreatmentVariables(variables1);172173expect(service.getTreatmentVariable<boolean>('feature-a')).toBe(true);174expect(service.getTreatmentVariable<number>('feature-b')).toBe(50);175expect(service.getTreatmentVariable<string>('feature-c')).toBe('test');176177const events: string[][] = [];178service.onDidTreatmentsChange((event) => {179events.push(event.affectedTreatmentVariables);180});181182// Remove feature-b by omitting it183const variables2: Record<string, boolean | number | string> = {184'feature-a': true,185'feature-c': 'test'186};187service.updateTreatmentVariables(variables2);188189expect(service.getTreatmentVariable<boolean>('feature-a')).toBe(true);190expect(service.getTreatmentVariable<number>('feature-b')).toBeUndefined();191expect(service.getTreatmentVariable<string>('feature-c')).toBe('test');192193expect(events).toHaveLength(1);194expect(events[0]).toEqual(['feature-b']);195196service.dispose();197});198});199200201