Path: blob/main/extensions/copilot/src/extension/byok/node/test/azureOpenAIEndpoint.spec.ts
13405 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 { afterEach, beforeEach, describe, expect, it } from 'vitest';6import { IChatModelInformation, ModelSupportedEndpoint } from '../../../../platform/endpoint/common/endpointProvider';7import { ITestingServicesAccessor } from '../../../../platform/test/node/services';8import { TokenizerType } from '../../../../util/common/tokenizer';9import { DisposableStore } from '../../../../util/vs/base/common/lifecycle';10import { IInstantiationService } from '../../../../util/vs/platform/instantiation/common/instantiation';11import { createExtensionUnitTestingServices } from '../../../test/node/services';12import { AzureOpenAIEndpoint } from '../azureOpenAIEndpoint';1314describe('AzureOpenAIEndpoint', () => {15let modelMetadata: IChatModelInformation;16const disposables = new DisposableStore();17let accessor: ITestingServicesAccessor;18let instaService: IInstantiationService;1920beforeEach(() => {21modelMetadata = {22id: 'test-azure-model',23vendor: 'Microsoft Azure',24name: 'Test Azure Model',25version: '1.0',26model_picker_enabled: true,27is_chat_default: false,28is_chat_fallback: false,29supported_endpoints: [ModelSupportedEndpoint.ChatCompletions],30capabilities: {31type: 'chat',32family: 'openai',33tokenizer: TokenizerType.O200K,34supports: {35parallel_tool_calls: false,36streaming: true,37tool_calls: false,38vision: false,39prediction: false,40thinking: false41},42limits: {43max_prompt_tokens: 128000,44max_output_tokens: 4096,45max_context_window_tokens: 13209646}47}48};4950const testingServiceCollection = createExtensionUnitTestingServices();51accessor = disposables.add(testingServiceCollection.createTestingAccessor());52instaService = accessor.get(IInstantiationService);53});5455afterEach(() => {56disposables.clear();57});5859describe('getExtraHeaders', () => {60it('should use Authorization header with Bearer token for Entra ID authentication', () => {61const entraToken = 'test-entra-token-abc123';62const endpoint = instaService.createInstance(63AzureOpenAIEndpoint,64modelMetadata,65entraToken,66'https://example-endpoint.example.com/v1/chat/completions'67);68const headers = endpoint.getExtraHeaders();6970// Should have Authorization header with Bearer token71expect(headers['Authorization']).toBe(`Bearer ${entraToken}`);7273// Should NOT have api-key header (Azure API key auth)74expect(headers['api-key']).toBeUndefined();7576// Should have standard headers77expect(headers['Content-Type']).toBe('application/json');78});7980it('should override parent class headers to replace api-key with Authorization', () => {81const entraToken = 'test-entra-token-xyz789';82const endpoint = instaService.createInstance(83AzureOpenAIEndpoint,84modelMetadata,85entraToken,86'https://example-endpoint.example.com/v1/chat/completions'87);88const headers = endpoint.getExtraHeaders();8990// Verify the override worked correctly91expect(headers['Authorization']).toBe(`Bearer ${entraToken}`);92expect(headers['api-key']).toBeUndefined();93expect(Object.keys(headers)).not.toContain('api-key');94});9596it('should work with different Azure OpenAI endpoint URLs', () => {97const entraToken = 'test-token-456';9899// Test with different endpoint formats100const urls = [101'https://example-endpoint-1.example.com/v1/chat/completions',102'https://example-endpoint-2.example.com/v1/chat/completions',103'https://example-endpoint-3.example.com/v1/chat/completions'104];105106for (const url of urls) {107const endpoint = instaService.createInstance(108AzureOpenAIEndpoint,109modelMetadata,110entraToken,111url112);113114const headers = endpoint.getExtraHeaders();115116expect(headers['Authorization']).toBe(`Bearer ${entraToken}`);117expect(headers['api-key']).toBeUndefined();118}119});120121it('should preserve other headers from parent class', () => {122const entraToken = 'test-token-789';123const endpoint = instaService.createInstance(124AzureOpenAIEndpoint,125modelMetadata,126entraToken,127'https://example-endpoint.example.com/v1/chat/completions'128);129130const headers = endpoint.getExtraHeaders();131132// Should preserve Content-Type from parent133expect(headers['Content-Type']).toBe('application/json');134135// Should have Authorization header136expect(headers['Authorization']).toBeDefined();137expect(headers['Authorization']).toContain('Bearer');138});139});140141describe('inheritance', () => {142it('should inherit from OpenAIEndpoint and maintain same constructor signature', () => {143const entraToken = 'test-token-inheritance';144145// Should be able to instantiate with same parameters as OpenAIEndpoint146const endpoint = instaService.createInstance(147AzureOpenAIEndpoint,148modelMetadata,149entraToken,150'https://example-endpoint.example.com/v1/chat/completions'151);152153// Should be an instance of AzureOpenAIEndpoint154expect(endpoint).toBeInstanceOf(AzureOpenAIEndpoint);155156// Should have getExtraHeaders method157expect(typeof endpoint.getExtraHeaders).toBe('function');158});159});160});161162163