mirror of
https://github.com/logto-io/logto.git
synced 2025-02-17 22:04:19 -05:00
feat(core): add jwt-customizer test script deployment (#5686)
feat(core): call cloud worker deploy service on custom jwt test call cloud worker deploy service on custom jwt test
This commit is contained in:
parent
63639ad502
commit
568e3dc202
4 changed files with 86 additions and 28 deletions
|
@ -1,13 +1,17 @@
|
||||||
import { LogtoJwtTokenKey } from '@logto/schemas';
|
import {
|
||||||
|
LogtoJwtTokenKey,
|
||||||
|
LogtoJwtTokenKeyType,
|
||||||
|
type JwtCustomizerTestRequestBody,
|
||||||
|
} from '@logto/schemas';
|
||||||
import { pickDefault } from '@logto/shared/esm';
|
import { pickDefault } from '@logto/shared/esm';
|
||||||
import { pick } from '@silverhand/essentials';
|
import { pick } from '@silverhand/essentials';
|
||||||
import Sinon from 'sinon';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
mockJwtCustomizerConfigForAccessToken,
|
mockJwtCustomizerConfigForAccessToken,
|
||||||
mockJwtCustomizerConfigForClientCredentials,
|
mockJwtCustomizerConfigForClientCredentials,
|
||||||
mockLogtoConfigRows,
|
mockLogtoConfigRows,
|
||||||
} from '#src/__mocks__/index.js';
|
} from '#src/__mocks__/index.js';
|
||||||
|
import { mockCloudClient, mockLogtoConfigsLibrary } from '#src/test-utils/mock-libraries.js';
|
||||||
import { MockTenant } from '#src/test-utils/tenant.js';
|
import { MockTenant } from '#src/test-utils/tenant.js';
|
||||||
import { createRequester } from '#src/utils/test-utils.js';
|
import { createRequester } from '#src/utils/test-utils.js';
|
||||||
|
|
||||||
|
@ -18,20 +22,16 @@ const logtoConfigQueries = {
|
||||||
deleteJwtCustomizer: jest.fn(),
|
deleteJwtCustomizer: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const logtoConfigLibraries = {
|
|
||||||
upsertJwtCustomizer: jest.fn(),
|
|
||||||
getJwtCustomizer: jest.fn(),
|
|
||||||
getJwtCustomizers: jest.fn(),
|
|
||||||
updateJwtCustomizer: jest.fn(),
|
|
||||||
deployJwtCustomizerScript: jest.fn(),
|
|
||||||
undeployJwtCustomizerScript: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const settingRoutes = await pickDefault(import('./index.js'));
|
const settingRoutes = await pickDefault(import('./index.js'));
|
||||||
|
|
||||||
describe('configs JWT customizer routes', () => {
|
describe('configs JWT customizer routes', () => {
|
||||||
const tenantContext = new MockTenant(undefined, { logtoConfigs: logtoConfigQueries });
|
const tenantContext = new MockTenant(
|
||||||
Sinon.stub(tenantContext, 'logtoConfigs').value(logtoConfigLibraries);
|
undefined,
|
||||||
|
{ logtoConfigs: logtoConfigQueries },
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
mockLogtoConfigsLibrary
|
||||||
|
);
|
||||||
|
|
||||||
const routeRequester = createRequester({
|
const routeRequester = createRequester({
|
||||||
authedRoutes: settingRoutes,
|
authedRoutes: settingRoutes,
|
||||||
|
@ -48,16 +48,22 @@ describe('configs JWT customizer routes', () => {
|
||||||
rows: [],
|
rows: [],
|
||||||
rowCount: 0,
|
rowCount: 0,
|
||||||
});
|
});
|
||||||
logtoConfigLibraries.upsertJwtCustomizer.mockResolvedValueOnce(
|
mockLogtoConfigsLibrary.upsertJwtCustomizer.mockResolvedValueOnce(
|
||||||
mockJwtCustomizerConfigForAccessToken
|
mockJwtCustomizerConfigForAccessToken
|
||||||
);
|
);
|
||||||
const response = await routeRequester
|
const response = await routeRequester
|
||||||
.put(`/configs/jwt-customizer/access-token`)
|
.put(`/configs/jwt-customizer/access-token`)
|
||||||
.send(mockJwtCustomizerConfigForAccessToken.value);
|
.send(mockJwtCustomizerConfigForAccessToken.value);
|
||||||
|
|
||||||
expect(logtoConfigLibraries.upsertJwtCustomizer).toHaveBeenCalled();
|
expect(mockLogtoConfigsLibrary.deployJwtCustomizerScript).toHaveBeenCalledWith(
|
||||||
|
tenantContext.cloudConnection,
|
||||||
|
{
|
||||||
|
key: LogtoJwtTokenKey.AccessToken,
|
||||||
|
value: mockJwtCustomizerConfigForAccessToken.value,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
expect(logtoConfigLibraries.upsertJwtCustomizer).toHaveBeenCalledWith(
|
expect(mockLogtoConfigsLibrary.upsertJwtCustomizer).toHaveBeenCalledWith(
|
||||||
LogtoJwtTokenKey.AccessToken,
|
LogtoJwtTokenKey.AccessToken,
|
||||||
mockJwtCustomizerConfigForAccessToken.value
|
mockJwtCustomizerConfigForAccessToken.value
|
||||||
);
|
);
|
||||||
|
@ -71,13 +77,13 @@ describe('configs JWT customizer routes', () => {
|
||||||
rows: [mockJwtCustomizerConfigForAccessToken],
|
rows: [mockJwtCustomizerConfigForAccessToken],
|
||||||
rowCount: 1,
|
rowCount: 1,
|
||||||
});
|
});
|
||||||
logtoConfigLibraries.upsertJwtCustomizer.mockResolvedValueOnce(
|
mockLogtoConfigsLibrary.upsertJwtCustomizer.mockResolvedValueOnce(
|
||||||
mockJwtCustomizerConfigForAccessToken
|
mockJwtCustomizerConfigForAccessToken
|
||||||
);
|
);
|
||||||
const response = await routeRequester
|
const response = await routeRequester
|
||||||
.put('/configs/jwt-customizer/access-token')
|
.put('/configs/jwt-customizer/access-token')
|
||||||
.send(mockJwtCustomizerConfigForAccessToken.value);
|
.send(mockJwtCustomizerConfigForAccessToken.value);
|
||||||
expect(logtoConfigLibraries.upsertJwtCustomizer).toHaveBeenCalledWith(
|
expect(mockLogtoConfigsLibrary.upsertJwtCustomizer).toHaveBeenCalledWith(
|
||||||
LogtoJwtTokenKey.AccessToken,
|
LogtoJwtTokenKey.AccessToken,
|
||||||
mockJwtCustomizerConfigForAccessToken.value
|
mockJwtCustomizerConfigForAccessToken.value
|
||||||
);
|
);
|
||||||
|
@ -86,16 +92,22 @@ describe('configs JWT customizer routes', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('PATCH /configs/jwt-customizer/:tokenType should update a record successfully', async () => {
|
it('PATCH /configs/jwt-customizer/:tokenType should update a record successfully', async () => {
|
||||||
logtoConfigLibraries.updateJwtCustomizer.mockResolvedValueOnce(
|
mockLogtoConfigsLibrary.updateJwtCustomizer.mockResolvedValueOnce(
|
||||||
mockJwtCustomizerConfigForAccessToken.value
|
mockJwtCustomizerConfigForAccessToken.value
|
||||||
);
|
);
|
||||||
const response = await routeRequester
|
const response = await routeRequester
|
||||||
.patch('/configs/jwt-customizer/access-token')
|
.patch('/configs/jwt-customizer/access-token')
|
||||||
.send(mockJwtCustomizerConfigForAccessToken.value);
|
.send(mockJwtCustomizerConfigForAccessToken.value);
|
||||||
|
|
||||||
expect(logtoConfigLibraries.deployJwtCustomizerScript).toHaveBeenCalled();
|
expect(mockLogtoConfigsLibrary.deployJwtCustomizerScript).toHaveBeenCalledWith(
|
||||||
|
tenantContext.cloudConnection,
|
||||||
|
{
|
||||||
|
key: LogtoJwtTokenKey.AccessToken,
|
||||||
|
value: mockJwtCustomizerConfigForAccessToken.value,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
expect(logtoConfigLibraries.updateJwtCustomizer).toHaveBeenCalledWith(
|
expect(mockLogtoConfigsLibrary.updateJwtCustomizer).toHaveBeenCalledWith(
|
||||||
LogtoJwtTokenKey.AccessToken,
|
LogtoJwtTokenKey.AccessToken,
|
||||||
mockJwtCustomizerConfigForAccessToken.value
|
mockJwtCustomizerConfigForAccessToken.value
|
||||||
);
|
);
|
||||||
|
@ -104,7 +116,7 @@ describe('configs JWT customizer routes', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GET /configs/jwt-customizer should return all records', async () => {
|
it('GET /configs/jwt-customizer should return all records', async () => {
|
||||||
logtoConfigLibraries.getJwtCustomizers.mockResolvedValueOnce({
|
mockLogtoConfigsLibrary.getJwtCustomizers.mockResolvedValueOnce({
|
||||||
[LogtoJwtTokenKey.AccessToken]: mockJwtCustomizerConfigForAccessToken.value,
|
[LogtoJwtTokenKey.AccessToken]: mockJwtCustomizerConfigForAccessToken.value,
|
||||||
[LogtoJwtTokenKey.ClientCredentials]: mockJwtCustomizerConfigForClientCredentials.value,
|
[LogtoJwtTokenKey.ClientCredentials]: mockJwtCustomizerConfigForClientCredentials.value,
|
||||||
});
|
});
|
||||||
|
@ -117,7 +129,7 @@ describe('configs JWT customizer routes', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GET /configs/jwt-customizer/:tokenType should return the record', async () => {
|
it('GET /configs/jwt-customizer/:tokenType should return the record', async () => {
|
||||||
logtoConfigLibraries.getJwtCustomizer.mockResolvedValueOnce(
|
mockLogtoConfigsLibrary.getJwtCustomizer.mockResolvedValueOnce(
|
||||||
mockJwtCustomizerConfigForAccessToken.value
|
mockJwtCustomizerConfigForAccessToken.value
|
||||||
);
|
);
|
||||||
const response = await routeRequester.get('/configs/jwt-customizer/access-token');
|
const response = await routeRequester.get('/configs/jwt-customizer/access-token');
|
||||||
|
@ -127,7 +139,7 @@ describe('configs JWT customizer routes', () => {
|
||||||
|
|
||||||
it('DELETE /configs/jwt-customizer/:tokenType should delete the record', async () => {
|
it('DELETE /configs/jwt-customizer/:tokenType should delete the record', async () => {
|
||||||
const response = await routeRequester.delete('/configs/jwt-customizer/client-credentials');
|
const response = await routeRequester.delete('/configs/jwt-customizer/client-credentials');
|
||||||
expect(logtoConfigLibraries.undeployJwtCustomizerScript).toHaveBeenCalledWith(
|
expect(mockLogtoConfigsLibrary.undeployJwtCustomizerScript).toHaveBeenCalledWith(
|
||||||
tenantContext.cloudConnection,
|
tenantContext.cloudConnection,
|
||||||
LogtoJwtTokenKey.ClientCredentials
|
LogtoJwtTokenKey.ClientCredentials
|
||||||
);
|
);
|
||||||
|
@ -136,4 +148,35 @@ describe('configs JWT customizer routes', () => {
|
||||||
);
|
);
|
||||||
expect(response.status).toEqual(204);
|
expect(response.status).toEqual(204);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('POST /configs/jwt-customizer/test should return 200', async () => {
|
||||||
|
const cloudConnectionResponse = { success: true };
|
||||||
|
jest.spyOn(tenantContext.cloudConnection, 'getClient').mockResolvedValue(mockCloudClient);
|
||||||
|
jest.spyOn(mockCloudClient, 'post').mockResolvedValue(cloudConnectionResponse);
|
||||||
|
|
||||||
|
const payload: JwtCustomizerTestRequestBody = {
|
||||||
|
tokenType: LogtoJwtTokenKeyType.AccessToken,
|
||||||
|
token: {},
|
||||||
|
script: mockJwtCustomizerConfigForAccessToken.value.script,
|
||||||
|
environmentVariables: mockJwtCustomizerConfigForAccessToken.value.environmentVariables,
|
||||||
|
context: mockJwtCustomizerConfigForAccessToken.value.contextSample,
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await routeRequester.post('/configs/jwt-customizer/test').send(payload);
|
||||||
|
|
||||||
|
expect(mockLogtoConfigsLibrary.deployJwtCustomizerScript).toHaveBeenCalledWith(
|
||||||
|
tenantContext.cloudConnection,
|
||||||
|
{
|
||||||
|
key: LogtoJwtTokenKey.AccessToken,
|
||||||
|
value: payload,
|
||||||
|
isTest: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(mockCloudClient.post).toHaveBeenCalledWith('/api/services/custom-jwt', {
|
||||||
|
body: payload,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -200,7 +200,7 @@ export default function logtoConfigJwtCustomizerRoutes<T extends AuthedRouter>(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!EnvSet.values.isCloud) {
|
if (!EnvSet.values.isCloud && !EnvSet.values.isUnitTest) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,6 +219,16 @@ export default function logtoConfigJwtCustomizerRoutes<T extends AuthedRouter>(
|
||||||
async (ctx, next) => {
|
async (ctx, next) => {
|
||||||
const { body } = ctx.guard;
|
const { body } = ctx.guard;
|
||||||
|
|
||||||
|
// Deploy the test script
|
||||||
|
await deployJwtCustomizerScript(cloudConnection, {
|
||||||
|
key:
|
||||||
|
body.tokenType === LogtoJwtTokenKeyType.AccessToken
|
||||||
|
? LogtoJwtTokenKey.AccessToken
|
||||||
|
: LogtoJwtTokenKey.ClientCredentials,
|
||||||
|
value: body,
|
||||||
|
isTest: true,
|
||||||
|
});
|
||||||
|
|
||||||
const client = await cloudConnection.getClient();
|
const client = await cloudConnection.getClient();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
import type router from '@logto/cloud/routes';
|
||||||
|
import Client from '@withtyped/client';
|
||||||
|
|
||||||
import { type LogtoConfigLibrary } from '#src/libraries/logto-config.js';
|
import { type LogtoConfigLibrary } from '#src/libraries/logto-config.js';
|
||||||
|
|
||||||
const { jest } = import.meta;
|
const { jest } = import.meta;
|
||||||
|
|
||||||
export const mockLogtoConfigsLibrary: LogtoConfigLibrary = {
|
export const mockLogtoConfigsLibrary: jest.Mocked<LogtoConfigLibrary> = {
|
||||||
getCloudConnectionData: jest.fn(),
|
getCloudConnectionData: jest.fn(),
|
||||||
getOidcConfigs: jest.fn(),
|
getOidcConfigs: jest.fn(),
|
||||||
upsertJwtCustomizer: jest.fn(),
|
upsertJwtCustomizer: jest.fn(),
|
||||||
|
@ -12,3 +15,5 @@ export const mockLogtoConfigsLibrary: LogtoConfigLibrary = {
|
||||||
deployJwtCustomizerScript: jest.fn(),
|
deployJwtCustomizerScript: jest.fn(),
|
||||||
undeployJwtCustomizerScript: jest.fn(),
|
undeployJwtCustomizerScript: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const mockCloudClient = new Client<typeof router>({ baseUrl: 'http://localhost:3001' });
|
||||||
|
|
|
@ -7,8 +7,7 @@ import type { CloudConnectionLibrary } from '#src/libraries/cloud-connection.js'
|
||||||
import { createCloudConnectionLibrary } from '#src/libraries/cloud-connection.js';
|
import { createCloudConnectionLibrary } from '#src/libraries/cloud-connection.js';
|
||||||
import type { ConnectorLibrary } from '#src/libraries/connector.js';
|
import type { ConnectorLibrary } from '#src/libraries/connector.js';
|
||||||
import { createConnectorLibrary } from '#src/libraries/connector.js';
|
import { createConnectorLibrary } from '#src/libraries/connector.js';
|
||||||
import { createLogtoConfigLibrary } from '#src/libraries/logto-config.js';
|
import { createLogtoConfigLibrary, type LogtoConfigLibrary } from '#src/libraries/logto-config.js';
|
||||||
import { type LogtoConfigLibrary } from '#src/libraries/logto-config.js';
|
|
||||||
import Libraries from '#src/tenants/Libraries.js';
|
import Libraries from '#src/tenants/Libraries.js';
|
||||||
import Queries from '#src/tenants/Queries.js';
|
import Queries from '#src/tenants/Queries.js';
|
||||||
import type TenantContext from '#src/tenants/TenantContext.js';
|
import type TenantContext from '#src/tenants/TenantContext.js';
|
||||||
|
@ -78,6 +77,7 @@ export class MockTenant implements TenantContext {
|
||||||
logtoConfigsOverride?: Partial<LogtoConfigLibrary>
|
logtoConfigsOverride?: Partial<LogtoConfigLibrary>
|
||||||
) {
|
) {
|
||||||
this.queries = new MockQueries(queriesOverride);
|
this.queries = new MockQueries(queriesOverride);
|
||||||
|
|
||||||
this.logtoConfigs = { ...createLogtoConfigLibrary(this.queries), ...logtoConfigsOverride };
|
this.logtoConfigs = { ...createLogtoConfigLibrary(this.queries), ...logtoConfigsOverride };
|
||||||
this.cloudConnection = createCloudConnectionLibrary(this.logtoConfigs);
|
this.cloudConnection = createCloudConnectionLibrary(this.logtoConfigs);
|
||||||
this.connectors = {
|
this.connectors = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue