Skip to content
Snippets Groups Projects
Verified Commit ae969339 authored by Konstantin Tsabolov's avatar Konstantin Tsabolov
Browse files

feat: refactor connection manager

parent 32de4453
No related branches found
No related tags found
1 merge request!21Refactor connection manager
Showing
with 498 additions and 1116 deletions
......@@ -12,12 +12,7 @@
"build": "nest build",
"prebuild:production": "pnpm clean",
"build:production": "pnpm prisma:generate && nest build -p tsconfig.production.json",
"prisma:dbpush": "prisma db push --schema=./src/prisma/schema.prisma",
"prisma:generate": "prisma generate --schema=./src/prisma/schema.prisma",
"prisma:migrate": "prisma migrate deploy --schema=./src/prisma/schema.prisma",
"prisma:studio": "prisma studio",
"start": "nest start",
"start:dev": "nest start --watch --preserveWatchOutput",
"start": "nest start --watch --preserveWatchOutput",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
......@@ -25,53 +20,35 @@
"test:e2e": "jest --config ./test/jest.config.js"
},
"dependencies": {
"@elastic/ecs-winston-format": "^1.5.0",
"@nestjs/axios": "^3.0.1",
"@nestjs/common": "^10.2.8",
"@nestjs/common": "^10.3.0",
"@nestjs/config": "^3.1.1",
"@nestjs/core": "^10.2.8",
"@nestjs/mapped-types": "^2.0.4",
"@nestjs/microservices": "^10.2.8",
"@nestjs/platform-express": "^10.2.8",
"@nestjs/core": "^10.3.0",
"@nestjs/microservices": "^10.3.0",
"@nestjs/platform-express": "^10.3.0",
"@nestjs/schedule": "^4.0.0",
"@nestjs/swagger": "^7.1.16",
"@nestjs/terminus": "^10.1.1",
"@prisma/client": "^5.6.0",
"@nestjs/swagger": "^7.1.17",
"@ocm/shared": "workspace:*",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"express": "^4.17.3",
"joi": "^17.11.0",
"jsonwebtoken": "^9.0.2",
"jwks-rsa": "^3.1.0",
"moment": "^2.29.4",
"nats": "^2.18.0",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",
"winston": "^3.11.0",
"winston-elasticsearch": "^0.17.4"
"rxjs": "^7.8.1"
},
"devDependencies": {
"@jest/globals": "^29.7.0",
"@nestjs/cli": "^10.2.1",
"@nestjs/schematics": "^10.0.3",
"@nestjs/testing": "^10.2.8",
"@swc/cli": "^0.1.62",
"@swc/core": "^1.3.96",
"@nestjs/testing": "^10.3.0",
"@swc/cli": "^0.1.63",
"@swc/core": "^1.3.101",
"@swc/jest": "^0.2.29",
"@types/express": "^4.17.21",
"@types/jest": "27.0.2",
"@types/jsonwebtoken": "^9.0.5",
"@types/node": "^20.9.0",
"@types/simple-oauth2": "^5.0.7",
"@types/supertest": "^2.0.16",
"dotenv-cli": "^7.3.0",
"@types/jest": "29.5.11",
"@types/node": "^20.10.5",
"jest": "^29.7.0",
"node-mocks-http": "^1.13.0",
"prisma": "^5.6.0",
"rimraf": "^5.0.5",
"source-map-support": "^0.5.21",
"supertest": "^6.3.3",
"swagger-ui-express": "^5.0.0",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
"typescript": "^5.3.3"
}
}
import type { INestApplication } from '@nestjs/common';
import type { TestingModule } from '@nestjs/testing';
import { Test } from '@nestjs/testing';
import AppModule from './app.module.js';
describe('App Module', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('should work', () => {
expect(true).toBe(true);
});
afterAll(async () => {
await app.close();
});
});
import type { MiddlewareConsumer, NestModule } from '@nestjs/common';
import { Module, RequestMethod } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { APP_FILTER } from '@nestjs/core';
import { ScheduleModule } from '@nestjs/schedule';
import { TerminusModule } from '@nestjs/terminus';
import ExceptionHandler from './common/exception.handler.js';
import config from './config/config.js';
import validationSchema from './config/validation.js';
import ConnectionsModule from './connections/module.js';
import SchedulerService from './connections/scheduler/scheduler.service.js';
import HealthController from './health/health.controller.js';
import { AuthMiddleware } from './middleware/auth.middleware.js';
import PrismaModule from './prisma/prisma.module.js';
@Module({
imports: [
ScheduleModule.forRoot(),
TerminusModule,
ConfigModule.forRoot({
isGlobal: true,
load: [config],
validationSchema,
}),
PrismaModule,
ConnectionsModule,
],
controllers: [HealthController],
providers: [
{
provide: APP_FILTER,
useClass: ExceptionHandler,
},
SchedulerService,
],
})
export default class AppModule implements NestModule {
// eslint-disable-next-line class-methods-use-this
public configure(consumer: MiddlewareConsumer) {
// eslint-disable-line
consumer
.apply(AuthMiddleware)
.exclude({
path: 'v1/health',
method: RequestMethod.GET,
})
.forRoutes('*');
}
}
import type { ConfigType } from '@nestjs/config';
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { RouterModule } from '@nestjs/core';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { HealthModule } from '@ocm/shared';
import { NATS_CLIENT } from './common/constants.js';
import { httpConfig } from './config/http.config.js';
import { natsConfig } from './config/nats.config.js';
import { ssiConfig } from './config/ssi.config.js';
import { validationSchema } from './config/validation.js';
import { ConnectionsModule } from './connections/connections.module.js';
import { InvitationsModule } from './invitations/invitations.module.js';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
load: [httpConfig, natsConfig, ssiConfig],
cache: true,
expandVariables: true,
validationSchema,
validationOptions: {
allowUnknown: true,
abortEarly: true,
},
}),
ClientsModule.registerAsync({
isGlobal: true,
clients: [
{
name: NATS_CLIENT,
inject: [natsConfig.KEY],
useFactory: (config: ConfigType<typeof natsConfig>) => ({
transport: Transport.NATS,
options: {
url: config.url as string,
},
}),
},
],
}),
HealthModule.registerAsync({
inject: [natsConfig.KEY],
useFactory: (config: ConfigType<typeof natsConfig>) => {
const options: Parameters<typeof HealthModule.register>[0] = {};
if (config.monitoringUrl) {
options.nats = {
monitoringUrl: config.monitoringUrl as string,
};
}
return options;
},
}),
ConnectionsModule,
InvitationsModule,
RouterModule.register([
{ module: HealthModule, path: '/health' },
{ module: ConnectionsModule, path: '/connections' },
{ module: InvitationsModule, path: '/invitations' },
]),
],
})
export class Application {}
export default class ConfigClient {
/**
*
* If there is no Limit to check expire till date return false
* @returns Number to calculate end date
*/
public static checkExpireTill(): Date | false {
const days = 2;
const tillDate = new Date();
tillDate.setDate(tillDate.getDate() - days);
return tillDate;
}
public static getConnectionExpire(): Date | false {
const min = 30;
const connectionExpire = min * 60 * 1000;
const compareDateTime = new Date(new Date().getTime() - connectionExpire);
return compareDateTime;
}
}
import type ResponseType from '../common/response.js';
import type ConnectionSubscriptionEndpointDto from '../connections/entities/connectionSubscribeEndPoint.entity.js';
import { Inject, Injectable } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { lastValueFrom } from 'rxjs';
import {
Attestation,
NATSServices,
Principal,
ProofManager,
} from '../common/constants.js';
import logger from '../utils/logger.js';
@Injectable()
export default class NatsClientService {
public constructor(
@Inject(NATSServices.SERVICE_NAME) private client: ClientProxy,
) {}
public sendConnectionStatusPrincipalManager(
status: string,
connectionId: string,
theirLabel: string,
participantDID: string,
theirDid: string,
) {
const pattern = {
endpoint: `${Principal.NATS_ENDPOINT}/${Principal.CONNECTION_COMPLETE_STATUS}`,
};
const payload = {
status,
connectionId,
theirLabel,
participantDID,
theirDid,
};
logger.info(`before nats call to principal manager ${payload}`);
return lastValueFrom(this.client.send<ResponseType>(pattern, payload));
}
public getIssueCredentials(connectionId: string) {
const pattern = {
endpoint: `${Attestation.NATS_ENDPOINT}/${Attestation.GET_ISSUE_CREDENTIALS}`,
};
const payload = {
connectionId,
};
return lastValueFrom(this.client.send<ResponseType>(pattern, payload));
}
public sendMembershipProofRequestToProofManager(connectionId: string) {
const pattern = {
endpoint: `${ProofManager.NATS_ENDPOINT}/${ProofManager.SEND_MEMBERSHIP_PROOF_REQUEST}`,
};
const payload = {
connectionId,
};
return lastValueFrom(this.client.send<ResponseType>(pattern, payload));
}
public getPresentProofs(connectionId: string) {
const pattern = {
endpoint: `${ProofManager.NATS_ENDPOINT}/${ProofManager.GET_PRESENT_PROOFS}`,
};
const payload = {
connectionId,
};
return lastValueFrom(this.client.send<ResponseType>(pattern, payload));
}
public publishConnection(data: ConnectionSubscriptionEndpointDto) {
this.client.emit(
`${NATSServices.SERVICE_NAME}/${NATSServices.CONNECTION_SUBSCRIBER_ENDPOINT}`,
data,
);
}
}
import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';
import { lastValueFrom, map } from 'rxjs';
@Injectable()
export default class RestClientService {
public constructor(private readonly httpService: HttpService) {}
public async post(url: string, payload: object) {
return lastValueFrom(
this.httpService
.post(url, payload)
.pipe(map((response) => response.data)),
);
}
}
export enum NATSServices {
SERVICE_NAME = 'CONNECTION_MANAGER_SERVICE',
CONNECTION_SUBSCRIBER_ENDPOINT = 'ConnectionSubscriberEndpoint',
}
export enum LoggerConfig {
FILE_PATH = 'logs/log.json',
LOG_DIR = './logs',
}
export enum Abstraction {
NATS_ENDPOINT = 'SSI_ABSTRACTION_SERVICE',
CONNECTION_STATE_CHANGED = 'ConnectionStateChanged',
}
export enum Principal {
NATS_ENDPOINT = 'PRINCIPAL_MANAGER_SERVICE',
CONNECTION_COMPLETE_STATUS = 'connectionCompleteStatus',
}
export enum Attestation {
NATS_ENDPOINT = 'ATTESTATION_MANAGER_SERVICE',
GET_ISSUE_CREDENTIALS = 'getIssueCredentials',
}
export enum ProofManager {
NATS_ENDPOINT = 'PROOF_MANAGER_SERVICE',
GET_PRESENT_PROOFS = 'getPresentProofs',
SEND_MEMBERSHIP_PROOF_REQUEST = 'sendMembershipProofRequest',
}
export const RECEIVED_CONNECTION_ALIAS = 'connection-received';
export const SERVICE_NAME = 'SCHEMA_MANAGER_SERVICE';
export const NATS_CLIENT = Symbol('NATS_CLIENT');
import moment from 'moment';
const getDate = () => moment().format('MM-DD-YYYY, h:mm:ss a');
export default getDate;
import type ResponseType from './response.js';
import type { ArgumentsHost, ExceptionFilter } from '@nestjs/common';
import { Catch, HttpException, HttpStatus } from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';
@Catch()
export default class ExceptionHandler implements ExceptionFilter {
public constructor(private readonly httpAdapterHost: HttpAdapterHost) {}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public catch(exception: any, host: ArgumentsHost): void {
// In certain situations `httpAdapter` might not be available in the
// constructor method, thus we should resolve it here.
const { httpAdapter } = this.httpAdapterHost;
const ctx = host.switchToHttp();
const response = ctx.getResponse();
let statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
let message =
exception.message.error || exception.message || 'Something went wrong!';
if (exception instanceof HttpException) {
const errorResponse: string | object = exception.getResponse();
statusCode = exception.getStatus();
message =
(typeof errorResponse === 'object' &&
Reflect.get(errorResponse, 'error')) ||
message;
}
const responseBody: ResponseType = {
statusCode,
message,
error: exception.message,
};
httpAdapter.reply(response, responseBody, statusCode);
}
}
export default interface ResponseType {
statusCode: number;
message: string;
data?: unknown;
error?: unknown;
}
import { fileURLToPath } from 'node:url';
const parentDirectory = fileURLToPath(new URL('..', import.meta.url));
const config = () => ({
PORT: Number(process.env.PORT),
APP_URL: process.env.CONNECTION_MANAGER_URL,
auth: {
useAuth: process.env.USE_AUTH || 'false',
clientId: process.env.OAUTH_CLIENT_ID,
clientSecret: process.env.OAUTH_CLIENT_SECRET,
tokenUrl: process.env.OAUTH_TOKEN_URL,
},
nats: {
url: process.env.NATS_URL,
},
database: {
type: 'postgres',
host: process.env.DB_HOST,
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
port: 5432,
synchronize: false,
logging: false,
entities: [`${parentDirectory}/../**/**.model{.ts,.js}`],
DATABASE_URL: process.env.DATABASE_URL,
},
agent: {
agentUrl: process.env.AGENT_URL,
},
ECSURL: process.env.ECSURL,
});
export default config;
import { registerAs } from '@nestjs/config';
export const httpConfig = registerAs('http', () => ({
host: process.env.HTTP_HOST,
port: Number(process.env.HTTP_PORT),
}));
import { registerAs } from '@nestjs/config';
export const natsConfig = registerAs('nats', () => ({
url: process.env.NATS_URL,
monitoringUrl: process.env.NATS_MONITORING_URL,
}));
import { registerAs } from '@nestjs/config';
export const ssiConfig = registerAs('ssi', () => ({
agentUrl: process.env.SSI_AGENT_URL,
}));
import Joi from 'joi';
const validationSchema = Joi.object({
DATABASE_URL: Joi.string().required(),
NATS_URL: Joi.string().required(),
PORT: Joi.number().required(),
CONNECTION_MANAGER_URL: Joi.string().required(),
USE_AUTH: Joi.string(),
AGENT_URL: Joi.string().required(),
OAUTH_CLIENT_ID: Joi.string(),
OAUTH_CLIENT_SECRET: Joi.string(),
OAUTH_TOKEN_URL: Joi.string(),
});
export const validationSchema = Joi.object({
HTTP_HOST: Joi.string().default('0.0.0.0'),
HTTP_PORT: Joi.number().default(3000),
NATS_URL: Joi.string().uri().default('nats://localhost:4222'),
NATS_MONITORING_URL: Joi.string().uri().default('http://localhost:8222'),
export default validationSchema;
SSI_AGENT_URL: Joi.string().default('http://localhost:3010'),
});
import {
Controller,
Get,
HttpStatus,
Param,
Post,
Query,
UseInterceptors,
UsePipes,
ValidationPipe,
} from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { MultitenancyParams, ResponseFormatInterceptor } from '@ocm/shared';
import { ConnectionsService } from './connections.service.js';
import { BlockParams } from './dto/block.dto.js';
import { GetByIdParams } from './dto/get-by-id.dto.js';
@Controller()
@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
@UseInterceptors(ResponseFormatInterceptor)
@ApiTags('Connections')
export class ConnectionsController {
public constructor(private readonly service: ConnectionsService) {}
@Get()
@ApiOperation({
summary: 'Fetch a list of connections',
description: 'This call provides a list of connections for a given tenant',
})
@ApiResponse({
status: HttpStatus.OK,
description: 'Connections fetched successfully',
content: {
'application/json': {
schema: {},
examples: {
'Connections fetched successfully': {
value: {
statusCode: 200,
message: 'Connections fetched successfully',
data: [],
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Tenant not found',
content: {
'application/json': {
schema: {},
examples: {
'Tenant not found': {
value: {
statusCode: 404,
message: 'Tenant not found',
data: null,
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.INTERNAL_SERVER_ERROR,
description: 'Internal server error',
content: {
'application/json': {
schema: {},
examples: {
'Internal server error': {
value: {
statusCode: 500,
message: 'Internal server error',
data: null,
},
},
},
},
},
})
public getAll(
@Query() { tenantId }: MultitenancyParams,
): ReturnType<ConnectionsService['getAllConnections']> {
return this.service.getAllConnections(tenantId);
}
@Get(':connectionId')
@ApiOperation({
summary: 'Fetch a connection by ID',
description:
'This call provides a connection for a given tenant and connection ID',
})
@ApiResponse({
status: HttpStatus.OK,
description: 'Connection fetched successfully',
content: {
'application/json': {
schema: {},
examples: {
'Connection fetched successfully': {
value: {
statusCode: 200,
message: 'Connection fetched successfully',
data: {},
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Connection not found',
content: {
'application/json': {
schema: {},
examples: {
'Tenant not found': {
value: {
statusCode: 404,
message: 'Tenant not found',
data: null,
},
},
'Connection not found': {
value: {
statusCode: 404,
message: 'Connection not found',
data: null,
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.INTERNAL_SERVER_ERROR,
description: 'Internal server error',
content: {
'application/json': {
schema: {},
examples: {
'Internal server error': {
value: {
statusCode: 500,
message: 'Internal server error',
data: null,
},
},
},
},
},
})
public getById(
@Param() { connectionId }: GetByIdParams,
@Query() { tenantId }: MultitenancyParams,
): ReturnType<ConnectionsService['getConnectionById']> {
return this.service.getConnectionById(tenantId, connectionId);
}
@Post()
@ApiOperation({
summary: 'Create a connection',
description: 'This call creates a self connection for a given tenant',
})
@ApiResponse({
status: HttpStatus.CREATED,
description: 'Connection created successfully',
content: {
'application/json': {
schema: {},
examples: {
'Connection created successfully': {
value: {
statusCode: 201,
message: 'Connection created successfully',
data: {},
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Tenant not found',
content: {
'application/json': {
schema: {},
examples: {
'Tenant not found': {
value: {
statusCode: 404,
message: 'Tenant not found',
data: null,
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.INTERNAL_SERVER_ERROR,
description: 'Internal server error',
content: {
'application/json': {
schema: {},
examples: {
'Internal server error': {
value: {
statusCode: 500,
message: 'Internal server error',
data: null,
},
},
},
},
},
})
public createWithSelf(
@Query() { tenantId }: MultitenancyParams,
): ReturnType<ConnectionsService['createConnectionWithSelf']> {
return this.service.createConnectionWithSelf(tenantId);
}
@Post(':idOrDid/block')
@ApiOperation({
summary: 'Block a connection',
description:
'This call blocks a connection for a given tenant and connection ID',
})
@ApiResponse({
status: HttpStatus.OK,
description: 'Connection blocked successfully',
content: {
'application/json': {
schema: {},
examples: {
'Connection blocked successfully': {
value: {
statusCode: 200,
message: 'Connection blocked successfully',
data: {},
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Connection not found',
content: {
'application/json': {
schema: {},
examples: {
'Tenant not found': {
value: {
statusCode: 404,
message: 'Tenant not found',
data: null,
},
},
'Connection not found': {
value: {
statusCode: 404,
message: 'Connection not found',
data: null,
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.INTERNAL_SERVER_ERROR,
description: 'Internal server error',
content: {
'application/json': {
schema: {},
examples: {
'Internal server error': {
value: {
statusCode: 500,
message: 'Internal server error',
data: null,
},
},
},
},
},
})
public block(
@Param() { idOrDid }: BlockParams,
@Query() { tenantId }: MultitenancyParams,
): ReturnType<ConnectionsService['blockConnection']> {
return this.service.blockConnection(tenantId, idOrDid);
}
}
import { Module } from '@nestjs/common';
import { ConnectionsController } from './connections.controller.js';
import { ConnectionsService } from './connections.service.js';
@Module({
providers: [ConnectionsService],
controllers: [ConnectionsController],
})
export class ConnectionsModule {}
import type {
EventDidcommConnectionsBlockInput,
EventDidcommConnectionsGetAllInput,
EventDidcommConnectionsGetByIdInput,
} from '@ocm/shared';
import type { Observable } from 'rxjs';
import { Inject, Injectable } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import {
EventDidcommConnectionsBlock,
EventDidcommConnectionsCreateWithSelf,
EventDidcommConnectionsGetAll,
EventDidcommConnectionsGetById,
} from '@ocm/shared';
import { map } from 'rxjs';
import { NATS_CLIENT } from '../common/constants.js';
@Injectable()
export class ConnectionsService {
public constructor(
@Inject(NATS_CLIENT) private readonly natsClient: ClientProxy,
) {}
public getAllConnections(
tenantId: string,
): Observable<EventDidcommConnectionsGetAll['data']> {
return this.natsClient
.send<EventDidcommConnectionsGetAll, EventDidcommConnectionsGetAllInput>(
EventDidcommConnectionsGetAll.token,
{ tenantId },
)
.pipe(map((result) => result.data));
}
public getConnectionById(
tenantId: string,
id: string,
): Observable<EventDidcommConnectionsGetById['data']> {
return this.natsClient
.send<
EventDidcommConnectionsGetById,
EventDidcommConnectionsGetByIdInput
>(EventDidcommConnectionsGetById.token, { tenantId, id })
.pipe(map((result) => result.data));
}
public createConnectionWithSelf(
tenantId: string,
): Observable<EventDidcommConnectionsCreateWithSelf['data']> {
return this.natsClient
.send<EventDidcommConnectionsCreateWithSelf>(
EventDidcommConnectionsCreateWithSelf.token,
{ tenantId },
)
.pipe(map((result) => result.data));
}
public blockConnection(
tenantId: string,
idOrDid: string,
): Observable<EventDidcommConnectionsBlock['data']> {
return this.natsClient
.send<EventDidcommConnectionsBlock, EventDidcommConnectionsBlockInput>(
EventDidcommConnectionsBlock.token,
{ tenantId, idOrDid },
)
.pipe(map((result) => result.data));
}
}
/* eslint-disable @typescript-eslint/no-explicit-any */
import type ConnectionStateDto from '../entities/connectionStateDto.entity.js';
import type { TestingModule } from '@nestjs/testing';
import { HttpModule } from '@nestjs/axios';
import { HttpStatus } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { Test } from '@nestjs/testing';
import { createResponse } from 'node-mocks-http';
import NatsClientService from '../../client/nats.client.js';
import RestClientService from '../../client/rest.client.js';
import { NATSServices } from '../../common/constants.js';
import PrismaService from '../../prisma/prisma.service.js';
import ConnectionsService from '../services/service.js';
import ConnectionsController from './controller.js';
describe.skip('ConnectionsController', () => {
let connectionController: ConnectionsController;
let connectionService: ConnectionsService;
// const connection = new ConnectionDto();
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [
ConfigModule,
HttpModule,
ClientsModule.register([
{
name: NATSServices.SERVICE_NAME,
transport: Transport.NATS,
},
]),
],
controllers: [ConnectionsController],
providers: [
ConnectionsService,
PrismaService,
NatsClientService,
RestClientService,
],
exports: [PrismaService],
}).compile();
connectionService = module.get<ConnectionsService>(ConnectionsService);
connectionController = module.get<ConnectionsController>(
ConnectionsController,
);
});
it('should be defined', () => {
expect(connectionController).toBeDefined();
});
describe('Get all connections', () => {
it('should return an array of connection', async () => {
const param = {};
const serviceResult: any = [
1,
{
id: '1a7f0b09-b20e-4971-b9b1-7adde7256bbc',
connectionId: '7b821264-2ae3-4459-b45f-19fa975d91f7',
participantId: '7780cd24-af13-423e-b1ff-ae944ab6fd71',
status: 'trusted',
participantDid: 'SU1SHqQiDcc6gDvqH8wwYF',
theirDid: 'Ax9xMqE89F9LStfGnTpDzg',
theirLabel: 'sagar@getnada.com',
createdDate: '2022-04-18T11:03:58.099Z',
updatedDate: '2022-04-18T11:05:10.004Z',
isActive: true,
},
];
const result: any = {
count: 1,
records: {
id: '1a7f0b09-b20e-4971-b9b1-7adde7256bbc',
connectionId: '7b821264-2ae3-4459-b45f-19fa975d91f7',
participantId: '7780cd24-af13-423e-b1ff-ae944ab6fd71',
status: 'trusted',
participantDid: 'SU1SHqQiDcc6gDvqH8wwYF',
theirDid: 'Ax9xMqE89F9LStfGnTpDzg',
theirLabel: 'sagar@getnada.com',
createdDate: '2022-04-18T11:03:58.099Z',
updatedDate: '2022-04-18T11:05:10.004Z',
isActive: true,
},
};
const response = createResponse();
jest
.spyOn(connectionService, 'findConnections')
.mockResolvedValueOnce(serviceResult);
const res: any = await connectionController.getConnection(
param,
response,
);
const resData = res._getData();
expect(res.statusCode).toBe(HttpStatus.OK);
expect(JSON.parse(resData).data).toStrictEqual(result);
});
it('If Not provided required parameter response should be bad request', async () => {
const param = {};
const serviceResult: any = [
1,
{
id: '1a7f0b09-b20e-4971-b9b1-7adde7256bbc',
connectionId: '7b821264-2ae3-4459-b45f-19fa975d91f7',
participantId: '7780cd24-af13-423e-b1ff-ae944ab6fd71',
status: 'trusted',
participantDid: 'SU1SHqQiDcc6gDvqH8wwYF',
theirDid: 'Ax9xMqE89F9LStfGnTpDzg',
theirLabel: 'sagar@getnada.com',
createdDate: '2022-04-18T11:03:58.099Z',
updatedDate: '2022-04-18T11:05:10.004Z',
isActive: true,
},
];
const response = createResponse();
jest
.spyOn(connectionService, 'findConnections')
.mockResolvedValueOnce(serviceResult);
const res = await connectionController.getConnection(param, response);
const resData = res._getData();
expect(res.statusCode).toBe(HttpStatus.BAD_REQUEST);
expect(JSON.parse(resData).message).toStrictEqual(
'Participant ID/ connection ID / participant DID must be provided',
);
});
it('Get connection against connection id', async () => {
const param = {
connectionId: '7b821264-2ae3-4459-b45f-19fa975d91f7',
};
const serviceResult: any = {
id: '1a7f0b09-b20e-4971-b9b1-7adde7256bbc',
connectionId: '7b821264-2ae3-4459-b45f-19fa975d91f7',
status: 'trusted',
participantDid: 'SU1SHqQiDcc6gDvqH8wwYF',
theirDid: 'Ax9xMqE89F9LStfGnTpDzg',
theirLabel: 'sagar@getnada.com',
createdDate: '2022-04-18T11:03:58.099Z',
updatedDate: '2022-04-18T11:05:10.004Z',
isActive: true,
};
const result: any = {
statusCode: 200,
message: 'Connections fetch successfully',
data: {
records: {
id: '1a7f0b09-b20e-4971-b9b1-7adde7256bbc',
connectionId: '7b821264-2ae3-4459-b45f-19fa975d91f7',
participantId: '7780cd24-af13-423e-b1ff-ae944ab6fd71',
status: 'trusted',
participantDid: 'SU1SHqQiDcc6gDvqH8wwYF',
theirDid: 'Ax9xMqE89F9LStfGnTpDzg',
theirLabel: 'sagar@getnada.com',
createdDate: '2022-04-18T11:03:58.099Z',
updatedDate: '2022-04-18T11:05:10.004Z',
isActive: true,
},
},
};
const response = createResponse();
jest
.spyOn(connectionService, 'findConnections')
.mockResolvedValueOnce(serviceResult);
const res: any = await connectionController.getConnection(
param,
response,
);
// eslint-disable-next-line no-underscore-dangle
const resData = res._getData();
expect(res.statusCode).toBe(HttpStatus.OK);
expect(JSON.parse(resData)).toStrictEqual(result);
});
it('Not fount if data is not present against connection id', async () => {
const param = {
connectionId: '7b821264-2ae3-4459-b45f-19fa975d91f7',
};
const serviceResult: any = {
id: '1a7f0b09-b20e-4971-b9b1-7adde7256bbc',
connectionId: '7b821264-2ae3-4459-b45f-19fa975d91f7',
status: 'trusted',
participantDid: 'SU1SHqQiDcc6gDvqH8wwYF',
theirDid: 'Ax9xMqE89F9LStfGnTpDzg',
theirLabel: 'sagar@getnada.com',
createdDate: '2022-04-18T11:03:58.099Z',
updatedDate: '2022-04-18T11:05:10.004Z',
isActive: false,
};
const result: any = {
statusCode: HttpStatus.NOT_FOUND,
message: 'No Data found',
};
const response = createResponse();
jest
.spyOn(connectionService, 'findConnections')
.mockResolvedValueOnce(serviceResult);
const res: any = await connectionController.getConnection(
param,
response,
);
// eslint-disable-next-line no-underscore-dangle
const resData = res._getData();
expect(res.statusCode).toBe(HttpStatus.NOT_FOUND);
expect(JSON.parse(resData)).toStrictEqual(result);
});
it('should return an array of connection with status filter', async () => {
const param = {};
const serviceResult: any = [
1,
{
id: '1a7f0b09-b20e-4971-b9b1-7adde7256bbc',
connectionId: '7b821264-2ae3-4459-b45f-19fa975d91f7',
participantId: '7780cd24-af13-423e-b1ff-ae944ab6fd71',
status: 'trusted',
participantDid: 'SU1SHqQiDcc6gDvqH8wwYF',
theirDid: 'Ax9xMqE89F9LStfGnTpDzg',
theirLabel: 'sagar@getnada.com',
createdDate: '2022-04-18T11:03:58.099Z',
updatedDate: '2022-04-18T11:05:10.004Z',
isActive: true,
},
];
const result: any = {
count: 1,
records: {
id: '1a7f0b09-b20e-4971-b9b1-7adde7256bbc',
connectionId: '7b821264-2ae3-4459-b45f-19fa975d91f7',
participantId: '7780cd24-af13-423e-b1ff-ae944ab6fd71',
status: 'trusted',
participantDid: 'SU1SHqQiDcc6gDvqH8wwYF',
theirDid: 'Ax9xMqE89F9LStfGnTpDzg',
theirLabel: 'sagar@getnada.com',
createdDate: '2022-04-18T11:03:58.099Z',
updatedDate: '2022-04-18T11:05:10.004Z',
isActive: true,
},
};
const response = createResponse();
jest
.spyOn(connectionService, 'findConnections')
.mockResolvedValueOnce(serviceResult);
const res: any = await connectionController.getConnection(
param,
response,
);
// eslint-disable-next-line no-underscore-dangle
const resData = res._getData();
expect(res.statusCode).toBe(HttpStatus.OK);
expect(JSON.parse(resData).data).toStrictEqual(result);
});
});
describe('Connection webhook calls', () => {
it('Create connection webhook call', async () => {
const webHook: ConnectionStateDto = {
_tags: {},
metadata: {},
id: '7edc871d-9fa3-4f30-8763-59c80bf346f5',
createdAt: '2022-04-21T10:52:27.151Z',
did: 'DD8Aue5tuohjBaCLM9GMU7',
didDoc: {
'@context': 'https://w3id.org/did/v1',
publicKey: [
[
{
id: 'C1buxAXWiisjFpVVyUGM5D#1',
controller: 'C1buxAXWiisjFpVVyUGM5D',
type: 'Ed25519VerificationKey2018',
publicKeyBase58: '714U4GdQqyeqhCANgJmTrGqUPg4QTGuEhJcEGYAvEH1Y',
},
],
],
service: [
{
id: 'C1buxAXWiisjFpVVyUGM5D#IndyAgentService',
serviceEndpoint: 'http://localhost:4011',
type: 'IndyAgent',
priority: 0,
recipientKeys: ['714U4GdQqyeqhCANgJmTrGqUPg4QTGuEhJcEGYAvEH1Y'],
routingKeys: [],
},
],
authentication: [[Object]],
id: 'DD8Aue5tuohjBaCLM9GMU7',
},
theirDid: '',
theirLabel: '',
verkey: '7exBgFhenY8hqBwBF56D8sp6akLstqXxS1MUUCpDErvX',
state: 'invited',
role: 'inviter',
alias: 'member',
invitation: {
'@type': 'https://didcomm.org/connections/1.0/invitation',
'@id': '8578735f-eef8-4748-b791-ba2f8f7002e2',
label: 'State_University',
recipientKeys: ['7exBgFhenY8hqBwBF56D8sp6akLstqXxS1MUUCpDErvX'],
serviceEndpoint: 'http://localhost:4017',
routingKeys: [],
},
multiUseInvitation: false,
};
const serviceResult: any = {};
jest
.spyOn(connectionService, 'createConnections')
.mockResolvedValueOnce(serviceResult);
const res: any = await connectionController.createConnection({
body: webHook,
});
expect(res.statusCode).toBe(HttpStatus.CREATED);
// expect(JSON.parse(resData).data).toStrictEqual(result);
});
it('Update connection webhook call -> member flow', async () => {
const webHook: ConnectionStateDto = {
_tags: {},
metadata: {},
id: '72534911-9be0-4e3f-8539-2a8a09e4e409',
createdAt: '2022-04-21T10:52:27.151Z',
did: 'DD8Aue5tuohjBaCLM9GMU7',
didDoc: {
'@context': 'https://w3id.org/did/v1',
publicKey: [
[
{
id: 'C1buxAXWiisjFpVVyUGM5D#1',
controller: 'C1buxAXWiisjFpVVyUGM5D',
type: 'Ed25519VerificationKey2018',
publicKeyBase58: '714U4GdQqyeqhCANgJmTrGqUPg4QTGuEhJcEGYAvEH1Y',
},
],
],
service: [
{
id: 'C1buxAXWiisjFpVVyUGM5D#IndyAgentService',
serviceEndpoint: 'http://localhost:4011',
type: 'IndyAgent',
priority: 0,
recipientKeys: ['714U4GdQqyeqhCANgJmTrGqUPg4QTGuEhJcEGYAvEH1Y'],
routingKeys: [],
},
],
authentication: [[Object]],
id: 'DD8Aue5tuohjBaCLM9GMU7',
},
theirDid: '',
theirLabel: '',
verkey: '7exBgFhenY8hqBwBF56D8sp6akLstqXxS1MUUCpDErvX',
state: 'complete',
role: 'inviter',
alias: 'member',
invitation: {
'@type': 'https://didcomm.org/connections/1.0/invitation',
'@id': '8578735f-eef8-4748-b791-ba2f8f7002e2',
label: 'State_University',
recipientKeys: ['7exBgFhenY8hqBwBF56D8sp6akLstqXxS1MUUCpDErvX'],
serviceEndpoint: 'http://localhost:4017',
routingKeys: [],
},
multiUseInvitation: false,
};
const restConnection: any = {
id: '29701e41-60e8-4fca-8504-ea3bcefa6486',
connectionId: '72534911-9be0-4e3f-8539-2a8a09e4e409',
participantId: '662dc769-a4de-4c95-934c-f6dab8cf432c',
status: 'trusted',
participantDid: 'PyLDJRKzmKmJShyEtjC4AQ',
theirDid: 'UgR1Rrp6p3VJGwLFZnBdwB',
theirLabel: 'Attest12',
createdDate: '2022-04-15T11:30:04.660Z',
updatedDate: '2022-04-15T11:36:58.560Z',
isActive: true,
};
const serviceResult: any = {};
jest
.spyOn(connectionService, 'updateStatusByConnectionId')
.mockResolvedValueOnce(serviceResult);
jest
.spyOn(connectionService, 'getConnectionByID')
.mockResolvedValueOnce(restConnection);
const res: any = await connectionController.createConnection({
body: webHook,
});
expect(res.statusCode).toBe(HttpStatus.OK);
// expect(JSON.parse(resData).data).toStrictEqual(result);
});
it('Update connection webhook call -> subscriber flow', async () => {
const webHook: ConnectionStateDto = {
_tags: {},
metadata: {},
id: '72534911-9be0-4e3f-8539-2a8a09e4e409',
createdAt: '2022-04-21T10:52:27.151Z',
did: 'DD8Aue5tuohjBaCLM9GMU7',
didDoc: {
'@context': 'https://w3id.org/did/v1',
publicKey: [
[
{
id: 'C1buxAXWiisjFpVVyUGM5D#1',
controller: 'C1buxAXWiisjFpVVyUGM5D',
type: 'Ed25519VerificationKey2018',
publicKeyBase58: '714U4GdQqyeqhCANgJmTrGqUPg4QTGuEhJcEGYAvEH1Y',
},
],
],
service: [
{
id: 'C1buxAXWiisjFpVVyUGM5D#IndyAgentService',
serviceEndpoint: 'http://localhost:4011',
type: 'IndyAgent',
priority: 0,
recipientKeys: ['714U4GdQqyeqhCANgJmTrGqUPg4QTGuEhJcEGYAvEH1Y'],
routingKeys: [],
},
],
authentication: [[Object]],
id: 'DD8Aue5tuohjBaCLM9GMU7',
},
theirDid: '',
theirLabel: '',
verkey: '7exBgFhenY8hqBwBF56D8sp6akLstqXxS1MUUCpDErvX',
state: 'complete',
role: 'inviter',
alias: 'subscriber',
invitation: {
'@type': 'https://didcomm.org/connections/1.0/invitation',
'@id': '8578735f-eef8-4748-b791-ba2f8f7002e2',
label: 'State_University',
recipientKeys: ['7exBgFhenY8hqBwBF56D8sp6akLstqXxS1MUUCpDErvX'],
serviceEndpoint: 'http://localhost:4017',
routingKeys: [],
},
multiUseInvitation: false,
};
const restConnection: any = {
id: '29701e41-60e8-4fca-8504-ea3bcefa6486',
connectionId: '72534911-9be0-4e3f-8539-2a8a09e4e409',
participantId: '662dc769-a4de-4c95-934c-f6dab8cf432c',
status: 'trusted',
participantDid: 'PyLDJRKzmKmJShyEtjC4AQ',
theirDid: 'UgR1Rrp6p3VJGwLFZnBdwB',
theirLabel: 'Attest12',
createdDate: '2022-04-15T11:30:04.660Z',
updatedDate: '2022-04-15T11:36:58.560Z',
isActive: true,
};
const serviceResult: any = {};
jest
.spyOn(connectionService, 'updateStatusByConnectionId')
.mockResolvedValueOnce(serviceResult);
jest
.spyOn(connectionService, 'getConnectionByID')
.mockResolvedValueOnce(restConnection);
const res: any = await connectionController.createConnection({
body: webHook,
});
expect(res.statusCode).toBe(HttpStatus.OK);
// expect(JSON.parse(resData).data).toStrictEqual(result);
});
it('Connection webhook call with wrong role', async () => {
const webHook: ConnectionStateDto = {
_tags: {},
metadata: {},
id: '72534911-9be0-4e3f-8539-2a8a09e4e409',
createdAt: '2022-04-21T10:52:27.151Z',
did: 'DD8Aue5tuohjBaCLM9GMU7',
didDoc: {
'@context': 'https://w3id.org/did/v1',
publicKey: [
[
{
id: 'C1buxAXWiisjFpVVyUGM5D#1',
controller: 'C1buxAXWiisjFpVVyUGM5D',
type: 'Ed25519VerificationKey2018',
publicKeyBase58: '714U4GdQqyeqhCANgJmTrGqUPg4QTGuEhJcEGYAvEH1Y',
},
],
],
service: [
{
id: 'C1buxAXWiisjFpVVyUGM5D#IndyAgentService',
serviceEndpoint: 'http://localhost:4011',
type: 'IndyAgent',
priority: 0,
recipientKeys: ['714U4GdQqyeqhCANgJmTrGqUPg4QTGuEhJcEGYAvEH1Y'],
routingKeys: [],
},
],
authentication: [[Object]],
id: 'DD8Aue5tuohjBaCLM9GMU7',
},
theirDid: '',
theirLabel: '',
verkey: '7exBgFhenY8hqBwBF56D8sp6akLstqXxS1MUUCpDErvX',
state: 'complete',
role: 'invitee',
alias: 'subscriber',
invitation: {
'@type': 'https://didcomm.org/connections/1.0/invitation',
'@id': '8578735f-eef8-4748-b791-ba2f8f7002e2',
label: 'State_University',
recipientKeys: ['7exBgFhenY8hqBwBF56D8sp6akLstqXxS1MUUCpDErvX'],
serviceEndpoint: 'http://localhost:4017',
routingKeys: [],
},
multiUseInvitation: false,
};
const restConnection = {
id: '29701e41-60e8-4fca-8504-ea3bcefa6486',
connectionId: '72534911-9be0-4e3f-8539-2a8a09e4e409',
participantId: '662dc769-a4de-4c95-934c-f6dab8cf432c',
status: 'trusted',
participantDid: 'PyLDJRKzmKmJShyEtjC4AQ',
theirDid: 'UgR1Rrp6p3VJGwLFZnBdwB',
theirLabel: 'Attest12',
createdDate: '2022-04-15T11:30:04.660Z',
updatedDate: '2022-04-15T11:36:58.560Z',
isActive: true,
};
const serviceResult = {};
jest
.spyOn(connectionService, 'updateStatusByConnectionId')
.mockResolvedValueOnce(serviceResult);
jest
.spyOn(connectionService, 'getConnectionByID')
.mockResolvedValueOnce(restConnection);
const res = await connectionController.createConnection({
body: webHook,
});
expect(res.statusCode).toBe(HttpStatus.BAD_REQUEST);
// expect(JSON.parse(resData).data).toStrictEqual(result);
});
});
describe('Get invitation URL', () => {
it('Get Member invitation URL', async () => {
const body = {
autoAcceptConnection: true,
};
const query = {
participantId: '7780cd24-af13-423e-b1ff-ae944ab6fd71',
process: 'member',
};
const serviceResult: any = {
invitationUrl:
'http://localhost:4005?c_i=eyJAdHlwZSI6ImRpZDpzb3Y6QnpDYnNOWWhNcmpIaXFaRFRVQVNIZztzcGVjL2Nvbm5lY3Rpb25zLzEuMC9pbnZpdGF0aW9uIiwiQGlkIjoiYWMzYjE0NjktY2Y0Ni00M2ZjLWE4M2EtZGNmZjJjMDA1YjRlIiwibGFiZWwiOiJ0ZWNobmljYV9jb3JwIiwicmVjaXBpZW50S2V5cyI6WyI1bml1NWZmZmVnYkZlS2F3bU5OblRBTEpzaHB1cXpjRm5CUGpBOFFWU2dtWCJdLCJzZXJ2aWNlRW5kcG9pbnQiOiJodHRwOi8vMy4xMTEuNzcuMzg6NDAwNSIsInJvdXRpbmdLZXlzIjpbXX0',
invitation: {
'@type':
'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/invitation',
'@id': 'ac3b1469-cf46-43fc-a83a-dcff2c005b4e',
label: 'technica_corp',
recipientKeys: ['5niu5fffegbFeKawmNNnTALJshpuqzcFnBPjA8QVSgmX'],
serviceEndpoint: 'http://localhost:4005',
routingKeys: [],
},
connection: {
_tags: {},
metadata: {},
id: 'c1d73d9e-6988-4c84-9ebc-068c265d2fb6',
createdAt: '2022-04-21T10:52:18.161Z',
did: '9nYw7CSdHPqXf6ayfA7Wo2',
didDoc: {
'@context': 'https://w3id.org/did/v1',
publicKey: [
{
id: '9nYw7CSdHPqXf6ayfA7Wo2#1',
controller: '9nYw7CSdHPqXf6ayfA7Wo2',
type: 'Ed25519VerificationKey2018',
publicKeyBase58: '5niu5fffegbFeKawmNNnTALJshpuqzcFnBPjA8QVSgmX',
},
],
service: [
{
id: '9nYw7CSdHPqXf6ayfA7Wo2#In7780cd24-af13-423e-b1ff-ae944ab6fd71dyAgentService',
serviceEndpoint: 'http://localhost:4005',
type: 'IndyAgent',
priority: 0,
recipientKeys: ['5niu5fffegbFeKawmNNnTALJshpuqzcFnBPjA8QVSgmX'],
routingKeys: [],
},
],
authentication: [
{
publicKey: '9nYw7CSdHPqXf6ayfA7Wo2#1',
type: 'Ed25519SignatureAuthentication2018',
},
],
id: '9nYw7CSdHPqXf6ayfA7Wo2',
},
verkey: '5niu5fffegbFeKawmNNnTALJshpuqzcFnBPjA8QVSgmX',
state: 'invited',
role: 'inviter',
alias: 'member',
autoAcceptConnection: true,
invitation: {
'@type': 'https://didcomm.org/connections/1.0/invitation',
'@id': 'ac3b1469-cf46-43fc-a83a-dcff2c005b4e',
label: 'technica_corp',
recipientKeys: ['5niu5fffegbFeKawmNNnTALJshpuqzcFnBPjA8QVSgmX'],
serviceEndpoint: 'http://localhost:4005',
routingKeys: [],
},
multiUseInvitation: false,
},
};
const result: any = {
statusCode: 200,
message: 'Connection created successfully',
data: {
invitationUrl:
'http://localhost:4005?c_i=eyJAdHlwZSI6ImRpZDpzb3Y6QnpDYnNOWWhNcmpIaXFaRFRVQVNIZztzcGVjL2Nvbm5lY3Rpb25zLzEuMC9pbnZpdGF0aW9uIiwiQGlkIjoiYWMzYjE0NjktY2Y0Ni00M2ZjLWE4M2EtZGNmZjJjMDA1YjRlIiwibGFiZWwiOiJ0ZWNobmljYV9jb3JwIiwicmVjaXBpZW50S2V5cyI6WyI1bml1NWZmZmVnYkZlS2F3bU5OblRBTEpzaHB1cXpjRm5CUGpBOFFWU2dtWCJdLCJzZXJ2aWNlRW5kcG9pbnQiOiJodHRwOi8vMy4xMTEuNzcuMzg6NDAwNSIsInJvdXRpbmdLZXlzIjpbXX0',
invitation: {
'@type':
'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/invitation',
'@id': 'ac3b1469-cf46-43fc-a83a-dcff2c005b4e',
label: 'technica_corp',
recipientKeys: ['5niu5fffegbFeKawmNNnTALJshpuqzcFnBPjA8QVSgmX'],
serviceEndpoint: 'http://localhost:4005',
routingKeys: [],
},
connection: {
_tags: {},
metadata: {},
id: 'c1d73d9e-6988-4c84-9ebc-068c265d2fb6',
createdAt: '2022-04-21T10:52:18.161Z',
did: '9nYw7CSdHPqXf6ayfA7Wo2',
didDoc: {
'@context': 'https://w3id.org/did/v1',
publicKey: [
{
id: '9nYw7CSdHPqXf6ayfA7Wo2#1',
controller: '9nYw7CSdHPqXf6ayfA7Wo2',
type: 'Ed25519VerificationKey2018',
publicKeyBase58:
'5niu5fffegbFeKawmNNnTALJshpuqzcFnBPjA8QVSgmX',
},
],
service: [
{
id: '9nYw7CSdHPqXf6ayfA7Wo2#In7780cd24-af13-423e-b1ff-ae944ab6fd71dyAgentService',
serviceEndpoint: 'http://localhost:4005',
type: 'IndyAgent',
priority: 0,
recipientKeys: [
'5niu5fffegbFeKawmNNnTALJshpuqzcFnBPjA8QVSgmX',
],
routingKeys: [],
},
],
authentication: [
{
publicKey: '9nYw7CSdHPqXf6ayfA7Wo2#1',
type: 'Ed25519SignatureAuthentication2018',
},
],
id: '9nYw7CSdHPqXf6ayfA7Wo2',
},
verkey: '5niu5fffegbFeKawmNNnTALJshpuqzcFnBPjA8QVSgmX',
state: 'invited',
role: 'inviter',
alias: 'member',
autoAcceptConnection: true,
invitation: {
'@type': 'https://didcomm.org/connections/1.0/invitation',
'@id': 'ac3b1469-cf46-43fc-a83a-dcff2c005b4e',
label: 'technica_corp',
recipientKeys: ['5niu5fffegbFeKawmNNnTALJshpuqzcFnBPjA8QVSgmX'],
serviceEndpoint: 'http://localhost:4005',
routingKeys: [],
},
multiUseInvitation: false,
},
},
};
const response = createResponse();
jest
.spyOn(connectionService, 'createInvitationURL')
.mockResolvedValueOnce(serviceResult);
const res: any = await connectionController.createConnectionInvitation(
body,
query,
response,
);
// eslint-disable-next-line no-underscore-dangle
const resData = res._getData();
expect(res.statusCode).toBe(HttpStatus.OK);
expect(resData).toStrictEqual(result);
});
it('Get Member invitation URL-> Agent is not present', async () => {
const body = {
autoAcceptConnection: true,
};
const query = {
participantId: '7780cd24-af13-423e-b1ff-ae944ab6fd71',
process: 'member',
};
const serviceResult: any = undefined;
const result: any = {
statusCode: HttpStatus.NOT_FOUND,
message: 'Agent Data not found.',
};
const response = createResponse();
jest
.spyOn(connectionService, 'createInvitationURL')
.mockResolvedValueOnce(serviceResult);
const res: any = await connectionController.createConnectionInvitation(
body,
query,
response,
);
// eslint-disable-next-line no-underscore-dangle
const resData = res._getData();
expect(res.statusCode).toBe(HttpStatus.NOT_FOUND);
expect(resData).toStrictEqual(result);
});
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment