diff --git a/src/models/System.ts b/src/models/System.ts index 472f53d..548dc5a 100644 --- a/src/models/System.ts +++ b/src/models/System.ts @@ -2,7 +2,7 @@ import { model, SchemaDefinition, Model as M } from "mongoose"; import { Base, IDoc, IDocRaw, MODIFY_MOTHODS } from "./common"; import newCache = require("@utils/newCache"); -export const FLAG = "system"; +export const FLAG = "systems"; export const cache = newCache(FLAG); diff --git a/src/modules/database/database.providers.ts b/src/modules/database/database.providers.ts index db4af71..a3490af 100644 --- a/src/modules/database/database.providers.ts +++ b/src/modules/database/database.providers.ts @@ -36,13 +36,7 @@ export const connectDatabase = () => { }; export const injectData = async () => { - let num = await UsersModel.count({ }).exec(); - if (num === 0) { - return UsersModel.addUser( - config.defaults.user.name, config.defaults.user.pass - ); - } - num = await UsergroupsModel.count({ }).exec(); + const num = await UsergroupsModel.count({ }).exec(); if (num === 0) { const group = await UsergroupsModel.create({ name: config.defaults.group.name diff --git a/src/modules/goods/goods.controller.ts b/src/modules/goods/goods.controller.ts index b400240..fbe32b8 100644 --- a/src/modules/goods/goods.controller.ts +++ b/src/modules/goods/goods.controller.ts @@ -132,6 +132,7 @@ export class GoodsAdminController { active: true })).toObject(); } catch (error) { + fs.remove(obj.file.path); if (cb) { cb("Good", error); } else { @@ -168,7 +169,7 @@ export class GoodsAdminController { appends: await this.getCategoriesIds(query.append || []) }; - return await this.fileProcess( + return this.fileProcess( { file, uploader: uploaderId, opt: fileProcessOpts }, (type, error) => { if (type === "Categories") { @@ -179,7 +180,7 @@ export class GoodsAdminController { } } if (type === "Good") { - throw new BadRequestException(error.toString()); + throw error; } } ); diff --git a/src/services/base.service.ts b/src/services/base.service.ts index 5f988ce..230afff 100644 --- a/src/services/base.service.ts +++ b/src/services/base.service.ts @@ -43,7 +43,7 @@ abstract class ModelService { return Promise.resolve({ }); } - private runBeforeEach() { + protected runBeforeEach() { return Promise.resolve(this.beforeEach()); } diff --git a/src/services/users.service.ts b/src/services/users.service.ts index 52bcd24..3f6ae86 100644 --- a/src/services/users.service.ts +++ b/src/services/users.service.ts @@ -5,6 +5,7 @@ import { Model as UserUsergroupsModel } from "@models/User-Usergroup"; import { IUsergroups } from "@models/Usergroup"; import { SystemService } from "@services/system"; import { BaseService, IGetOptions } from "@services/base"; +import { config } from "@utils/config"; @Component() export class UsersService extends BaseService { @@ -15,7 +16,26 @@ export class UsersService extends BaseService { this.setModel(UsersModel); } + protected async beforeEach() { + const num = await cache.get("total") || + await UsersModel.count({ }).exec(); + if (num !== 0) { + return; + } + const user = await UsersModel.addUser( + config.defaults.user.name, config.defaults.user.pass + ); + const gid = await this.sysSvr.getDefaultUsergroup(); + if (gid) { + await UserUsergroupsModel.create({ + user: user._id, usergroup: gid + }); + } + } + public async addUser(obj, gid?: ObjectId) { + await this.runBeforeAll(); + await this.runBeforeEach(); try { const user = await UsersModel.addUser(obj.username, obj.password); if (!gid) { @@ -40,6 +60,8 @@ export class UsersService extends BaseService { } public async isVaild(username: string, password: string) { + await this.runBeforeAll(); + await this.runBeforeEach(); try { return await UsersModel.isVaild(username, password); } catch (err) { @@ -54,6 +76,8 @@ export class UsersService extends BaseService { public async getUsergroups( uid: ObjectId, pageObj = this.DEF_PER_OBJ ) { + await this.runBeforeAll(); + await this.runBeforeEach(); const perNum = pageObj.perNum || this.DEF_PER_OBJ.perNum; const page = pageObj.page || this.DEF_PER_OBJ.page; const groups = await UserUsergroupsModel diff --git a/test/api/collections/collections_token.e2e.ts b/test/api/collections/collections_token.e2e.ts index e48131c..8e6a80f 100644 --- a/test/api/collections/collections_token.e2e.ts +++ b/test/api/collections/collections_token.e2e.ts @@ -1,21 +1,16 @@ -import supertest = require("supertest"); import faker = require("faker"); -import { basename } from "path"; -import fs = require("fs-extra"); -import { Model as TokensModel } from "@models/Token"; -import { config } from "@utils/config"; -import { Model as GoodsModels } from "@models/Good"; import { - connect, drop, newUser, addCategoryAndRegexp + connect, drop, addCategoryAndRegexp } from "../../helpers/database"; import { init } from "../../helpers/server"; -import { uploadFiles, newFile } from "../../helpers/files"; import { newIds } from "../../helpers/utils"; +import { TokenRequest, GuestRequest } from "../../helpers/request"; +import * as files from "../../helpers/files"; describe("Token to Upload Files Api", () => { - let request: supertest.SuperTest; + let request: TokenRequest; before(() => { return connect(); @@ -27,30 +22,23 @@ describe("Token to Upload Files Api", () => { return drop(ids); }); - before(async () => { - request = await init(); + const filepaths = [ ]; + + after(() => { + return files.remove(filepaths); + }); + + before("login", async () => { + const req = new GuestRequest(await init(), ids, filepaths); + request = await req.loginWithToken(); }); const FILE_COUNST = 10; - const filepaths = [ ]; const prefix = `${faker.random.word()}_`; before(async () => { // Generator Files for (let i = 0; i < FILE_COUNST; i++) { - filepaths.push(await newFile(`${prefix}${faker.random.uuid()}`)); - } - }); - - after(async () => { - for (const filepath of filepaths) { - fs.removeSync(filepath); - const good = (await GoodsModels.findOne({ - originname: basename(filepath) - }).exec()).toObject(); - fs.removeSync( - `${config.paths.upload}/${good.category}/${good.filename}` - ); - await GoodsModels.findByIdAndRemove(good._id).exec(); + await request.newFile(`${prefix}${faker.random.uuid()}`); } }); @@ -62,37 +50,11 @@ describe("Token to Upload Files Api", () => { ids.regexps.push(docs[1]._id); }); - const user = { - name: faker.name.firstName(), - pass: faker.random.words(), - token: "" - }; - step("Login", async () => { - const doc = await newUser(user.name, user.pass); - ids.users.push(doc._id); - const { - body: result - } = await request.post("/api/v1/auth/login?token=true") - .send({ - username: user.name, password: user.pass - }).then(); - result.should.have.property("token"); - ids.tokens.push( - (await TokensModel.findOne({ token: result.token }).exec())._id - ); - user.token = result.token; - }); - - step("Logout", () => { - return request.post("/api/v1/auth/logout").then(); - }); - let name = ""; step("Upload Files", async () => { const { body: result, status - } = await uploadFiles(request, filepaths); - ids.collections.push(result._id); + } = await request.uploadFiles(filepaths); status.should.be.eql(201); result.should.have.properties("name", "_id", "goods"); name = result.name; diff --git a/test/api/system/system.e2e.ts b/test/api/system/system.e2e.ts index f93c07b..3ba66da 100644 --- a/test/api/system/system.e2e.ts +++ b/test/api/system/system.e2e.ts @@ -1,34 +1,26 @@ import { Model as SystemModel } from "@models/System"; -import supertest = require("supertest"); -import { - connect, drop -} from "../../helpers/database"; +import { connect, drop } from "../../helpers/database"; import { init } from "../../helpers/server"; import auth = require("@db/auth"); -import { newName } from "../../helpers/utils"; +import { newName, newIds } from "../../helpers/utils"; +import { AdminRequest, GuestRequest } from "../../helpers/request"; -describe("Collections E2E Api", () => { +describe("System E2E Api", () => { - let request: supertest.SuperTest; + let request: AdminRequest; before(() => { return connect(); }); - const ids = { - users: [ ] - }; + const ids = newIds(); after(() => { return drop(ids); }); - before(async () => { - request = await init(); - }); - before("login", async () => { - ids.users.push((await auth.login(request))[0]); + request = await new GuestRequest(await init(), ids).login(); }); after(async () => { diff --git a/test/helpers/database/user.ts b/test/helpers/database/user.ts index c7d0fee..a3db8d9 100644 --- a/test/helpers/database/user.ts +++ b/test/helpers/database/user.ts @@ -20,8 +20,7 @@ export const newUser = (username?: string, password?: string) => { export const newUserWithUsergroup = ( username = newName(), password = newName(), gid?: ObjectId ) => { - init(); - return usersSvr.addUser({ + return init().addUser({ username, password }, gid); }; diff --git a/test/helpers/files.ts b/test/helpers/files.ts index acbee9f..e7b4822 100644 --- a/test/helpers/files.ts +++ b/test/helpers/files.ts @@ -5,16 +5,16 @@ import faker = require("faker"); import fs = require("fs-extra"); import { sleep } from "./utils"; -interface IUploadFileOptions { +export interface IUploadFileOptions { query?: { [key: string]: string }; } /* tslint:disable:no-empty-interface */ -interface IUploadFilesOptions extends IUploadFileOptions { } +export interface IUploadFilesOptions extends IUploadFileOptions { } -const addQuery = (url: string, opts: IUploadFileOptions) => { +export const addQuery = (url: string, opts: IUploadFileOptions) => { if (opts.query && Object.keys(opts.query).length > 0) { const query = [ ]; for (const key of Object.keys(opts.query)) { diff --git a/test/helpers/request.ts b/test/helpers/request.ts new file mode 100644 index 0000000..83c4485 --- /dev/null +++ b/test/helpers/request.ts @@ -0,0 +1,195 @@ +import supertest = require("supertest"); +import auth = require("@db/auth"); +import { IIds } from "./database"; +import { newUser } from "@db/user"; +import { Model as TokensModel } from "@models/Token"; +import { isNumber } from "util"; +import { newName } from "./utils"; +import { + IUploadFileOptions, addQuery, IUploadFilesOptions, newFile +} from "./files"; + +type ST = supertest.SuperTest; + +class BaseRequest { + + constructor( + protected readonly req: ST, + protected readonly ids: IIds, + protected readonly filepaths: string[] = [ ] + ) { } + + public get(url: string, callback?) { + return this.req.get(url, callback); + } + + public post(url: string, callback?) { + return this.req.post(url, callback); + } + + public put(url: string, callback?) { + return this.req.put(url, callback); + } + + public delete(url: string, callback?) { + return this.req.delete(url, callback); + } + + public getIds() { + return this.ids; + } + + public getFilepaths() { + return this.filepaths; + } + + protected users = [ ]; + + public async newUser(username = newName(), password = newName()) { + const user = await newUser(username, password); + this.users.push({ username, password }); + this.ids.users.push(user._id); + return this; + } + + protected newFilepaths: string[] = [ ]; + + public async newFile(filename?: string) { + const filepath = await newFile(filename); + this.filepaths.push(filepath); + this.newFilepaths.push(filepath); + return this; + } + +} + +export class GuestRequest extends BaseRequest { + + public async login( + username?: string | number, password?: string + ): Promise { + const index = isNumber(username) ? username : -1; + if (index !== -1 && (this.users.length - 1 >= index)) { + const user = this.users[0]; + await this.req.post("/api/v1/auth/login").send(user).then(); + } else { + return (await this.newUser()).login(this.users.length - 1); + } + return new AdminRequest(this.req, this.ids, this.filepaths); + } + + public async loginWithToken( + username?: string | number, password?: string + ): Promise { + const index = isNumber(username) ? username : -1; + if (index !== -1 && (this.users.length - 1 >= index)) { + const user = this.users[0]; + const { body } = + await this.req.post("/api/v1/auth/login?token=true") + .send(user).then(); + const token = + await TokensModel.findOne({ token: body.token }).exec(); + this.ids.tokens.push(token._id); + return new TokenRequest( + this.req, user.username, body.token, this.ids, this.filepaths + ); + } else { + return (await this.newUser()).loginWithToken(this.users.length - 1); + } + } + +} + +class LoginedRequest extends BaseRequest { + + public async logout() { + await this.get("/api/v1/auth/logout").then(); + return new GuestRequest(this.req, this.ids, this.filepaths); + } + + public async uploadFile(filepath?: string, opts: IUploadFileOptions = { }) { + let url = "/api/v1/goods"; + url = addQuery(url, opts); + + if (!filepath) { + if (this.filepaths.length === 0) { + await this.newFile(); + } + filepath = this.newFilepaths[this.newFilepaths.length - 1]; + } else if (this.filepaths.indexOf(filepath) > -1) { + this.filepaths.push(filepath); + } + + return this.post(url).attach("file", filepath).then((ref) => { + const { status, body } = ref; + if (status === 201 ) { + this.ids.goods.push(body._id); + } + return ref; + }); + } + + public async uploadFiles( + filepaths: string[], opts: IUploadFilesOptions = { } + ) { + let url = "/api/v1/goods/collections"; + url = addQuery(url, opts); + + let req = this.post(url); + filepaths.forEach((filepath) => { + if (this.filepaths.indexOf(filepath) > -1) { + this.filepaths.push(filepath); + } + req = req.attach("files", filepath); + }); + return req.then().then((ref) => { + const { status, body } = ref; + + if (status === 201 ) { + body.goods.forEach((good) => { + this.ids.goods.push(good._id); + }); + this.ids.collections.push(body._id); + } + return ref; + }); + } +} + +export class AdminRequest extends LoginedRequest { + +} + +export class TokenRequest extends LoginedRequest { + + private readonly auth; + + constructor( + req: ST, username: string, token: string, + ids: IIds, filepaths?: string[] + ) { + super(req, ids, filepaths); + this.auth = { username, token }; + } + + public get(url: string, callback?) { + return super.get(url, callback) + .auth(this.auth.username, this.auth.token); + } + + public post(url: string, callback?) { + return super.post(url, callback) + .auth(this.auth.username, this.auth.token); + } + + public put(url: string, callback?) { + return super.put(url, callback) + .auth(this.auth.username, this.auth.token); + } + + public delete(url: string, callback?) { + return super.delete(url, callback) + .auth(this.auth.username, this.auth.token); + } + +} diff --git a/test/issues/ban_user_n_its_token.e2e.ts b/test/issues/ban_user_n_its_token.e2e.ts index 9fa20d0..d33a1cf 100644 --- a/test/issues/ban_user_n_its_token.e2e.ts +++ b/test/issues/ban_user_n_its_token.e2e.ts @@ -1,16 +1,13 @@ -import supertest = require("supertest"); - -import { connect, drop, newUser } from "../helpers/database"; +import { connect, drop } from "../helpers/database"; import { init } from "../helpers/server"; import { UsersService } from "@services/users"; -import { TokensService } from "@services/tokens"; import { SystemService } from "@services/system"; -import { newName, newIds } from "../helpers/utils"; +import { newIds } from "../helpers/utils"; +import { TokenRequest, GuestRequest } from "../helpers/request"; describe("Fix Issues", () => { - let request: supertest.SuperTest; - const tokensSvr = new TokensService(); + let request: TokenRequest; const usersSvr = new UsersService(new SystemService()); before(() => { @@ -23,34 +20,14 @@ describe("Fix Issues", () => { return drop(ids); }); - before(async () => { - request = await init(); + before("Login", async () => { + request = await new GuestRequest(await init(), ids).loginWithToken(); }); - const user = { - name: newName(), - pass: newName(), - token: "" - }; describe("Token Action When User ban", () => { - step("Login", async () => { - const doc = await newUser(user.name, user.pass); - ids.users.push(doc._id); - const { - body: result - } = await request.post("/api/v1/auth/login?token=true") - .send({ - username: user.name, password: user.pass - }).then(); - result.should.have.property("token"); - ids.tokens.push(await tokensSvr.getIdByToken(result.token)); - user.token = result.token; - }); - step("Get Goods Success By Token", async () => { - const { status } = await request.get("/api/v1/users/goods") - .auth(user.name, user.token).then(); + const { status } = await request.get("/api/v1/users/goods").then(); status.should.be.eql(200); }); @@ -59,8 +36,7 @@ describe("Fix Issues", () => { }); step("Get Goods Fail By Token", async () => { - const { status } = await request.get("/api/v1/users/goods") - .auth(user.name, user.token).then(); + const { status } = await request.get("/api/v1/users/goods").then(); status.should.be.eql(403); }); @@ -69,8 +45,7 @@ describe("Fix Issues", () => { }); step("Get Goods Fail By Token", async () => { - const { status } = await request.get("/api/v1/users/goods") - .auth(user.name, user.token).then(); + const { status } = await request.get("/api/v1/users/goods").then(); status.should.be.eql(200); }); diff --git a/test/issues/github/github_issue_31.e2e.ts b/test/issues/github/github_issue_31.e2e.ts index 7eaf7d8..287aedd 100644 --- a/test/issues/github/github_issue_31.e2e.ts +++ b/test/issues/github/github_issue_31.e2e.ts @@ -1,63 +1,50 @@ -import supertest = require("supertest"); import fs = require("fs-extra"); import { basename } from "path"; -import { Model as GoodsModels } from "@models/Good"; import { - connect, drop, newUser, addCategoryAndRegexp + connect, drop, addCategoryAndRegexp } from "../../helpers/database"; import { init } from "../../helpers/server"; import * as files from "../../helpers/files"; -import { config } from "@utils/config"; -import auth = require("@db/auth"); import { newIds } from "../../helpers/utils"; +import { AdminRequest, GuestRequest } from "../../helpers/request"; /** * Fix [Issue 31](https://github.com/BoxSystem/StoreBox-Api/issues/31) */ describe("Fix Issues", () => { - let request: supertest.SuperTest; + let request: AdminRequest; before(() => { return connect(); }); const ids = newIds(); + const filepaths = [ ]; after(() => { return drop(ids); }); - before(async () => { - request = await init(); + before("login", async () => { + request = await new GuestRequest(await init(), ids, filepaths).login(); }); - describe("Github 31 [Can upload same file]", () => { - - let filepath = ""; - let filename = ""; - before(async () => { - filepath = await files.newFile(); - }); - - after(() => { - return files.remove(filepath); - }); + before(async () => { + await request.newFile(); + }); - after(() => { - GoodsModels.remove({ - originname: filename - }).exec(); - }); + after(() => { + return files.remove(filepaths); + }); - before("login", async () => { - ids.users.push((await auth.login(request))[0]); - }); + describe("Github 31 [Can upload same file]", () => { step("Add Category and Regexp", async () => { - filename = basename(filepath); + const filepath = filepaths[filepaths.length - 1]; + const filename = basename(filepath); const docs = await addCategoryAndRegexp( new RegExp(`^${filename}$`) ); @@ -66,16 +53,12 @@ describe("Fix Issues", () => { }); step("Upload Success", async () => { - const { - body: result, status - } = await files.uploadFile(request, filepath); + const { status } = await request.uploadFile(); status.should.be.eql(201); }); step("Upload Fail", async () => { - const { - body: result, status - } = await files.uploadFile(request, filepath); + const { status, body } = await request.uploadFile(); status.should.be.not.eql(201); status.should.be.eql(400); }); diff --git a/test/models/user.spec.ts b/test/models/user.spec.ts index d750d6c..3124b37 100644 --- a/test/models/user.spec.ts +++ b/test/models/user.spec.ts @@ -2,7 +2,7 @@ import * as db from "../helpers/database"; import * as md5 from "md5"; import { Model as UsersModel } from "@models/User"; import { Observer, Observable, Subject } from "rxjs"; -import { newIds } from "../helpers/utils"; +import { newIds, newName } from "../helpers/utils"; describe("User Model", () => { @@ -23,8 +23,8 @@ describe("User Model", () => { }); beforeEach(() => { - user.username = md5(Date.now() + ""); - user.password = md5(Date.now() + ""); + user.username = newName(); + user.password = newName(); return UsersModel.addUser(user.username, user.password) .then((result) => { user.id = result._id.toString(); @@ -32,16 +32,10 @@ describe("User Model", () => { }).catch(console.log); }); - afterEach(() => { - return UsersModel.removeUser(user.id).then(() => { - user.id = ""; - }); - }); - it("Add User", async () => { const user = { - username: md5(Date.now() + ""), - password: md5(Date.now() + ""), + username: newName(), + password: newName(), }; let result; // 添加测试用户 @@ -58,6 +52,7 @@ describe("User Model", () => { UsersModel.removeUser(id); }); + // Mothod move to service it.skip("User List", async () => { // const results = await UsersModel.list(); // results.should.be.an.Array(); diff --git a/test/services/collections.spec.ts b/test/services/collections.spec.ts index f6e4478..579b468 100644 --- a/test/services/collections.spec.ts +++ b/test/services/collections.spec.ts @@ -1,4 +1,6 @@ import { CollectionsService } from "@services/collections"; +import { UsersService } from "@services/users"; +import { SystemService } from "@services/system"; import { Model as UsersModel } from "@models/User"; import db = require("../helpers/database"); import { newName } from "../helpers/utils"; @@ -6,13 +8,16 @@ import { newName } from "../helpers/utils"; describe("Collections Service Test Unit", () => { let collectionsSvr: CollectionsService; + let usersSvr: UsersService; before(() => { return db.connect(); }); - beforeEach(() => { + beforeEach(async () => { collectionsSvr = new CollectionsService(); + usersSvr = new UsersService(new SystemService()); + await usersSvr.conut(); // UserModel Init }); it("Fail to Create a Collection with Empty Good # 0", async () => {