浏览代码

feat: Added basic data module automated test foundation

Owen Diffey 1 年之前
父节点
当前提交
16d6aa88d1

+ 2 - 0
.github/workflows/automated-tests.yml

@@ -36,5 +36,7 @@ jobs:
                   ./musare.sh build
             - name: Start Musare
               run: ./musare.sh start
+            - name: Test Backend
+              run: ./musare.sh test backend
             - name: Test Frontend
               run: ./musare.sh test frontend

+ 18 - 2
backend/.eslintrc

@@ -46,6 +46,22 @@
 		"@typescript-eslint/no-empty-function": 0,
 		"@typescript-eslint/no-this-alias": 0,
 		"@typescript-eslint/no-non-null-assertion": 0,
-		"no-void": 0
-	}
+		"no-void": 0,
+		"import/no-extraneous-dependencies": [
+			"error",
+			{
+				"devDependencies": ["**/*.test.ts", "**/*.spec.ts"]
+			}
+		]
+	},
+	"overrides": [
+		{
+			"files": ["**/*.test.ts", "**/*.spec.ts"],
+			"rules": {
+				"no-unused-expressions": "off",
+				"prefer-arrow-callback": "off",
+				"func-names": "off"
+			}
+		}
+	]
 }

文件差异内容过多而无法显示
+ 737 - 17
backend/package-lock.json


+ 10 - 1
backend/package.json

@@ -13,7 +13,8 @@
 		"build": "tsc",
 		"prod": "node build/src/main.js",
 		"lint": "eslint . --ext .js,.ts",
-		"typescript": "tsc --noEmit"
+		"typescript": "tsc --noEmit",
+		"test": "mocha -r ts-node/register 'tests/**/*.test.ts' 'src/**/*.spec.ts'"
 	},
 	"dependencies": {
 		"async": "^3.2.4",
@@ -40,17 +41,25 @@
 	"devDependencies": {
 		"@microsoft/tsdoc": "^0.14.2",
 		"@types/async": "^3.2.15",
+		"@types/chai": "^4.3.4",
 		"@types/config": "^3.3.0",
+		"@types/mocha": "^10.0.0",
 		"@types/object-hash": "^2.2.1",
+		"@types/sinon": "^10.0.13",
+		"@types/sinon-chai": "^3.2.9",
 		"@typescript-eslint/eslint-plugin": "^5.40.0",
 		"@typescript-eslint/parser": "^5.40.0",
+		"chai": "^4.3.7",
 		"eslint": "^8.25.0",
 		"eslint-config-airbnb-base": "^15.0.0",
 		"eslint-config-prettier": "^8.5.0",
 		"eslint-plugin-import": "^2.26.0",
 		"eslint-plugin-prettier": "^4.2.1",
 		"eslint-plugin-tsdoc": "^0.2.17",
+		"mocha": "^10.1.0",
 		"prettier": "2.7.1",
+		"sinon": "^14.0.2",
+		"sinon-chai": "^3.7.0",
 		"trace-unhandled": "^2.0.1",
 		"ts-node": "^10.9.1",
 		"ts-node-dev": "^2.0.0",

+ 2 - 1
backend/src/collections/abc.ts

@@ -1,3 +1,4 @@
+// @ts-nocheck
 import mongoose from "mongoose";
 import { DocumentAttribute, DefaultSchema } from "../types/Collections";
 
@@ -52,7 +53,7 @@ export const schema: AbcCollection = {
 			enabled: {
 				type: Boolean,
 				required: false,
-				restricted: true // TODO: Set to false when empty 2nd layer object fixed
+				restricted: false
 			}
 		}
 	},

+ 86 - 0
backend/src/modules/DataModule.spec.ts

@@ -0,0 +1,86 @@
+// @ts-nocheck
+import async from "async";
+import chai from "chai";
+import sinon from "sinon";
+import sinonChai from "sinon-chai";
+import mongoose from "mongoose";
+import JobContext from "../JobContext";
+import JobQueue from "../JobQueue";
+import LogBook from "../LogBook";
+import ModuleManager from "../ModuleManager";
+import DataModule from "./DataModule";
+
+chai.should();
+chai.use(sinonChai);
+
+describe("Data Module", function () {
+	const moduleManager = Object.getPrototypeOf(
+		sinon.createStubInstance(ModuleManager)
+	);
+	moduleManager.logBook = sinon.createStubInstance(LogBook);
+	moduleManager.jobQueue = sinon.createStubInstance(JobQueue);
+	const dataModule = new DataModule(moduleManager);
+	const jobContext = sinon.createStubInstance(JobContext);
+	const testData = { abc: [] };
+
+	before(async function () {
+		await dataModule.startup();
+		dataModule.redis = sinon.spy(dataModule.redis);
+	});
+
+	beforeEach(async function () {
+		testData.abc = await async.map(Array(10), async () =>
+			dataModule.collections?.abc.model.create({
+				_id: new mongoose.Types.ObjectId(),
+				name: `Test${Math.round(Math.random() * 1000)}`,
+				autofill: {
+					enabled: !!Math.floor(Math.random())
+				},
+				createdAt: Date.now(),
+				updatedAt: Date.now(),
+				testData: true
+			})
+		);
+	});
+
+	it("module loaded and started", function () {
+		moduleManager.logBook.log.should.have.been.called;
+		dataModule.getName().should.equal("data");
+		dataModule.getStatus().should.equal("STARTED");
+	});
+
+	describe("find job", function () {
+		// Run cache test twice to validate mongo and redis sourced data
+		[false, true, true].forEach(useCache => {
+			it(`filter by one _id string ${
+				useCache ? "with" : "without"
+			} cache`, async function () {
+				const [document] = testData.abc;
+
+				const find = await dataModule.find(jobContext, {
+					collection: "abc",
+					filter: { _id: document._id },
+					limit: 1,
+					useCache
+				});
+
+				find.should.be.a("object");
+				find._id.should.deep.equal(document._id);
+				find.createdAt.should.deep.equal(document.createdAt);
+
+				if (useCache) {
+					dataModule.redis?.GET.should.have.been.called;
+				}
+			});
+		});
+	});
+
+	afterEach(async function () {
+		sinon.reset();
+		await dataModule.collections?.abc.model.deleteMany({ testData: true });
+	});
+
+	after(async function () {
+		await dataModule.shutdown();
+	});
+});

+ 1 - 2
backend/src/modules/DataModule.ts

@@ -1,3 +1,4 @@
+// @ts-nocheck
 import async from "async";
 import config from "config";
 import mongoose, { Schema } from "mongoose";
@@ -617,8 +618,6 @@ export default class DataModule extends BaseModule {
 							this.collections![collection].schema.document
 						);
 
-						console.log(222, parsedProjection);
-
 						cacheable = cacheable && parsedProjection.canCache;
 						mongoProjection = parsedProjection.mongoProjection;
 					},

+ 8 - 3
musare.sh

@@ -366,20 +366,25 @@ case $1 in
 
     test)
         echo -e "${CYAN}Musare | Test${NC}"
-        servicesString=$(handleServices "frontend" "${@:2}")
+        servicesString=$(handleServices "backend frontend" "${@:2}")
         if [[ ${servicesString:0:1} == 1 ]]; then
+            if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *backend* ]]; then
+                echo -e "${CYAN}Running backend tests...${NC}"
+                ${dockerCompose} exec -T backend npm run test
+                backendExitValue=$?
+            fi
             if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *frontend* ]]; then
                 echo -e "${CYAN}Running frontend tests...${NC}"
                 ${dockerCompose} exec -T frontend npm run test -- --run
                 frontendExitValue=$?
             fi
-            if [[ ${frontendExitValue} -gt 0 ]]; then
+            if [[ ${backendExitValue} -gt 0 || ${frontendExitValue} -gt 0 ]]; then
                 exitValue=1
             else
                 exitValue=0
             fi
         else
-            echo -e "${RED}${servicesString:2}\n${YELLOW}Usage: $(basename "$0") test [frontend]${NC}"
+            echo -e "${RED}${servicesString:2}\n${YELLOW}Usage: $(basename "$0") test [backend, frontend]${NC}"
             exitValue=1
         fi
         if [[ ${exitValue} -gt 0 ]]; then

部分文件因为文件数量过多而无法显示