import { expect } from "chai"; import sinon from "sinon"; import "mocha"; import { ExitCode, InternalService, Microservice } from "../../src"; class MockService1 extends InternalService {}; class MockService2 extends InternalService {}; class FaultyBootService extends InternalService { public async boot() { throw new Error("Boot error"); } }; class FaultyStartService extends InternalService { public async start() { throw new Error("Start error"); } } class FaultyShutdownService extends InternalService { public async shutdown() { throw new Error("Shutdown error"); } } describe("Internal service integration", () => { describe("Service installation", () => { let service = new Microservice(); service.installServices([MockService1, MockService2]); it("should have one service installed", () => { expect(service.services().size).to.equal(2); }); it("should have the microservice instance", () => { expect(service.service(MockService1).microservice()).to.equal(service); }); }); describe("Duplicate service installation", () => { let service = new Microservice(); service.installService(MockService1); it("should throw the correct error type", () => { // For some reason checking error type fails here... expect(() => service.installService(MockService1)).to.throw(); // expect(() => service.installService(MockService1)).to.throw(InternalServiceNotFoundError); }); }); describe("Fetch an installed service", () => { let service = new Microservice(); service.installService(MockService1); it("should return the correct service instance", () => { expect(service.service(MockService1)).to.be.an.instanceOf(MockService1); }); }); describe("Fetch a non-installed service", () => { let service = new Microservice(); it("should throw an error", () => { expect(() => service.service(MockService1)).to.throw(); }); }); describe("Invoke the appropriate boot, start, and shutdown methods", () => { let microservice = new Microservice(); microservice.installService(MockService1); let service = microservice.service(MockService1); let spyBoot = sinon.spy(service, "boot"); let spyStart = sinon.spy(service, "start"); let spyShutdown = sinon.spy(service, "shutdown"); it("should start and finish the app", async () => { let cb = new Promise((resolve) => microservice.once("ready", resolve)); let execPromise = microservice.exec(); await cb; microservice.quit(); await execPromise; }); it("should have invoked boot method", () => { sinon.assert.calledOnce(spyBoot); }); it("should have invoked start method", () => { sinon.assert.calledOnce(spyStart); }); it("should have invoked shutdown method", () => { sinon.assert.calledOnce(spyShutdown); }); }); describe("Error handling", () => { describe("Faulty boot service", () => { let microservice = new Microservice(); microservice.installServices([MockService1, FaultyBootService]); it("should crash with correct exit code", async () => { let exitCode = await microservice.exec(); expect(exitCode).to.equal(ExitCode.BootError); }); }); describe("Faulty start service", () => { let microservice = new Microservice(); microservice.installServices([MockService1, FaultyStartService]); it("should crash with correct exit code", async () => { let exitCode = await microservice.exec(); expect(exitCode).to.equal(ExitCode.StartError); }); }); describe("Faulty shutdown service", () => { let microservice = new Microservice(); microservice.installServices([MockService1, FaultyShutdownService]); it("should crash with correct exit code", async () => { let execPromise = microservice.exec(); microservice.quit(); let exitCode = await execPromise; expect(exitCode).to.equal(ExitCode.ShutdownError); }); }); }); });