mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-22 11:20:15 +01:00
ci: Update AppService tests to initialize app config instead of app.locals
This commit is contained in:
parent
3ecb96149a
commit
5b43bf6c95
1 changed files with 256 additions and 199 deletions
|
|
@ -54,6 +54,11 @@ jest.mock('./Config', () => ({
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('./Config/getAppConfig', () => ({
|
||||||
|
initializeAppConfig: jest.fn(),
|
||||||
|
getAppConfig: jest.fn(),
|
||||||
|
}));
|
||||||
jest.mock('./ToolService', () => ({
|
jest.mock('./ToolService', () => ({
|
||||||
loadAndFormatTools: jest.fn().mockReturnValue({
|
loadAndFormatTools: jest.fn().mockReturnValue({
|
||||||
ExampleTool: {
|
ExampleTool: {
|
||||||
|
|
@ -117,23 +122,23 @@ const azureGroups = [
|
||||||
];
|
];
|
||||||
|
|
||||||
describe('AppService', () => {
|
describe('AppService', () => {
|
||||||
let app;
|
|
||||||
const mockedTurnstileConfig = {
|
const mockedTurnstileConfig = {
|
||||||
siteKey: 'default-site-key',
|
siteKey: 'default-site-key',
|
||||||
options: {},
|
options: {},
|
||||||
};
|
};
|
||||||
|
const { initializeAppConfig } = require('./Config/getAppConfig');
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
app = { locals: {} };
|
|
||||||
process.env.CDN_PROVIDER = undefined;
|
process.env.CDN_PROVIDER = undefined;
|
||||||
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly assign process.env and app.locals based on custom config', async () => {
|
it('should correctly assign process.env and initialize app config based on custom config', async () => {
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
expect(process.env.CDN_PROVIDER).toEqual('testStrategy');
|
expect(process.env.CDN_PROVIDER).toEqual('testStrategy');
|
||||||
|
|
||||||
expect(app.locals).toEqual({
|
expect(initializeAppConfig).toHaveBeenCalledWith({
|
||||||
config: expect.objectContaining({
|
config: expect.objectContaining({
|
||||||
fileStrategy: 'testStrategy',
|
fileStrategy: 'testStrategy',
|
||||||
}),
|
}),
|
||||||
|
|
@ -187,7 +192,7 @@ describe('AppService', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
const { logger } = require('~/config');
|
const { logger } = require('~/config');
|
||||||
expect(logger.info).toHaveBeenCalledWith(expect.stringContaining('Outdated Config version'));
|
expect(logger.info).toHaveBeenCalledWith(expect.stringContaining('Outdated Config version'));
|
||||||
|
|
@ -201,8 +206,12 @@ describe('AppService', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
expect(app.locals.imageOutputType).toEqual(EImageOutputType.WEBP);
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
imageOutputType: EImageOutputType.WEBP,
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should default to `PNG` `imageOutputType` with no provided type', async () => {
|
it('should default to `PNG` `imageOutputType` with no provided type', async () => {
|
||||||
|
|
@ -212,15 +221,23 @@ describe('AppService', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
expect(app.locals.imageOutputType).toEqual(EImageOutputType.PNG);
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
imageOutputType: EImageOutputType.PNG,
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should default to `PNG` `imageOutputType` with no provided config', async () => {
|
it('should default to `PNG` `imageOutputType` with no provided config', async () => {
|
||||||
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(undefined));
|
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(undefined));
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
expect(app.locals.imageOutputType).toEqual(EImageOutputType.PNG);
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
imageOutputType: EImageOutputType.PNG,
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should initialize Firebase when fileStrategy is firebase', async () => {
|
it('should initialize Firebase when fileStrategy is firebase', async () => {
|
||||||
|
|
@ -230,7 +247,7 @@ describe('AppService', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
const { initializeFirebase } = require('./Files/Firebase/initialize');
|
const { initializeFirebase } = require('./Files/Firebase/initialize');
|
||||||
expect(initializeFirebase).toHaveBeenCalled();
|
expect(initializeFirebase).toHaveBeenCalled();
|
||||||
|
|
@ -242,7 +259,7 @@ describe('AppService', () => {
|
||||||
const { loadAndFormatTools } = require('./ToolService');
|
const { loadAndFormatTools } = require('./ToolService');
|
||||||
const { setCachedTools, getCachedTools } = require('./Config');
|
const { setCachedTools, getCachedTools } = require('./Config');
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
expect(loadAndFormatTools).toHaveBeenCalledWith({
|
expect(loadAndFormatTools).toHaveBeenCalledWith({
|
||||||
adminFilter: undefined,
|
adminFilter: undefined,
|
||||||
|
|
@ -305,16 +322,17 @@ describe('AppService', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.assistants);
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals[EModelEndpoint.assistants]).toEqual(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
disableBuilder: true,
|
[EModelEndpoint.assistants]: expect.objectContaining({
|
||||||
pollIntervalMs: 5000,
|
disableBuilder: true,
|
||||||
timeoutMs: 30000,
|
pollIntervalMs: 5000,
|
||||||
supportedIds: expect.arrayContaining(['id1', 'id2']),
|
timeoutMs: 30000,
|
||||||
privateAssistants: false,
|
supportedIds: expect.arrayContaining(['id1', 'id2']),
|
||||||
|
privateAssistants: false,
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
@ -334,16 +352,20 @@ describe('AppService', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.agents);
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals[EModelEndpoint.agents]).toEqual(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
disableBuilder: true,
|
[EModelEndpoint.agents]: expect.objectContaining({
|
||||||
recursionLimit: 10,
|
disableBuilder: true,
|
||||||
maxRecursionLimit: 20,
|
recursionLimit: 10,
|
||||||
allowedProviders: expect.arrayContaining(['openai', 'anthropic']),
|
maxRecursionLimit: 20,
|
||||||
capabilities: expect.arrayContaining([AgentCapabilities.tools, AgentCapabilities.actions]),
|
allowedProviders: expect.arrayContaining(['openai', 'anthropic']),
|
||||||
|
capabilities: expect.arrayContaining([
|
||||||
|
AgentCapabilities.tools,
|
||||||
|
AgentCapabilities.actions,
|
||||||
|
]),
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
@ -351,13 +373,14 @@ describe('AppService', () => {
|
||||||
it('should configure Agents endpoint with defaults when no config is provided', async () => {
|
it('should configure Agents endpoint with defaults when no config is provided', async () => {
|
||||||
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve({}));
|
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve({}));
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.agents);
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals[EModelEndpoint.agents]).toEqual(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
disableBuilder: false,
|
[EModelEndpoint.agents]: expect.objectContaining({
|
||||||
capabilities: expect.arrayContaining([...defaultAgentCapabilities]),
|
disableBuilder: false,
|
||||||
|
capabilities: expect.arrayContaining([...defaultAgentCapabilities]),
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
@ -373,13 +396,17 @@ describe('AppService', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.agents);
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals[EModelEndpoint.agents]).toEqual(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
disableBuilder: false,
|
[EModelEndpoint.agents]: expect.objectContaining({
|
||||||
capabilities: expect.arrayContaining([...defaultAgentCapabilities]),
|
disableBuilder: false,
|
||||||
|
capabilities: expect.arrayContaining([...defaultAgentCapabilities]),
|
||||||
|
}),
|
||||||
|
[EModelEndpoint.openAI]: expect.objectContaining({
|
||||||
|
titleConvo: true,
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
@ -400,9 +427,18 @@ describe('AppService', () => {
|
||||||
process.env.WESTUS_API_KEY = 'westus-key';
|
process.env.WESTUS_API_KEY = 'westus-key';
|
||||||
process.env.EASTUS_API_KEY = 'eastus-key';
|
process.env.EASTUS_API_KEY = 'eastus-key';
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.azureAssistants);
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals[EModelEndpoint.azureAssistants].capabilities.length).toEqual(3);
|
expect.objectContaining({
|
||||||
|
[EModelEndpoint.azureAssistants]: expect.objectContaining({
|
||||||
|
capabilities: expect.arrayContaining([
|
||||||
|
expect.any(String),
|
||||||
|
expect.any(String),
|
||||||
|
expect.any(String),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly configure Azure OpenAI endpoint based on custom config', async () => {
|
it('should correctly configure Azure OpenAI endpoint based on custom config', async () => {
|
||||||
|
|
@ -419,18 +455,18 @@ describe('AppService', () => {
|
||||||
process.env.WESTUS_API_KEY = 'westus-key';
|
process.env.WESTUS_API_KEY = 'westus-key';
|
||||||
process.env.EASTUS_API_KEY = 'eastus-key';
|
process.env.EASTUS_API_KEY = 'eastus-key';
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.azureOpenAI);
|
|
||||||
const azureConfig = app.locals[EModelEndpoint.azureOpenAI];
|
|
||||||
expect(azureConfig).toHaveProperty('modelNames');
|
|
||||||
expect(azureConfig).toHaveProperty('modelGroupMap');
|
|
||||||
expect(azureConfig).toHaveProperty('groupMap');
|
|
||||||
|
|
||||||
const { modelNames, modelGroupMap, groupMap } = validateAzureGroups(azureGroups);
|
const { modelNames, modelGroupMap, groupMap } = validateAzureGroups(azureGroups);
|
||||||
expect(azureConfig.modelNames).toEqual(modelNames);
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(azureConfig.modelGroupMap).toEqual(modelGroupMap);
|
expect.objectContaining({
|
||||||
expect(azureConfig.groupMap).toEqual(groupMap);
|
[EModelEndpoint.azureOpenAI]: expect.objectContaining({
|
||||||
|
modelNames,
|
||||||
|
modelGroupMap,
|
||||||
|
groupMap,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not modify FILE_UPLOAD environment variables without rate limits', async () => {
|
it('should not modify FILE_UPLOAD environment variables without rate limits', async () => {
|
||||||
|
|
@ -442,7 +478,7 @@ describe('AppService', () => {
|
||||||
|
|
||||||
const initialEnv = { ...process.env };
|
const initialEnv = { ...process.env };
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
// Expect environment variables to remain unchanged
|
// Expect environment variables to remain unchanged
|
||||||
expect(process.env.FILE_UPLOAD_IP_MAX).toEqual(initialEnv.FILE_UPLOAD_IP_MAX);
|
expect(process.env.FILE_UPLOAD_IP_MAX).toEqual(initialEnv.FILE_UPLOAD_IP_MAX);
|
||||||
|
|
@ -468,7 +504,7 @@ describe('AppService', () => {
|
||||||
Promise.resolve(rateLimitsConfig),
|
Promise.resolve(rateLimitsConfig),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
// Verify that process.env has been updated according to the rate limits config
|
// Verify that process.env has been updated according to the rate limits config
|
||||||
expect(process.env.FILE_UPLOAD_IP_MAX).toEqual('100');
|
expect(process.env.FILE_UPLOAD_IP_MAX).toEqual('100');
|
||||||
|
|
@ -484,7 +520,7 @@ describe('AppService', () => {
|
||||||
process.env.FILE_UPLOAD_USER_MAX = 'initialUserMax';
|
process.env.FILE_UPLOAD_USER_MAX = 'initialUserMax';
|
||||||
process.env.FILE_UPLOAD_USER_WINDOW = 'initialUserWindow';
|
process.env.FILE_UPLOAD_USER_WINDOW = 'initialUserWindow';
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
// Verify that process.env falls back to the initial values
|
// Verify that process.env falls back to the initial values
|
||||||
expect(process.env.FILE_UPLOAD_IP_MAX).toEqual('initialMax');
|
expect(process.env.FILE_UPLOAD_IP_MAX).toEqual('initialMax');
|
||||||
|
|
@ -502,7 +538,7 @@ describe('AppService', () => {
|
||||||
|
|
||||||
const initialEnv = { ...process.env };
|
const initialEnv = { ...process.env };
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
// Expect environment variables to remain unchanged
|
// Expect environment variables to remain unchanged
|
||||||
expect(process.env.IMPORT_IP_MAX).toEqual(initialEnv.IMPORT_IP_MAX);
|
expect(process.env.IMPORT_IP_MAX).toEqual(initialEnv.IMPORT_IP_MAX);
|
||||||
|
|
@ -528,7 +564,7 @@ describe('AppService', () => {
|
||||||
Promise.resolve(importLimitsConfig),
|
Promise.resolve(importLimitsConfig),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
// Verify that process.env has been updated according to the rate limits config
|
// Verify that process.env has been updated according to the rate limits config
|
||||||
expect(process.env.IMPORT_IP_MAX).toEqual('150');
|
expect(process.env.IMPORT_IP_MAX).toEqual('150');
|
||||||
|
|
@ -544,7 +580,7 @@ describe('AppService', () => {
|
||||||
process.env.IMPORT_USER_MAX = 'initialUserMax';
|
process.env.IMPORT_USER_MAX = 'initialUserMax';
|
||||||
process.env.IMPORT_USER_WINDOW = 'initialUserWindow';
|
process.env.IMPORT_USER_WINDOW = 'initialUserWindow';
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
// Verify that process.env falls back to the initial values
|
// Verify that process.env falls back to the initial values
|
||||||
expect(process.env.IMPORT_IP_MAX).toEqual('initialMax');
|
expect(process.env.IMPORT_IP_MAX).toEqual('initialMax');
|
||||||
|
|
@ -581,37 +617,32 @@ describe('AppService', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
// Check OpenAI endpoint configuration
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.openAI);
|
|
||||||
expect(app.locals[EModelEndpoint.openAI]).toEqual(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
titleConvo: true,
|
// Check OpenAI endpoint configuration
|
||||||
titleModel: 'gpt-3.5-turbo',
|
[EModelEndpoint.openAI]: expect.objectContaining({
|
||||||
titleMethod: 'structured',
|
titleConvo: true,
|
||||||
titlePrompt: 'Custom title prompt for conversation',
|
titleModel: 'gpt-3.5-turbo',
|
||||||
titlePromptTemplate: 'Summarize this conversation: {{conversation}}',
|
titleMethod: 'structured',
|
||||||
}),
|
titlePrompt: 'Custom title prompt for conversation',
|
||||||
);
|
titlePromptTemplate: 'Summarize this conversation: {{conversation}}',
|
||||||
|
}),
|
||||||
// Check Assistants endpoint configuration
|
// Check Assistants endpoint configuration
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.assistants);
|
[EModelEndpoint.assistants]: expect.objectContaining({
|
||||||
expect(app.locals[EModelEndpoint.assistants]).toMatchObject({
|
titleMethod: 'functions',
|
||||||
titleMethod: 'functions',
|
titlePrompt: 'Generate a title for this assistant conversation',
|
||||||
titlePrompt: 'Generate a title for this assistant conversation',
|
titlePromptTemplate: 'Assistant conversation template: {{messages}}',
|
||||||
titlePromptTemplate: 'Assistant conversation template: {{messages}}',
|
}),
|
||||||
});
|
// Check Azure OpenAI endpoint configuration
|
||||||
|
[EModelEndpoint.azureOpenAI]: expect.objectContaining({
|
||||||
// Check Azure OpenAI endpoint configuration
|
titleConvo: true,
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.azureOpenAI);
|
titleMethod: 'completion',
|
||||||
expect(app.locals[EModelEndpoint.azureOpenAI]).toEqual(
|
titleModel: 'gpt-4',
|
||||||
expect.objectContaining({
|
titlePrompt: 'Azure title prompt',
|
||||||
titleConvo: true,
|
titlePromptTemplate: 'Azure conversation: {{context}}',
|
||||||
titleMethod: 'completion',
|
}),
|
||||||
titleModel: 'gpt-4',
|
|
||||||
titlePrompt: 'Azure title prompt',
|
|
||||||
titlePromptTemplate: 'Azure conversation: {{context}}',
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
@ -634,19 +665,25 @@ describe('AppService', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.agents);
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals[EModelEndpoint.agents]).toMatchObject({
|
expect.objectContaining({
|
||||||
disableBuilder: false,
|
[EModelEndpoint.agents]: expect.objectContaining({
|
||||||
titleConvo: true,
|
disableBuilder: false,
|
||||||
titleModel: 'gpt-4',
|
titleConvo: true,
|
||||||
titleMethod: 'structured',
|
titleModel: 'gpt-4',
|
||||||
titlePrompt: 'Generate a descriptive title for this agent conversation',
|
titleMethod: 'structured',
|
||||||
titlePromptTemplate: 'Agent conversation summary: {{content}}',
|
titlePrompt: 'Generate a descriptive title for this agent conversation',
|
||||||
recursionLimit: 15,
|
titlePromptTemplate: 'Agent conversation summary: {{content}}',
|
||||||
capabilities: expect.arrayContaining([AgentCapabilities.tools, AgentCapabilities.actions]),
|
recursionLimit: 15,
|
||||||
});
|
capabilities: expect.arrayContaining([
|
||||||
|
AgentCapabilities.tools,
|
||||||
|
AgentCapabilities.actions,
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle missing title configuration options with defaults', async () => {
|
it('should handle missing title configuration options with defaults', async () => {
|
||||||
|
|
@ -661,16 +698,21 @@ describe('AppService', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.openAI);
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals[EModelEndpoint.openAI]).toMatchObject({
|
expect.objectContaining({
|
||||||
titleConvo: true,
|
[EModelEndpoint.openAI]: expect.objectContaining({
|
||||||
});
|
titleConvo: true,
|
||||||
// Check that the optional fields are undefined when not provided
|
}),
|
||||||
expect(app.locals[EModelEndpoint.openAI].titlePrompt).toBeUndefined();
|
}),
|
||||||
expect(app.locals[EModelEndpoint.openAI].titlePromptTemplate).toBeUndefined();
|
);
|
||||||
expect(app.locals[EModelEndpoint.openAI].titleMethod).toBeUndefined();
|
|
||||||
|
// Verify that optional fields are not set when not provided
|
||||||
|
const initCall = initializeAppConfig.mock.calls[0][0];
|
||||||
|
expect(initCall[EModelEndpoint.openAI].titlePrompt).toBeUndefined();
|
||||||
|
expect(initCall[EModelEndpoint.openAI].titlePromptTemplate).toBeUndefined();
|
||||||
|
expect(initCall[EModelEndpoint.openAI].titleMethod).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly configure titleEndpoint when specified', async () => {
|
it('should correctly configure titleEndpoint when specified', async () => {
|
||||||
|
|
@ -691,23 +733,24 @@ describe('AppService', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
// Check OpenAI endpoint has titleEndpoint
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.openAI);
|
expect.objectContaining({
|
||||||
expect(app.locals[EModelEndpoint.openAI]).toMatchObject({
|
// Check OpenAI endpoint has titleEndpoint
|
||||||
titleConvo: true,
|
[EModelEndpoint.openAI]: expect.objectContaining({
|
||||||
titleModel: 'gpt-3.5-turbo',
|
titleConvo: true,
|
||||||
titleEndpoint: EModelEndpoint.anthropic,
|
titleModel: 'gpt-3.5-turbo',
|
||||||
titlePrompt: 'Generate a concise title',
|
titleEndpoint: EModelEndpoint.anthropic,
|
||||||
});
|
titlePrompt: 'Generate a concise title',
|
||||||
|
}),
|
||||||
// Check Agents endpoint has titleEndpoint
|
// Check Agents endpoint has titleEndpoint
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.agents);
|
[EModelEndpoint.agents]: expect.objectContaining({
|
||||||
expect(app.locals[EModelEndpoint.agents]).toMatchObject({
|
titleEndpoint: 'custom-provider',
|
||||||
titleEndpoint: 'custom-provider',
|
titleMethod: 'structured',
|
||||||
titleMethod: 'structured',
|
}),
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly configure all endpoint when specified', async () => {
|
it('should correctly configure all endpoint when specified', async () => {
|
||||||
|
|
@ -731,39 +774,40 @@ describe('AppService', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
// Check that 'all' endpoint config is loaded
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals).toHaveProperty('all');
|
expect.objectContaining({
|
||||||
expect(app.locals.all).toMatchObject({
|
// Check that 'all' endpoint config is loaded
|
||||||
titleConvo: true,
|
all: expect.objectContaining({
|
||||||
titleModel: 'gpt-4o-mini',
|
titleConvo: true,
|
||||||
titleMethod: 'structured',
|
titleModel: 'gpt-4o-mini',
|
||||||
titlePrompt: 'Default title prompt for all endpoints',
|
titleMethod: 'structured',
|
||||||
titlePromptTemplate: 'Default template: {{conversation}}',
|
titlePrompt: 'Default title prompt for all endpoints',
|
||||||
titleEndpoint: EModelEndpoint.anthropic,
|
titlePromptTemplate: 'Default template: {{conversation}}',
|
||||||
streamRate: 50,
|
titleEndpoint: EModelEndpoint.anthropic,
|
||||||
});
|
streamRate: 50,
|
||||||
|
}),
|
||||||
// Check that OpenAI endpoint has its own config
|
// Check that OpenAI endpoint has its own config
|
||||||
expect(app.locals).toHaveProperty(EModelEndpoint.openAI);
|
[EModelEndpoint.openAI]: expect.objectContaining({
|
||||||
expect(app.locals[EModelEndpoint.openAI]).toMatchObject({
|
titleConvo: true,
|
||||||
titleConvo: true,
|
titleModel: 'gpt-3.5-turbo',
|
||||||
titleModel: 'gpt-3.5-turbo',
|
}),
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('AppService updating app.locals and issuing warnings', () => {
|
describe('AppService updating app config and issuing warnings', () => {
|
||||||
let app;
|
|
||||||
let initialEnv;
|
let initialEnv;
|
||||||
|
const { initializeAppConfig } = require('./Config/getAppConfig');
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Store initial environment variables to restore them after each test
|
// Store initial environment variables to restore them after each test
|
||||||
initialEnv = { ...process.env };
|
initialEnv = { ...process.env };
|
||||||
|
|
||||||
app = { locals: {} };
|
|
||||||
process.env.CDN_PROVIDER = undefined;
|
process.env.CDN_PROVIDER = undefined;
|
||||||
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|
@ -771,26 +815,27 @@ describe('AppService updating app.locals and issuing warnings', () => {
|
||||||
process.env = { ...initialEnv };
|
process.env = { ...initialEnv };
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update app.locals with default values if loadCustomConfig returns undefined', async () => {
|
it('should initialize app config with default values if loadCustomConfig returns undefined', async () => {
|
||||||
// Mock loadCustomConfig to return undefined
|
// Mock loadCustomConfig to return undefined
|
||||||
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(undefined));
|
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(undefined));
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
expect(app.locals).toBeDefined();
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals.paths).toBeDefined();
|
|
||||||
expect(app.locals.config).toEqual({});
|
|
||||||
expect(app.locals.fileStrategy).toEqual(FileSources.local);
|
|
||||||
expect(app.locals.socialLogins).toEqual(defaultSocialLogins);
|
|
||||||
expect(app.locals.balance).toEqual(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
enabled: false,
|
paths: expect.anything(),
|
||||||
startBalance: undefined,
|
config: {},
|
||||||
|
fileStrategy: FileSources.local,
|
||||||
|
socialLogins: defaultSocialLogins,
|
||||||
|
balance: expect.objectContaining({
|
||||||
|
enabled: false,
|
||||||
|
startBalance: undefined,
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update app.locals with values from loadCustomConfig', async () => {
|
it('should initialize app config with values from loadCustomConfig', async () => {
|
||||||
// Mock loadCustomConfig to return a specific config object with a complete balance config
|
// Mock loadCustomConfig to return a specific config object with a complete balance config
|
||||||
const customConfig = {
|
const customConfig = {
|
||||||
fileStrategy: 'firebase',
|
fileStrategy: 'firebase',
|
||||||
|
|
@ -808,17 +853,20 @@ describe('AppService updating app.locals and issuing warnings', () => {
|
||||||
Promise.resolve(customConfig),
|
Promise.resolve(customConfig),
|
||||||
);
|
);
|
||||||
|
|
||||||
await AppService(app);
|
await AppService();
|
||||||
|
|
||||||
expect(app.locals).toBeDefined();
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals.paths).toBeDefined();
|
expect.objectContaining({
|
||||||
expect(app.locals.config).toEqual(customConfig);
|
paths: expect.anything(),
|
||||||
expect(app.locals.fileStrategy).toEqual(customConfig.fileStrategy);
|
config: customConfig,
|
||||||
expect(app.locals.socialLogins).toEqual(customConfig.registration.socialLogins);
|
fileStrategy: customConfig.fileStrategy,
|
||||||
expect(app.locals.balance).toEqual(customConfig.balance);
|
socialLogins: customConfig.registration.socialLogins,
|
||||||
|
balance: customConfig.balance,
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should apply the assistants endpoint configuration correctly to app.locals', async () => {
|
it('should apply the assistants endpoint configuration correctly to app config', async () => {
|
||||||
const mockConfig = {
|
const mockConfig = {
|
||||||
endpoints: {
|
endpoints: {
|
||||||
assistants: {
|
assistants: {
|
||||||
|
|
@ -831,16 +879,22 @@ describe('AppService updating app.locals and issuing warnings', () => {
|
||||||
};
|
};
|
||||||
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig));
|
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig));
|
||||||
|
|
||||||
const app = { locals: {} };
|
await AppService();
|
||||||
await AppService(app);
|
|
||||||
|
|
||||||
expect(app.locals).toHaveProperty('assistants');
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
const { assistants } = app.locals;
|
expect.objectContaining({
|
||||||
expect(assistants.disableBuilder).toBe(true);
|
assistants: expect.objectContaining({
|
||||||
expect(assistants.pollIntervalMs).toBe(5000);
|
disableBuilder: true,
|
||||||
expect(assistants.timeoutMs).toBe(30000);
|
pollIntervalMs: 5000,
|
||||||
expect(assistants.supportedIds).toEqual(['id1', 'id2']);
|
timeoutMs: 30000,
|
||||||
expect(assistants.excludedIds).toBeUndefined();
|
supportedIds: ['id1', 'id2'],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify excludedIds is undefined when not provided
|
||||||
|
const initCall = initializeAppConfig.mock.calls[0][0];
|
||||||
|
expect(initCall.assistants.excludedIds).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should log a warning when both supportedIds and excludedIds are provided', async () => {
|
it('should log a warning when both supportedIds and excludedIds are provided', async () => {
|
||||||
|
|
@ -857,8 +911,7 @@ describe('AppService updating app.locals and issuing warnings', () => {
|
||||||
};
|
};
|
||||||
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig));
|
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig));
|
||||||
|
|
||||||
const app = { locals: {} };
|
await require('./AppService')();
|
||||||
await require('./AppService')(app);
|
|
||||||
|
|
||||||
const { logger } = require('~/config');
|
const { logger } = require('~/config');
|
||||||
expect(logger.warn).toHaveBeenCalledWith(
|
expect(logger.warn).toHaveBeenCalledWith(
|
||||||
|
|
@ -879,8 +932,7 @@ describe('AppService updating app.locals and issuing warnings', () => {
|
||||||
};
|
};
|
||||||
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig));
|
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig));
|
||||||
|
|
||||||
const app = { locals: {} };
|
await require('./AppService')();
|
||||||
await require('./AppService')(app);
|
|
||||||
|
|
||||||
const { logger } = require('~/config');
|
const { logger } = require('~/config');
|
||||||
expect(logger.warn).toHaveBeenCalledWith(
|
expect(logger.warn).toHaveBeenCalledWith(
|
||||||
|
|
@ -905,8 +957,7 @@ describe('AppService updating app.locals and issuing warnings', () => {
|
||||||
process.env[varInfo.key] = 'test';
|
process.env[varInfo.key] = 'test';
|
||||||
});
|
});
|
||||||
|
|
||||||
const app = { locals: {} };
|
await require('./AppService')();
|
||||||
await require('./AppService')(app);
|
|
||||||
|
|
||||||
const { logger } = require('~/config');
|
const { logger } = require('~/config');
|
||||||
deprecatedAzureVariables.forEach(({ key, description }) => {
|
deprecatedAzureVariables.forEach(({ key, description }) => {
|
||||||
|
|
@ -931,8 +982,7 @@ describe('AppService updating app.locals and issuing warnings', () => {
|
||||||
process.env[varInfo.key] = 'test';
|
process.env[varInfo.key] = 'test';
|
||||||
});
|
});
|
||||||
|
|
||||||
const app = { locals: {} };
|
await require('./AppService')();
|
||||||
await require('./AppService')(app);
|
|
||||||
|
|
||||||
const { logger } = require('~/config');
|
const { logger } = require('~/config');
|
||||||
conflictingAzureVariables.forEach(({ key }) => {
|
conflictingAzureVariables.forEach(({ key }) => {
|
||||||
|
|
@ -959,16 +1009,19 @@ describe('AppService updating app.locals and issuing warnings', () => {
|
||||||
process.env.OCR_API_KEY_CUSTOM_VAR_NAME = 'actual-api-key';
|
process.env.OCR_API_KEY_CUSTOM_VAR_NAME = 'actual-api-key';
|
||||||
process.env.OCR_BASEURL_CUSTOM_VAR_NAME = 'https://actual-ocr-url.com';
|
process.env.OCR_BASEURL_CUSTOM_VAR_NAME = 'https://actual-ocr-url.com';
|
||||||
|
|
||||||
// Initialize app
|
await AppService();
|
||||||
const app = { locals: {} };
|
|
||||||
await AppService(app);
|
|
||||||
|
|
||||||
// Verify that the raw string references were preserved and not interpolated
|
// Verify that the raw string references were preserved and not interpolated
|
||||||
expect(app.locals.ocr).toBeDefined();
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals.ocr.apiKey).toEqual('${OCR_API_KEY_CUSTOM_VAR_NAME}');
|
expect.objectContaining({
|
||||||
expect(app.locals.ocr.baseURL).toEqual('${OCR_BASEURL_CUSTOM_VAR_NAME}');
|
ocr: expect.objectContaining({
|
||||||
expect(app.locals.ocr.strategy).toEqual('mistral_ocr');
|
apiKey: '${OCR_API_KEY_CUSTOM_VAR_NAME}',
|
||||||
expect(app.locals.ocr.mistralModel).toEqual('mistral-medium');
|
baseURL: '${OCR_BASEURL_CUSTOM_VAR_NAME}',
|
||||||
|
strategy: 'mistral_ocr',
|
||||||
|
mistralModel: 'mistral-medium',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly configure peoplePicker permissions when specified', async () => {
|
it('should correctly configure peoplePicker permissions when specified', async () => {
|
||||||
|
|
@ -984,15 +1037,19 @@ describe('AppService updating app.locals and issuing warnings', () => {
|
||||||
|
|
||||||
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig));
|
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig));
|
||||||
|
|
||||||
const app = { locals: {} };
|
await AppService();
|
||||||
await AppService(app);
|
|
||||||
|
|
||||||
// Check that interface config includes the permissions
|
// Check that interface config includes the permissions
|
||||||
expect(app.locals.interfaceConfig.peoplePicker).toBeDefined();
|
expect(initializeAppConfig).toHaveBeenCalledWith(
|
||||||
expect(app.locals.interfaceConfig.peoplePicker).toMatchObject({
|
expect.objectContaining({
|
||||||
users: true,
|
interfaceConfig: expect.objectContaining({
|
||||||
groups: true,
|
peoplePicker: expect.objectContaining({
|
||||||
roles: true,
|
users: true,
|
||||||
});
|
groups: true,
|
||||||
|
roles: true,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue