mirror of
https://github.com/dadosfera/maestro.git
synced 2026-11-01 16:19:07 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f78c5a00dd |
@@ -0,0 +1,57 @@
|
|||||||
|
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||||
|
import { Metadata } from '@grpc/grpc-js';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
|
import { AuthClientService } from './auth.service';
|
||||||
|
|
||||||
|
describe('AuthClientService.resetUsers', () => {
|
||||||
|
const logger = {
|
||||||
|
info: jest.fn(),
|
||||||
|
debug: jest.fn(),
|
||||||
|
error: jest.fn(),
|
||||||
|
};
|
||||||
|
const resetUser = jest.fn();
|
||||||
|
let service: AuthClientService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
service = new AuthClientService({ logger } as any, {} as any);
|
||||||
|
(service as any).authService = { ResetUser: resetUser };
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the DUC response when every requested user was reset', async () => {
|
||||||
|
const response = {
|
||||||
|
message: 'Users reset successfully',
|
||||||
|
successfulUsers: ['user-1'],
|
||||||
|
failedUsers: [],
|
||||||
|
};
|
||||||
|
resetUser.mockReturnValue(of(response));
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
service.resetUsers(['user-1'], new Metadata()),
|
||||||
|
).resolves.toEqual(response);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns a non-2xx error instead of masking failed resets', async () => {
|
||||||
|
const response = {
|
||||||
|
message: 'Some users failed',
|
||||||
|
successfulUsers: ['user-1'],
|
||||||
|
failedUsers: ['user-2'],
|
||||||
|
};
|
||||||
|
resetUser.mockReturnValue(of(response));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.resetUsers(['user-1', 'user-2'], new Metadata());
|
||||||
|
fail('Expected resetUsers to reject');
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(HttpException);
|
||||||
|
expect((error as HttpException).getStatus()).toBe(HttpStatus.BAD_GATEWAY);
|
||||||
|
expect((error as HttpException).getResponse()).toEqual({
|
||||||
|
statusCode: HttpStatus.BAD_GATEWAY,
|
||||||
|
message: 'Failed to reset MFA for one or more users.',
|
||||||
|
successfulUsers: ['user-1'],
|
||||||
|
failedUsers: ['user-2'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -295,6 +295,22 @@ export class AuthClientService implements OnModuleInit {
|
|||||||
this.authService.ResetUser({ users }, metadata),
|
this.authService.ResetUser({ users }, metadata),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (response.failedUsers?.length > 0) {
|
||||||
|
this.logger.error('resetUsers - Partial or total failure', {
|
||||||
|
successfulUsers: response.successfulUsers,
|
||||||
|
failedUsers: response.failedUsers,
|
||||||
|
});
|
||||||
|
throw new HttpException(
|
||||||
|
{
|
||||||
|
statusCode: HttpStatus.BAD_GATEWAY,
|
||||||
|
message: 'Failed to reset MFA for one or more users.',
|
||||||
|
successfulUsers: response.successfulUsers,
|
||||||
|
failedUsers: response.failedUsers,
|
||||||
|
},
|
||||||
|
HttpStatus.BAD_GATEWAY,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.info('resetUsers - Success', { response });
|
this.logger.info('resetUsers - Success', { response });
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ describe('ConnectionTestService catalog cache', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('maps cached columns and derives references from the engine allowlist', async () => {
|
it('maps cached columns to the existing table metadata contract', async () => {
|
||||||
connectionsApiService.proxy.mockResolvedValue({
|
connectionsApiService.proxy.mockResolvedValue({
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
@@ -91,16 +91,6 @@ describe('ConnectionTestService catalog cache', () => {
|
|||||||
data_type: 'bigint',
|
data_type: 'bigint',
|
||||||
is_primary_key: true,
|
is_primary_key: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
column_name: 'name',
|
|
||||||
data_type: 'varchar',
|
|
||||||
is_primary_key: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
platformApiService.proxy.mockResolvedValue({
|
|
||||||
allowed_datatypes: [
|
|
||||||
{ engine: 'postgresql', allowed_datatypes: ['bigint', 'timestamp'] },
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -120,10 +110,13 @@ describe('ConnectionTestService catalog cache', () => {
|
|||||||
{
|
{
|
||||||
table_name: 'customers',
|
table_name: 'customers',
|
||||||
columns: [
|
columns: [
|
||||||
{ name: 'id', type: 'bigint', is_primary_key: true },
|
{
|
||||||
{ name: 'name', type: 'varchar', is_primary_key: false },
|
name: 'id',
|
||||||
|
type: 'bigint',
|
||||||
|
is_primary_key: true,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
references: [{ name: 'id', type: 'bigint', is_primary_key: true }],
|
references: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@@ -132,39 +125,6 @@ describe('ConnectionTestService catalog cache', () => {
|
|||||||
'/connection_catalog/config-id/schemas/public/tables/customers/columns',
|
'/connection_catalog/config-id/schemas/public/tables/customers/columns',
|
||||||
user,
|
user,
|
||||||
);
|
);
|
||||||
expect(platformApiService.proxy).toHaveBeenCalledWith(
|
|
||||||
'GET',
|
|
||||||
'/jobs/jdbc/configs/allowed_datatypes',
|
|
||||||
user,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns empty references when the allowlist call fails', async () => {
|
|
||||||
connectionsApiService.proxy.mockResolvedValue({
|
|
||||||
columns: [{ column_name: 'id', data_type: 'bigint', is_primary_key: true }],
|
|
||||||
});
|
|
||||||
platformApiService.proxy.mockRejectedValue(new Error('platform down'));
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
service.getTableMetadata(
|
|
||||||
{
|
|
||||||
connection_id: 'config-id',
|
|
||||||
plugin: 'postgresql',
|
|
||||||
schema: 'public',
|
|
||||||
table_list: ['customers'],
|
|
||||||
},
|
|
||||||
user,
|
|
||||||
),
|
|
||||||
).resolves.toEqual({
|
|
||||||
operation_result: true,
|
|
||||||
tables_metadata: [
|
|
||||||
{
|
|
||||||
table_name: 'customers',
|
|
||||||
columns: [{ name: 'id', type: 'bigint', is_primary_key: true }],
|
|
||||||
references: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('submits a catalog refresh without holding the request open', async () => {
|
it('submits a catalog refresh without holding the request open', async () => {
|
||||||
|
|||||||
@@ -213,20 +213,6 @@ export class ConnectionTestService {
|
|||||||
body: GetTableMetadataReq,
|
body: GetTableMetadataReq,
|
||||||
user: RequestUser,
|
user: RequestUser,
|
||||||
): Promise<GetTableMetadataRes> {
|
): Promise<GetTableMetadataRes> {
|
||||||
// Columns eligible as the incremental reference field are the ones whose
|
|
||||||
// data type is allowed for this engine (e.g. int/date/timestamp). The
|
|
||||||
// allowlist is owned by the platform API, keyed by engine === plugin.
|
|
||||||
const allowedByEngine = await this.platformApiService
|
|
||||||
.proxy('GET', '/jobs/jdbc/configs/allowed_datatypes', user)
|
|
||||||
.catch(() => null);
|
|
||||||
const allowedDataTypes: string[] =
|
|
||||||
allowedByEngine?.allowed_datatypes?.find(
|
|
||||||
(datatypes) => datatypes.engine === body.plugin,
|
|
||||||
)?.allowed_datatypes ?? [];
|
|
||||||
const allowedSet = new Set(
|
|
||||||
allowedDataTypes.map((type) => type.toLowerCase()),
|
|
||||||
);
|
|
||||||
|
|
||||||
const tables_metadata = await Promise.all(
|
const tables_metadata = await Promise.all(
|
||||||
body.table_list.map(async (table_name) => {
|
body.table_list.map(async (table_name) => {
|
||||||
const result = await this.connectionsApiService.proxy(
|
const result = await this.connectionsApiService.proxy(
|
||||||
@@ -236,18 +222,14 @@ export class ConnectionTestService {
|
|||||||
`/tables/${encodeURIComponent(table_name)}/columns`,
|
`/tables/${encodeURIComponent(table_name)}/columns`,
|
||||||
user,
|
user,
|
||||||
);
|
);
|
||||||
const columns = result.columns.map((column) => ({
|
|
||||||
name: column.column_name,
|
|
||||||
type: column.data_type,
|
|
||||||
is_primary_key: column.is_primary_key,
|
|
||||||
}));
|
|
||||||
const references = columns.filter((column) =>
|
|
||||||
allowedSet.has(String(column.type).toLowerCase()),
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
table_name,
|
table_name,
|
||||||
columns,
|
columns: result.columns.map((column) => ({
|
||||||
references,
|
name: column.column_name,
|
||||||
|
type: column.data_type,
|
||||||
|
is_primary_key: column.is_primary_key,
|
||||||
|
})),
|
||||||
|
references: [],
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user