From 242e3bd81e5e8506f18ee86cfa1df93a19712998 Mon Sep 17 00:00:00 2001 From: Zack Jackson Date: Fri, 9 Apr 2021 18:21:01 -0700 Subject: [PATCH] adding tests --- .npmignore | 1 + package.json | 14 ++- test/adapters/event-adapter.js | 51 ++++++++++ test/controllers/post-model.js | 41 ++++++++ test/datasources/datasource-file.js | 15 +++ test/models/mixins.js | 145 ++++++++++++++++++++++++++++ test/models/model-factory.js | 31 ++++++ test/models/model.js | 137 ++++++++++++++++++++++++++ test/services/event-service.js | 9 ++ test/use-cases/add-model.js | 33 +++++++ test/use-cases/execute-command.js | 37 +++++++ webpack/fetch-remotes.js | 60 ++++++++++++ 12 files changed, 572 insertions(+), 2 deletions(-) create mode 100644 test/adapters/event-adapter.js create mode 100644 test/controllers/post-model.js create mode 100644 test/datasources/datasource-file.js create mode 100644 test/models/mixins.js create mode 100644 test/models/model-factory.js create mode 100644 test/models/model.js create mode 100644 test/services/event-service.js create mode 100644 test/use-cases/add-model.js create mode 100644 test/use-cases/execute-command.js create mode 100644 webpack/fetch-remotes.js diff --git a/.npmignore b/.npmignore index 53c2f91b..c287b58d 100644 --- a/.npmignore +++ b/.npmignore @@ -2,3 +2,4 @@ .gitignore .eslint.js /src +/test \ No newline at end of file diff --git a/package.json b/package.json index 89bf67b8..00a4925e 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "build": "npm run build:esm && npm run build:cjs", "build:esm": "babel --delete-dir-on-start -d esm/ src/ && cp src/index.js esm && cp src/cluster.js esm && cp src/auth.js esm", "build:cjs": "babel --delete-dir-on-start --env-name cjs -d lib/ src/ && cp src/index.js lib && cp src/cluster.js lib && cp src/auth.js esm", - "prepublish": "yarn build" + "prepublish": "yarn build", + "test": "mocha --recursive -r esm" }, "peerDependencies": { "core-js": "^3" @@ -31,7 +32,16 @@ "eslint-plugin-prettier": "^3.1.4", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-standard": "^4.0.2", - "prettier": "^2.1.2" + "prettier": "^2.1.2", + "@babel/node": "^7.10.5", + "@babel/polyfill": "^7.11.5", + "esm": "^3.2.25", + "express-cli": "0.0.1", + "mocha": "^8.2.0", + "nodemon": "^2.0.6", + "rimraf": "^3.0.2", + "webpack": "^5.4.0", + "webpack-cli": "^3.3.12" }, "dependencies": { "dotenv": "^8.2.0", diff --git a/test/adapters/event-adapter.js b/test/adapters/event-adapter.js new file mode 100644 index 00000000..7499b68c --- /dev/null +++ b/test/adapters/event-adapter.js @@ -0,0 +1,51 @@ + +// var assert = require('assert'); +// import Model from '../../src/models/model'; +// import { listen } from '../../src/adapters/event-adapter'; +// import { Event } from '../services/event-service'; + +// describe('event-adapter', function () { +// // describe('listen()', async function () { +// it('should automatically unsubscribe on receipt of message', async function () { +// const id = {}; +// function make() { +// return (...b) => ({ a: 'a', b }); +// } +// const adapters = { +// listen: listen(Event), +// async test({ model }) { +// const subscription = await model.listen({ +// topic: 'test', +// id: id, +// filter: 'test', +// once: true, +// model, +// callback: ({ subscription }) => subscription +// }); +// console.log({ subscriptions: subscription.getSubscriptions()[0] }); +// } +// } +// const model = await Model.create({ +// spec: { +// modelName: 'ABC', +// factory: make(), +// ports: { +// listen: { +// type: 'outbound' +// }, +// test: { +// type: 'outbound' +// } +// }, +// dependencies: adapters +// }, +// args: [{ c: 'c' }] +// }); +// const subscription = await model.test(); +// console.log({ subscriptions: subscription.getSubscriptions()[0] }); +// assert.strictEqual( +// false, subscription.getSubscriptions()[0][1].delete(id) +// ); +// }); +// }); +// }); \ No newline at end of file diff --git a/test/controllers/post-model.js b/test/controllers/post-model.js new file mode 100644 index 00000000..76369732 --- /dev/null +++ b/test/controllers/post-model.js @@ -0,0 +1,41 @@ +'use strict' + +var assert = require('assert'); + +import addModelFactory from '../../lib/use-cases/add-model' +import postModelFactory from '../../lib/controllers/post-model' + +import DataSourceFactory from '../../lib/datasources' +import ModelFactory from '../../lib/models'; +import ObserverFactory from '../../lib/models/observer'; +import hash from '../../lib/lib/hash' + +describe('Controllers', function () { + describe('postModel()', function () { + it('should add new model', async function () { + ModelFactory.registerModel({ + modelName: 'ABC', + factory: ({ a }) => ({ a, b: 'c' }), + endpoint: 'abcs', + dependencies: {} + }); + ModelFactory.registerEvent( + ModelFactory.EventTypes.CREATE, + 'ABC', + (model) => ({ model }) + ); + const addModel = await addModelFactory({ + modelName: 'ABC', + models: ModelFactory, + repository: DataSourceFactory.getDataSource('ABC'), + observer: ObserverFactory.getInstance() + }); + const resp = await postModelFactory( + addModel, + ModelFactory.getModelId, + hash + )({ body: { a: 'a' }, headers: { 'User-Agent': 'test' }, ip: '127.0.0.1' }); + assert.strictEqual(resp.statusCode, 201); + }); + }); +}); \ No newline at end of file diff --git a/test/datasources/datasource-file.js b/test/datasources/datasource-file.js new file mode 100644 index 00000000..4dada76d --- /dev/null +++ b/test/datasources/datasource-file.js @@ -0,0 +1,15 @@ +"use strict"; + +var assert = require("assert"); +process.env.DATASOURCE_ADAPTER = "DataSourceFile"; +const { default: DataSourceFactory } = require("../../lib/datasources"); + +describe("datasources", function () { + var ds = DataSourceFactory.getDataSource("test"); + ds.load({ + name: "test" + }); + ds.save(1, "data"); + console.log("record", ds.find(1)); + it("read from file", function () {}); +}); diff --git a/test/models/mixins.js b/test/models/mixins.js new file mode 100644 index 00000000..5170a2b1 --- /dev/null +++ b/test/models/mixins.js @@ -0,0 +1,145 @@ +"use strict"; + +var assert = require("assert"); +const { + fromSymbol, + toSymbol, + fromTimestamp, + withSerializers, + withDeserializers, +} = require("../../src/models/mixins"); + +describe("Mixins", function () { + it("should return strings in place of symbols", function () { + const ID = Symbol("id"); + const CREATETIME = Symbol("createTime"); + + const keyMap = { + id: ID, + createTime: CREATETIME, + }; + var time = new Date().getTime(); + var obj1 = { + [ID]: "123", + [CREATETIME]: time, + id: "123", + createTime: time, + }; + // console.log("obj1", obj1); + var obj2 = fromSymbol(keyMap)(obj1); + // console.log("obj2", obj2); + assert.strictEqual(JSON.stringify(obj1), JSON.stringify(obj2)); + }); + it("should return Symbols in place of strings", function () { + const ID = Symbol("id"); + const CREATETIME = Symbol("createTime"); + + const keyMap = { + id: ID, + createTime: CREATETIME, + }; + var time = new Date().getTime(); + var obj1 = { + id: "123", + createTime: time, + }; + // console.log("obj1", obj1); + var obj2 = toSymbol(keyMap)(obj1); + // console.log("obj2", obj2); + assert.strictEqual(JSON.stringify(obj1), JSON.stringify(obj2)); + }); + it("should return utc in place of timestamp", function () { + var time = new Date().getTime(); + var obj1 = { + createTime: time, + updateTime: time, + }; + // console.log("obj1", obj1); + var obj2 = fromTimestamp(["createTime", "updateTime"])(obj1); + // console.log("obj2", obj2); + assert.strictEqual( + new Date(obj1.createTime).toUTCString(), + obj2.createTime + ); + assert.strictEqual( + new Date(obj1.updateTime).toUTCString(), + obj2.updateTime + ); + }); + it("should return serialized output", function () { + var time = new Date().getTime(); + const ID = Symbol("id"); + const CREATETIME = Symbol("createTime"); + const keyMap = { + id: ID, + createTime: CREATETIME, + }; + var obj1 = { + [ID]: "123", + [CREATETIME]: time, + }; + var serialize = withSerializers( + fromSymbol(keyMap), + fromTimestamp(["createTime"]) + ); + var obj2 = serialize(obj1); + var obj3 = { + createTime: new Date(time).toUTCString(), + id: "123", + }; + // console.log(fromTimestamps(["createTime"]).toString()); + // console.log(fromSymbols(keyMap).toString()); + // console.log(withSerializer( + // fromSymbols(keyMap), + // fromTimestamps(["createTime"]) + // ).toString()); + //console.log(makeModel.toString()); + // console.log("obj1", obj1); + // console.log("obj2", obj2); + // console.log("obj3", obj3); + // console.log("stringify(obj1)", JSON.stringify(obj1)); + // console.log("stringify(obj2)", JSON.stringify(obj2)); + // console.log("stringify(obj3)", JSON.stringify(obj3)); + assert.strictEqual(JSON.stringify(obj2), JSON.stringify(obj3)); + }); + + it("should return deserialized output", function () { + var time = new Date().getTime(); + const ID = Symbol("id"); + const CREATETIME = Symbol("createTime"); + const keyMap = { + id: ID, + createTime: CREATETIME, + }; + var obj1 = { + [ID]: "123", + [CREATETIME]: time, + }; + var serialize = withSerializers( + fromSymbol(keyMap), + fromTimestamp(["createTime"]) + ); + var deserialize = withDeserializers( + toSymbol(keyMap), + ); + var obj2 = deserialize(serialize(obj1)); + var obj3 = { + createTime: new Date(time).toUTCString(), + id: "123", + }; + // console.log(fromTimestamps(["createTime"]).toString()); + // console.log(fromSymbols(keyMap).toString()); + // console.log(withSerializer( + // fromSymbols(keyMap), + // fromTimestamps(["createTime"]) + // ).toString()); + //console.log(makeModel.toString()); + console.log("obj1", obj1); + console.log("obj2", obj2); + console.log("obj3", obj3); + console.log("parse(obj1)", JSON.parse(JSON.stringify(obj1))); + console.log("parse(obj2)", JSON.parse(JSON.stringify(obj2))); + console.log("parse(obj3)", JSON.parse(JSON.stringify(obj3))); + assert.strictEqual(JSON.parse(JSON.stringify(obj2)), JSON.parse(JSON.stringify(obj))); + }); +}); diff --git a/test/models/model-factory.js b/test/models/model-factory.js new file mode 100644 index 00000000..660aa826 --- /dev/null +++ b/test/models/model-factory.js @@ -0,0 +1,31 @@ +'use strict' + +var assert = require('assert'); + +import ModelFactory from '../../src/models'; + + +describe('ModelFactory', function () { + describe('#createModel()', function () { + it('should register & create model', async function () { + ModelFactory.registerModel({ + modelName: 'ABC', + factory: ({ a }) => ({ a, b: 'c' }), + endpoint: 'abcs', + dependencies: {} + }); + const model = await ModelFactory.createModel('ABC', { a: 'a' }); + assert.strictEqual(ModelFactory.getModelName(model), 'ABC'); + }); + it('should have props from args', async function () { + ModelFactory.registerModel({ + modelName: 'ABC', + factory: ({ a }) => ({ a, b: 'c' }), + endpoint: 'abcs', + dependencies: {} + }); + const model = await ModelFactory.createModel('ABC', { a: 'a' }); + assert.strictEqual(model.a, 'a'); + }); + }); +}); \ No newline at end of file diff --git a/test/models/model.js b/test/models/model.js new file mode 100644 index 00000000..626ae132 --- /dev/null +++ b/test/models/model.js @@ -0,0 +1,137 @@ +'use strict' + +var assert = require('assert'); + +import Model from '../models/model' + + +describe('Model', function () { + describe('#create()', function () { + it('should return new model', async function () { + const model = await Model.create({ + spec: { + modelName: 'ABC', + factory: ({ b }) => ({ a: 'a', b }), + }, + args: [{ c: 'c' }] + }); + assert.ok(model); + }); + }); + describe('#injection()', function () { + it('dependency injection should work', async function () { + function make(dependencies) { + return async (...b) => ({ + a: 'a', + b, + injection: dependencies.injection + }) + } + const dependencies = { + injection() { + return this; + } + } + const model = await Model.create({ + spec: { + modelName: 'ABC', + factory: make(dependencies), + dependencies + }, + args: [{ c: 'c' }] + }); + assert.strictEqual(model, model.injection()); + }); + }); + describe('#port1()', function () { + it('should generate port and attach to adapter', async function () { + const adapters = { + async port1({ model }) { + console.log(model); + } + } + + function make() { + return (...b) => ({ a: 'a', b }); + } + + const model = await Model.create({ + spec: { + modelName: 'ABC', + factory: make(), + ports: { + port1: { + type: 'outbound' + } + }, + dependencies: {...adapters} + }, + args: [{ c: 'c' }] + }); + assert.ok(model.port1()); + }); + }); + describe('#getName()', function () { + it('should return model name', async function () { + const model = await Model.create({ + spec: { + modelName: 'ABC', + factory: ({ b }) => ({ a: 'a', b }), + }, + args: [{ b: 'c' }] + }); + assert.ok(Model.getId(model)); + assert.strictEqual(Model.getName(model), 'ABC'); + }); + }); + describe('#a', function () { + it('should return model prop', async function () { + const model = await Model.create({ + spec: { + modelName: 'ABC', + factory: ({ b }) => ({ a: 'a', b }), + }, + args: [{ b: 'c' }] + }); + assert.strictEqual(model.a, 'a'); + }); + }); + describe('#b', function () { + it('should return model prop with args value', async function () { + const model = await Model.create({ + spec: { + modelName: 'ABC', + factory: ({ b }) => ({ a: 'a', b }), + }, + args: [{ b: 'c' }] + }); + assert.strictEqual(model.b, 'c'); + }); + }); + describe('#getKey()', function () { + it('should return key', async function () { + const model = await Model.create({ + spec: { + modelName: 'ABC', + factory: ({ b }) => ({ a: 'a', b }), + }, + args: [{ b: 'c' }] + }); + assert.ok(Model.getKey('onUpdate')); + }); + }); + describe('#onUpdate()', function () { + it('should return updated model', async function () { + const model = await Model.create({ + spec: { + modelName: 'ABC', + factory: ({ b }) => ({ a: 'a', b }), + }, + args: [{ b: 'c' }] + }); + assert.strictEqual(model.a, 'a'); + const updated = model[Model.getKey('onUpdate')]({ a: 'b' }); + assert.strictEqual(updated.a, 'b'); + }); + }); +}); \ No newline at end of file diff --git a/test/services/event-service.js b/test/services/event-service.js new file mode 100644 index 00000000..3fffc76e --- /dev/null +++ b/test/services/event-service.js @@ -0,0 +1,9 @@ + + +export const Event = { + + async listen(topic, callback) { + setTimeout(() => callback({ topic, message: 'test' }), 1000); + } + +} \ No newline at end of file diff --git a/test/use-cases/add-model.js b/test/use-cases/add-model.js new file mode 100644 index 00000000..a402daf2 --- /dev/null +++ b/test/use-cases/add-model.js @@ -0,0 +1,33 @@ +'use strict' + +var assert = require('assert'); + +import addModelFactory from '../../lib/use-cases/add-model' +import DataSourceFactory from '../../lib/datasources' +import ModelFactory from '../../lib/lib/models'; +import ObserverFactory from '../../lib/models/observer'; + +describe('Use-Cases', function () { + describe('addModel()', function () { + it('should add new model', async function () { + ModelFactory.registerModel({ + modelName: 'ABC', + factory: ({ a }) => ({ a, b: 'c' }), + endpoint: 'abcs', + dependencies: {} + }); + ModelFactory.registerEvent( + ModelFactory.EventTypes.CREATE, + 'ABC', + (model) => ({model}) + ); + const model = await addModelFactory({ + modelName: 'ABC', + models: ModelFactory, + repository: DataSourceFactory.getDataSource('ABC'), + observer: ObserverFactory.getInstance() + })({ a: 'a' }); + assert.strictEqual(model.a, { a: 'a' }.a); + }); + }); +}); \ No newline at end of file diff --git a/test/use-cases/execute-command.js b/test/use-cases/execute-command.js new file mode 100644 index 00000000..720c75cf --- /dev/null +++ b/test/use-cases/execute-command.js @@ -0,0 +1,37 @@ +var assert = require("assert"); +import DataSourceFactory from "../../lib/datasources"; +import ObserverFactory from "../../src/models/observer"; +import ModelFactory from "../../src/models/model-factory"; +import checkAcl from "../../src/esm/lib/check-acl"; + +const { + default: executeCommand, +} = require("@module-federation/aegis/lib/use-cases/execute-command"); + +describe("executeCommand()", function () { + it("should add new model", async function () { + const spec = { + modelName: "test", + endpoint: "tests", + factory: () => ({ decrypt: () => console.log("decrypted") }), + commands: { + decrypt: { + command: "decrypt", + acl: "read", + }, + }, + }; + + ModelFactory.registerModel(spec); + + var m = await ModelFactory.createModel( + ObserverFactory.getInstance(), + DataSourceFactory.getDataSource("TEST"), + "TEST", + [1, 2, 3] + ); + //checkAcl(spec.commands[query.command].acl, permission) + console.log(m); + await executeCommand(ModelFactory, m, { command: "decrypt" }, "*"); + }); +}); diff --git a/webpack/fetch-remotes.js b/webpack/fetch-remotes.js new file mode 100644 index 00000000..9997b9ef --- /dev/null +++ b/webpack/fetch-remotes.js @@ -0,0 +1,60 @@ +const { URL } = require("url"); +const http = require("http"); +const fs = require("fs"); + +/** + * Download remote container bundles + * @param {{ + * name: string, + * url: string, + * path: string + * }[]} remoteEntry `name` of app, `url` of remote entry, download file to `path` + * + * @returns {Promise<{[index: string]: string}>} local paths to downloaded entries + */ +module.exports = async remoteEntry => { + console.log(remoteEntry); + const entries = Array.isArray(remoteEntry) ? remoteEntry : [remoteEntry]; + + const getPath = entry => { + const url = new URL(entry.url); + const path = [ + url.pathname.replace(".js", ""), + url.hostname.replace(".", "-"), + url.port, + entry.name.concat(".js"), + ].join("-"); + + return entry.path.concat(path); + }; + + const remotes = await Promise.all( + entries.map(async entry => { + const path = getPath(entry); + console.log(path); + + return new Promise(resolve => { + const rslv = () => resolve({ [entry.name]: path }); + + const req = http.request(entry.url, res => { + res.on("error", rslv); + if (res.statusCode < 200 || res.statusCode >= 300) { + return rslv(); + } + res.pipe(fs.createWriteStream(path)); + + res.on("end", rslv); + }); + + req.on("error", rslv); + req.end(); + }); + }) + ).catch(() => { + return entries.map(entry => ({ + [entry.name]: getPath(entry), + })); + }); + + return remotes.reduce((p, c) => ({ ...c, ...p })); +};