From ff4a33e234094cf497a4eb38699d4eb221be55f2 Mon Sep 17 00:00:00 2001
From: Berend Sliedrecht <berend@animo.id>
Date: Thu, 23 Nov 2023 13:47:24 +0100
Subject: [PATCH] test(ssi): added integration and unit tests

Signed-off-by: Berend Sliedrecht <berend@animo.id>
---
 .../agent/__tests__/agent.controller.spec.ts  | 32 ++++++++++
 .../src/agent/agent.controller.ts             |  4 +-
 .../src/agent/agent.service.ts                |  8 ++-
 .../agent/connection/connection.controller.ts | 14 -----
 .../src/agent/connection/connection.module.ts | 13 ----
 .../__tests__/connections.controller.spec.ts  | 35 +++++++++++
 .../connections/connections.controller.ts     | 14 +++++
 .../agent/connections/connections.module.ts   | 13 ++++
 .../connections.service.ts}                   |  2 +-
 apps/ssi-abstraction/src/app.module.ts        |  4 +-
 .../src/config/__tests__/mockConfig.ts        | 61 +++++++++++++++++++
 apps/ssi-abstraction/src/config/config.ts     |  6 +-
 apps/ssi-abstraction/test/agent.e2e-spec.ts   | 57 +++++++++++++++++
 .../test/connections.e2e-spec.ts              | 51 ++++++++++++++++
 pnpm-lock.yaml                                | 16 ++---
 15 files changed, 284 insertions(+), 46 deletions(-)
 create mode 100644 apps/ssi-abstraction/src/agent/__tests__/agent.controller.spec.ts
 delete mode 100644 apps/ssi-abstraction/src/agent/connection/connection.controller.ts
 delete mode 100644 apps/ssi-abstraction/src/agent/connection/connection.module.ts
 create mode 100644 apps/ssi-abstraction/src/agent/connections/__tests__/connections.controller.spec.ts
 create mode 100644 apps/ssi-abstraction/src/agent/connections/connections.controller.ts
 create mode 100644 apps/ssi-abstraction/src/agent/connections/connections.module.ts
 rename apps/ssi-abstraction/src/agent/{connection/connection.service.ts => connections/connections.service.ts} (93%)
 create mode 100644 apps/ssi-abstraction/src/config/__tests__/mockConfig.ts
 create mode 100644 apps/ssi-abstraction/test/agent.e2e-spec.ts
 create mode 100644 apps/ssi-abstraction/test/connections.e2e-spec.ts

diff --git a/apps/ssi-abstraction/src/agent/__tests__/agent.controller.spec.ts b/apps/ssi-abstraction/src/agent/__tests__/agent.controller.spec.ts
new file mode 100644
index 0000000..5d24ea1
--- /dev/null
+++ b/apps/ssi-abstraction/src/agent/__tests__/agent.controller.spec.ts
@@ -0,0 +1,32 @@
+import { Test } from '@nestjs/testing';
+
+import { mockConfigModule } from '../../config/__tests__/mockConfig.js';
+import { AgentController } from '../agent.controller.js';
+import { AgentService } from '../agent.service.js';
+
+describe('AgentController', () => {
+  let agentController: AgentController;
+  let agentService: AgentService;
+
+  beforeEach(async () => {
+    const moduleRef = await Test.createTestingModule({
+      imports: [mockConfigModule],
+      controllers: [AgentController],
+      providers: [AgentService],
+    }).compile();
+
+    agentService = moduleRef.get(AgentService);
+    agentController = moduleRef.get(AgentController);
+  });
+
+  describe('public did', () => {
+    it('should get the public did information of the agent', async () => {
+      const result = { id: 'test' };
+      jest
+        .spyOn(agentService, 'getPublicDid')
+        .mockImplementation(() => Promise.resolve(result));
+
+      expect(await agentController.publicDid()).toBe(result);
+    });
+  });
+});
diff --git a/apps/ssi-abstraction/src/agent/agent.controller.ts b/apps/ssi-abstraction/src/agent/agent.controller.ts
index 4a07c5b..42fcd10 100644
--- a/apps/ssi-abstraction/src/agent/agent.controller.ts
+++ b/apps/ssi-abstraction/src/agent/agent.controller.ts
@@ -9,8 +9,6 @@ export class AgentController {
 
   @MessagePattern('info.publicDid')
   public async publicDid() {
-    return {
-      id: 'test',
-    };
+    return await this.agent.getPublicDid()
   }
 }
diff --git a/apps/ssi-abstraction/src/agent/agent.service.ts b/apps/ssi-abstraction/src/agent/agent.service.ts
index 7e06a89..bc6289f 100644
--- a/apps/ssi-abstraction/src/agent/agent.service.ts
+++ b/apps/ssi-abstraction/src/agent/agent.service.ts
@@ -79,7 +79,7 @@ export class AgentService {
         key: walletKey,
       },
       endpoints,
-      logger: new AgentLogger(LogLevel.warn),
+      logger: new AgentLogger(LogLevel.off),
     };
   }
 
@@ -176,6 +176,12 @@ export class AgentService {
     }
   }
 
+  public async getPublicDid() {
+    return {
+      id: 'test',
+    };
+  }
+
   public async onModuleInit() {
     await this.agent.initialize();
     await this.registerPublicDid();
diff --git a/apps/ssi-abstraction/src/agent/connection/connection.controller.ts b/apps/ssi-abstraction/src/agent/connection/connection.controller.ts
deleted file mode 100644
index 83df332..0000000
--- a/apps/ssi-abstraction/src/agent/connection/connection.controller.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Controller } from '@nestjs/common';
-import { MessagePattern } from '@nestjs/microservices';
-
-import { ConnectionService } from './connection.service.js';
-
-@Controller('connection')
-export class ConnectionController {
-  public constructor(private connectionService: ConnectionService) {}
-
-  @MessagePattern('connection.getAll')
-  public async getAll() {
-    return this.connectionService.getAll();
-  }
-}
diff --git a/apps/ssi-abstraction/src/agent/connection/connection.module.ts b/apps/ssi-abstraction/src/agent/connection/connection.module.ts
deleted file mode 100644
index 4deaa82..0000000
--- a/apps/ssi-abstraction/src/agent/connection/connection.module.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Module } from '@nestjs/common';
-
-import { AgentModule } from '../agent.module.js';
-
-import { ConnectionController } from './connection.controller.js';
-import { ConnectionService } from './connection.service.js';
-
-@Module({
-  imports: [AgentModule],
-  providers: [ConnectionService],
-  controllers: [ConnectionController],
-})
-export class ConnectionModule {}
diff --git a/apps/ssi-abstraction/src/agent/connections/__tests__/connections.controller.spec.ts b/apps/ssi-abstraction/src/agent/connections/__tests__/connections.controller.spec.ts
new file mode 100644
index 0000000..f516874
--- /dev/null
+++ b/apps/ssi-abstraction/src/agent/connections/__tests__/connections.controller.spec.ts
@@ -0,0 +1,35 @@
+import type { ConnectionRecord } from '@aries-framework/core';
+
+import { Test } from '@nestjs/testing';
+
+import { mockConfigModule } from '../../../config/__tests__/mockConfig.js';
+import { AgentModule } from '../../agent.module.js';
+import { ConnectionsController } from '../connections.controller.js';
+import { ConnectionsService } from '../connections.service.js';
+
+describe('ConnectionsController', () => {
+  let connectionsController: ConnectionsController;
+  let connectionsService: ConnectionsService;
+
+  beforeEach(async () => {
+    const moduleRef = await Test.createTestingModule({
+      imports: [mockConfigModule, AgentModule],
+      controllers: [ConnectionsController],
+      providers: [ConnectionsService],
+    }).compile();
+
+    connectionsService = moduleRef.get(ConnectionsService);
+    connectionsController = moduleRef.get(ConnectionsController);
+  });
+
+  describe('get all', () => {
+    it('should get all the connection records of the agent', async () => {
+      const result: Array<ConnectionRecord> = [];
+      jest
+        .spyOn(connectionsService, 'getAll')
+        .mockImplementation(() => Promise.resolve(result));
+
+      expect(await connectionsController.getAll()).toBe(result);
+    });
+  });
+});
diff --git a/apps/ssi-abstraction/src/agent/connections/connections.controller.ts b/apps/ssi-abstraction/src/agent/connections/connections.controller.ts
new file mode 100644
index 0000000..c2aa973
--- /dev/null
+++ b/apps/ssi-abstraction/src/agent/connections/connections.controller.ts
@@ -0,0 +1,14 @@
+import { Controller } from '@nestjs/common';
+import { MessagePattern } from '@nestjs/microservices';
+
+import { ConnectionsService } from './connections.service.js';
+
+@Controller('connections')
+export class ConnectionsController {
+  public constructor(private connectionsService: ConnectionsService) {}
+
+  @MessagePattern('didcomm.connections.getAll')
+  public async getAll() {
+    return await this.connectionsService.getAll();
+  }
+}
diff --git a/apps/ssi-abstraction/src/agent/connections/connections.module.ts b/apps/ssi-abstraction/src/agent/connections/connections.module.ts
new file mode 100644
index 0000000..edee4f4
--- /dev/null
+++ b/apps/ssi-abstraction/src/agent/connections/connections.module.ts
@@ -0,0 +1,13 @@
+import { Module } from '@nestjs/common';
+
+import { AgentModule } from '../agent.module.js';
+
+import { ConnectionsController } from './connections.controller.js';
+import { ConnectionsService } from './connections.service.js';
+
+@Module({
+  imports: [AgentModule],
+  providers: [ConnectionsService],
+  controllers: [ConnectionsController],
+})
+export class ConnectionsModule {}
diff --git a/apps/ssi-abstraction/src/agent/connection/connection.service.ts b/apps/ssi-abstraction/src/agent/connections/connections.service.ts
similarity index 93%
rename from apps/ssi-abstraction/src/agent/connection/connection.service.ts
rename to apps/ssi-abstraction/src/agent/connections/connections.service.ts
index 0e4c7ed..5b8c7e8 100644
--- a/apps/ssi-abstraction/src/agent/connection/connection.service.ts
+++ b/apps/ssi-abstraction/src/agent/connections/connections.service.ts
@@ -6,7 +6,7 @@ import { Injectable } from '@nestjs/common';
 import { AgentService } from '../agent.service.js';
 
 @Injectable()
-export class ConnectionService {
+export class ConnectionsService {
   public agent: AppAgent;
 
   public constructor(agentService: AgentService) {
diff --git a/apps/ssi-abstraction/src/app.module.ts b/apps/ssi-abstraction/src/app.module.ts
index 762a4eb..42d9931 100644
--- a/apps/ssi-abstraction/src/app.module.ts
+++ b/apps/ssi-abstraction/src/app.module.ts
@@ -4,7 +4,7 @@ import { TerminusModule } from '@nestjs/terminus';
 import { HealthController } from '@ocm/shared';
 
 import { AgentModule } from './agent/agent.module.js';
-import { ConnectionModule } from './agent/connection/connection.module.js';
+import { ConnectionsModule } from './agent/connections/connections.module.js';
 import { config } from './config/config.js';
 import { validationSchema } from './config/validation.js';
 
@@ -17,7 +17,7 @@ import { validationSchema } from './config/validation.js';
       validationSchema,
     }),
     AgentModule,
-    ConnectionModule,
+    ConnectionsModule,
   ],
   controllers: [HealthController],
 })
diff --git a/apps/ssi-abstraction/src/config/__tests__/mockConfig.ts b/apps/ssi-abstraction/src/config/__tests__/mockConfig.ts
new file mode 100644
index 0000000..c12689f
--- /dev/null
+++ b/apps/ssi-abstraction/src/config/__tests__/mockConfig.ts
@@ -0,0 +1,61 @@
+import type { AppConfig } from '../config.js';
+
+import { AutoAcceptCredential } from '@aries-framework/core';
+import { ConfigModule, ConfigService } from '@nestjs/config';
+
+import { validationSchema } from '../validation.js';
+
+const mockConfig: AppConfig = {
+  agentHost: '',
+  port: 3000,
+  jwtSecret: '',
+  nats: {
+    url: 'localhost',
+  },
+  agent: {
+    name: 'my-test-agent',
+    walletId: 'some-id',
+    walletKey: 'some-key',
+    ledgerIds: ['BCOVRIN_TEST'],
+    host: '3000',
+    peerPort: '3001',
+    path: '',
+    publicDidSeed: 'none',
+    autoAcceptConnection: false,
+    autoAcceptCredential: AutoAcceptCredential.ContentApproved,
+  },
+};
+
+export const mockConfigModule = ConfigModule.forRoot({
+  load: [() => mockConfig],
+  validationSchema,
+});
+
+describe('configuration', () => {
+  describe('service', () => {
+    it('should be able to instantiate a config service', () => {
+      const configuration = new ConfigService(mockConfig);
+      expect(configuration).toBeInstanceOf(ConfigService);
+    });
+
+    it('should be able to extract root value', () => {
+      const configuration = new ConfigService(mockConfig);
+
+      expect(configuration.get('port')).toStrictEqual(mockConfig.port);
+    });
+
+    it('should be able to extract root value as object', () => {
+      const configuration = new ConfigService(mockConfig);
+
+      expect(configuration.get('agent')).toMatchObject(mockConfig.agent);
+    });
+
+    it('should be able to extract nested values', () => {
+      const configuration = new ConfigService(mockConfig);
+
+      expect(configuration.get('agent.autoAcceptCredential')).toStrictEqual(
+        mockConfig.agent.autoAcceptCredential,
+      );
+    });
+  });
+});
diff --git a/apps/ssi-abstraction/src/config/config.ts b/apps/ssi-abstraction/src/config/config.ts
index 874026b..3e54d34 100644
--- a/apps/ssi-abstraction/src/config/config.ts
+++ b/apps/ssi-abstraction/src/config/config.ts
@@ -1,6 +1,6 @@
 import { AutoAcceptCredential } from '@aries-framework/core';
 
-interface Config {
+export interface AppConfig {
   agentHost: string;
   port: number;
   jwtSecret: string;
@@ -20,11 +20,10 @@ interface Config {
     publicDidSeed: string;
     autoAcceptConnection: boolean;
     autoAcceptCredential: AutoAcceptCredential;
-    idUnionKey: string;
   };
 }
 
-export const config = (): Config => ({
+export const config = (): AppConfig => ({
   agentHost: process.env.AGENT_HOST || '',
   port: Number(process.env.PORT),
   jwtSecret: process.env.JWT_SECRET || '',
@@ -46,6 +45,5 @@ export const config = (): Config => ({
     autoAcceptCredential:
       (process.env.AGENT_AUTO_ACCEPT_CREDENTIAL as AutoAcceptCredential) ||
       AutoAcceptCredential.ContentApproved,
-    idUnionKey: process.env.AGENT_ID_UNION_KEY || '',
   },
 });
diff --git a/apps/ssi-abstraction/test/agent.e2e-spec.ts b/apps/ssi-abstraction/test/agent.e2e-spec.ts
new file mode 100644
index 0000000..f5ec1eb
--- /dev/null
+++ b/apps/ssi-abstraction/test/agent.e2e-spec.ts
@@ -0,0 +1,57 @@
+import type { INestApplication } from '@nestjs/common';
+import type { ClientProxy } from '@nestjs/microservices';
+
+import { ClientsModule, Transport } from '@nestjs/microservices';
+import { Test } from '@nestjs/testing';
+import { firstValueFrom, type Observable } from 'rxjs';
+
+import { AgentModule } from '../src/agent/agent.module.js';
+import { AgentService } from '../src/agent/agent.service.js';
+import { mockConfigModule } from '../src/config/__tests__/mockConfig.js';
+
+describe('Agent', () => {
+  const TOKEN = 'AGENT_CLIENT_SERVICE';
+  let app: INestApplication;
+  let client: ClientProxy;
+
+  const agentService = {
+    getPublicDid: () =>
+      Promise.resolve({
+        id: 'test',
+      }),
+  };
+
+  beforeAll(async () => {
+    const moduleRef = await Test.createTestingModule({
+      imports: [
+        mockConfigModule,
+        AgentModule,
+        ClientsModule.register([{ name: TOKEN, transport: Transport.NATS }]),
+      ],
+    })
+      .overrideProvider(AgentService)
+      .useValue(agentService)
+      .compile();
+
+    app = moduleRef.createNestApplication();
+
+    app.connectMicroservice({ transport: Transport.NATS });
+
+    await app.startAllMicroservices();
+    await app.init();
+
+    client = app.get(TOKEN);
+    await client.connect();
+  });
+
+  it('info.publicDid', async () => {
+    const response$: Observable<unknown> = client.send('info.publicDid', {});
+    const response = await firstValueFrom(response$);
+    expect(response).toMatchObject({ id: 'test' });
+  });
+
+  afterAll(async () => {
+    await app.close();
+    client.close();
+  });
+});
diff --git a/apps/ssi-abstraction/test/connections.e2e-spec.ts b/apps/ssi-abstraction/test/connections.e2e-spec.ts
new file mode 100644
index 0000000..d749062
--- /dev/null
+++ b/apps/ssi-abstraction/test/connections.e2e-spec.ts
@@ -0,0 +1,51 @@
+import type { INestApplication } from '@nestjs/common';
+import type { ClientProxy } from '@nestjs/microservices';
+
+import { ClientsModule, Transport } from '@nestjs/microservices';
+import { Test } from '@nestjs/testing';
+import { firstValueFrom, type Observable } from 'rxjs';
+
+import { AgentModule } from '../src/agent/agent.module.js';
+import { ConnectionsModule } from '../src/agent/connections/connections.module.js';
+import { mockConfigModule } from '../src/config/__tests__/mockConfig.js';
+
+describe('Connections', () => {
+  const TOKEN = 'CONNECTIONS_CLIENT_SERVICE';
+  let app: INestApplication;
+  let client: ClientProxy;
+
+  beforeAll(async () => {
+    const moduleRef = await Test.createTestingModule({
+      imports: [
+        mockConfigModule,
+        AgentModule,
+        ConnectionsModule,
+        ClientsModule.register([{ name: TOKEN, transport: Transport.NATS }]),
+      ],
+    }).compile();
+
+    app = moduleRef.createNestApplication();
+
+    app.connectMicroservice({ transport: Transport.NATS });
+
+    await app.startAllMicroservices();
+    await app.init();
+
+    client = app.get(TOKEN);
+    await client.connect();
+  });
+
+  it('didcomm.connections.getAll', async () => {
+    const response$: Observable<unknown> = client.send(
+      'didcomm.connections.getAll',
+      {},
+    );
+    const response = await firstValueFrom(response$);
+    expect(response).toMatchObject([]);
+  });
+
+  afterAll(async () => {
+    await app.close();
+    client.close();
+  });
+});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index bbea83a..c3d6966 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -36,8 +36,8 @@ importers:
         specifier: ^5.0.1
         version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.54.0)(prettier@3.1.0)
       eslint-plugin-workspaces:
-        specifier: ^0.10.0
-        version: 0.10.0
+        specifier: ^0.9.0
+        version: 0.9.0
       husky:
         specifier: ^8.0.0
         version: 8.0.3
@@ -7869,10 +7869,10 @@ packages:
       synckit: 0.8.5
     dev: true
 
-  /eslint-plugin-workspaces@0.10.0:
-    resolution: {integrity: sha512-H692yRZFczzzyde0Sq3nmRDlyywv6foYJnmsxO3slWImJdCf4g5D+gzdWeRpmfitgUsFZxXVJdvW4OS6yY4M9g==}
+  /eslint-plugin-workspaces@0.9.0:
+    resolution: {integrity: sha512-krMuZ+yZgzwv1oTBfz50oamNVPDIm7CDyot3i1GRKBqMD2oXAwnXHLQWH7ctpV8k6YVrkhcaZhuV9IJxD8OPAQ==}
     dependencies:
-      find-workspaces: 0.3.0
+      find-workspaces: 0.2.0
     dev: true
 
   /eslint-scope@5.1.1:
@@ -8191,7 +8191,7 @@ packages:
     dependencies:
       chalk: 4.1.2
       commander: 7.2.0
-      fast-glob: 3.3.1
+      fast-glob: 3.3.2
       find-up: 5.0.0
       fs-extra: 9.1.0
     dev: false
@@ -8608,8 +8608,8 @@ packages:
       semver-regex: 4.0.5
     dev: true
 
-  /find-workspaces@0.3.0:
-    resolution: {integrity: sha512-sHdt3vbddcDuN0CYnKoG/b77jrOkSYPlxoM7ve7/vEvAd29XC7u/qE2zavRzJv4eD1sbTvDnRNZskdy/e0v83A==}
+  /find-workspaces@0.2.0:
+    resolution: {integrity: sha512-OTHryv88yjzwvbXHGi0+XRFu7Jqe5pFuIR2mhqdatDJQOBJd7MFJOPFJv4EbNo8n1BNM/13Y2KcyDpFQYf0ETw==}
     dependencies:
       fast-glob: 3.3.2
       pkg-types: 1.0.3
-- 
GitLab