Skip to content

Commit

Permalink
feat: midway-mock支持applicationContext获取ctx依赖注入,支持mock IoC容器中的对象方法
Browse files Browse the repository at this point in the history
  • Loading branch information
kurten committed Jan 25, 2019
1 parent 4dda68b commit 4f07c6d
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 56 deletions.
8 changes: 4 additions & 4 deletions package.json
Expand Up @@ -8,20 +8,20 @@
"@types/mocha": "^5.2.5",
"@types/node": "^10.12.18",
"autocannon": "^2.4.1",
"chalk": "^2.4.1",
"chalk": "^2.4.2",
"debug": "^4.1.1",
"gh-pages": "^1.2.0",
"git-hooks": "^1.1.10",
"lerna": "^3.4.3",
"lerna": "^3.10.7",
"lerna-relinker": "^1.4.0",
"node-ab": "0.0.6",
"opencollective-postinstall": "^2.0.1",
"opencollective": "^1.0.3",
"opencollective-postinstall": "^2.0.1",
"tree-kill": "^1.2.0",
"tslint": "^5.12.0",
"typedoc": "^0.11.1",
"typescript": "^3.2.0",
"vuepress": "^0.14.2"
"vuepress": "^0.14.8"
},
"scripts": {
"autod": "lerna run autod",
Expand Down
3 changes: 1 addition & 2 deletions packages/context/src/base/Resource.ts
Expand Up @@ -5,7 +5,6 @@ import { existsSync,
readdirSync
} from 'fs';
import { resolve, parse, dirname, join } from 'path';
import * as _ from 'lodash';
import { IResource } from '../interfaces';

export class Resource implements IResource {
Expand Down Expand Up @@ -67,7 +66,7 @@ export class Resource implements IResource {
getSubResources(): IResource[] {
if (this.isDir()) {
const files: string[] = readdirSync(this.getPath());
const arr = _.map(files, file => {
const arr = files.map(file => {
return new Resource(this.getPath(), file);
});

Expand Down
89 changes: 47 additions & 42 deletions packages/context/src/factory/common/ManagedResolverFactory.ts
Expand Up @@ -26,15 +26,6 @@ import { ObjectConfiguration } from '../../base/Configuration';
import { Autowire } from './Autowire';
import { NotFoundError } from '../../utils/errorFactory';


// 基础模版,用于 {{xxx.xx}} 这种形式的属性注入
function tpl(s: string, props: any): string {
return _.template(s, {
// use `{{` and `}}` as delimiters
interpolate: /{{([\s\S]+?)}}/g
})(props);
}

/**
* 所有解析器基类
*/
Expand All @@ -49,11 +40,11 @@ class BaseManagedResolver implements IManagedResolver {
throw new Error('not implement');
}

resolve(managed: IManagedInstance, props: any): any {
resolve(managed: IManagedInstance): any {
throw new Error('not implement');
}

async resolveAsync(managed: IManagedInstance, props: any): Promise<any> {
async resolveAsync(managed: IManagedInstance): Promise<any> {
throw new Error('not implement');
}
}
Expand All @@ -66,13 +57,13 @@ class JSONResolver extends BaseManagedResolver {
return KEYS.JSON_ELEMENT;
}

resolve(managed: IManagedInstance, props: any): any {
resolve(managed: IManagedInstance): any {
const mjson = <ManagedJSON>managed;
return JSON.parse(tpl(mjson.value, props));
return JSON.parse(this._factory.tpl(mjson.value));
}

async resolveAsync(managed: IManagedInstance, props: any): Promise<any> {
return this.resolve(managed, props);
async resolveAsync(managed: IManagedInstance): Promise<any> {
return this.resolve(managed);
}
}

Expand All @@ -89,40 +80,40 @@ class ValueResolver extends BaseManagedResolver {
* @param managed 类型接口
* @param props 注入的属性值
*/
_resolveCommon(managed: IManagedInstance, props: any): any {
_resolveCommon(managed: IManagedInstance): any {
const mv = <ManagedValue>managed;
switch (mv.valueType) {
case VALUE_TYPE.STRING:
case VALUE_TYPE.TEMPLATE:
return tpl(mv.value, props);
return this._factory.tpl(mv.value);
case VALUE_TYPE.NUMBER:
return Number(tpl(mv.value, props));
return Number(this._factory.tpl(mv.value));
case VALUE_TYPE.INTEGER:
return parseInt(tpl(mv.value, props), 10);
return parseInt(this._factory.tpl(mv.value), 10);
case VALUE_TYPE.DATE:
return new Date(tpl(mv.value, props));
return new Date(this._factory.tpl(mv.value));
case VALUE_TYPE.BOOLEAN:
return mv.value === 'true';
}

return mv.value;
}

resolve(managed: IManagedInstance, props: any): any {
resolve(managed: IManagedInstance): any {
const mv = <ManagedValue>managed;
if (mv.valueType === VALUE_TYPE.MANAGED) {
return this._factory.resolveManaged(mv.value);
} else {
return this._resolveCommon(managed, props);
return this._resolveCommon(managed);
}
}

async resolveAsync(managed: IManagedInstance, props: any): Promise<any> {
async resolveAsync(managed: IManagedInstance): Promise<any> {
const mv = <ManagedValue>managed;
if (mv.valueType === VALUE_TYPE.MANAGED) {
return await this._factory.resolveManagedAsync(mv.value);
} else {
return this._resolveCommon(managed, props);
return this._resolveCommon(managed);
}
}
}
Expand All @@ -135,14 +126,14 @@ class RefResolver extends BaseManagedResolver {
return KEYS.REF_ELEMENT;
}

resolve(managed: IManagedInstance, props: any): any {
resolve(managed: IManagedInstance): any {
const mr = <ManagedReference>managed;
return this._factory.context.get(mr.name, null);
return this._factory.context.get(mr.name);
}

async resolveAsync(managed: IManagedInstance, props: any): Promise<any> {
async resolveAsync(managed: IManagedInstance): Promise<any> {
const mr = <ManagedReference>managed;
return await this._factory.context.getAsync(mr.name, null);
return await this._factory.context.getAsync(mr.name);
}
}

Expand All @@ -154,7 +145,7 @@ class ListResolver extends BaseManagedResolver {
return KEYS.LIST_ELEMENT;
}

resolve(managed: IManagedInstance, props: any): any {
resolve(managed: IManagedInstance): any {
const ml = <ManagedList>managed;
const arr = [];
for (let i = 0; i < ml.length; i++) {
Expand All @@ -163,7 +154,7 @@ class ListResolver extends BaseManagedResolver {
return arr;
}

async resolveAsync(managed: IManagedInstance, props: any): Promise<any> {
async resolveAsync(managed: IManagedInstance): Promise<any> {
const ml = <ManagedList>managed;
const arr = [];
for (let i = 0; i < ml.length; i++) {
Expand All @@ -181,7 +172,7 @@ class SetResolver extends BaseManagedResolver {
return KEYS.SET_ELEMENT;
}

resolve(managed: IManagedInstance, props: any): any {
resolve(managed: IManagedInstance): any {
const ms = <ManagedSet>managed;
const s = new Set();
for (let item of ms) {
Expand All @@ -190,7 +181,7 @@ class SetResolver extends BaseManagedResolver {
return s;
}

async resolveAsync(managed: IManagedInstance, props: any): Promise<any> {
async resolveAsync(managed: IManagedInstance): Promise<any> {
const ms = <ManagedSet>managed;
const s = new Set();
for (let item of ms) {
Expand All @@ -208,7 +199,7 @@ class MapResolver extends BaseManagedResolver {
return KEYS.MAP_ELEMENT;
}

resolve(managed: IManagedInstance, props: any): any {
resolve(managed: IManagedInstance): any {
const mm = <ManagedMap>managed;
const m = new Map();
for (let key of mm.keys()) {
Expand All @@ -217,7 +208,7 @@ class MapResolver extends BaseManagedResolver {
return m;
}

async resolveAsync(managed: IManagedInstance, props: any): Promise<any> {
async resolveAsync(managed: IManagedInstance): Promise<any> {
const mm = <ManagedMap>managed;
const m = new Map();
for (let key of mm.keys()) {
Expand All @@ -235,7 +226,7 @@ class PropertiesResolver extends BaseManagedResolver {
return KEYS.PROPS_ELEMENT;
}

resolve(managed: IManagedInstance, props: any): any {
resolve(managed: IManagedInstance): any {
const m = <ManagedProperties>managed;
const cfg = new ObjectConfiguration();
const keys = m.keys();
Expand All @@ -246,7 +237,7 @@ class PropertiesResolver extends BaseManagedResolver {
return cfg;
}

async resolveAsync(managed: IManagedInstance, props: any): Promise<any> {
async resolveAsync(managed: IManagedInstance): Promise<any> {
const m = <ManagedProperties>managed;
const cfg = new ObjectConfiguration();
const keys = m.keys();
Expand All @@ -266,12 +257,12 @@ class PropertyResolver extends BaseManagedResolver {
return KEYS.PROPERTY_ELEMENT;
}

resolve(managed: IManagedInstance, props: any): any {
resolve(managed: IManagedInstance): any {
const mp = <ManagedProperty>managed;
return this._factory.resolveManaged(mp.value);
}

async resolveAsync(managed: IManagedInstance, props: any): Promise<any> {
async resolveAsync(managed: IManagedInstance): Promise<any> {
const mp = <ManagedProperty>managed;
return await this._factory.resolveManagedAsync(mp.value);
}
Expand All @@ -285,12 +276,12 @@ class ObjectResolver extends BaseManagedResolver {
return KEYS.OBJECT_ELEMENT;
}

resolve(managed: IManagedInstance, props: any): any {
resolve(managed: IManagedInstance): any {
const mo = <ManagedObject>managed;
return this._factory.create(mo.definition, null);
}

async resolveAsync(managed: IManagedInstance, props: any): Promise<any> {
async resolveAsync(managed: IManagedInstance): Promise<any> {
const mo = <ManagedObject>managed;
return await this._factory.createAsync(mo.definition, null);
}
Expand Down Expand Up @@ -328,6 +319,20 @@ export class ManagedResolverFactory {
}
return this._props;
}
/**
* 用于解析模版化的值
* example: {{aaa.bbb.ccc}}
* @param value 配置的模版值
*/
tpl(value) {
if (value && value.indexOf('{{') > -1) {
return _.template(value, {
// use `{{` and `}}` as delimiters
interpolate: /{{([\s\S]+?)}}/g
})(this.props);
}
return value;
}

registerResolver(resolver: IManagedResolver) {
this.resolvers.set(resolver.type, resolver);
Expand All @@ -337,14 +342,14 @@ export class ManagedResolverFactory {
if (!this.resolvers.has(managed.type)) {
throw new Error(`${managed.type} resolver is not exists!`);
}
return this.resolvers.get(managed.type).resolve(managed, this.props);
return this.resolvers.get(managed.type).resolve(managed);
}

async resolveManagedAsync(managed: IManagedInstance): Promise<any> {
if (!this.resolvers.has(managed.type)) {
throw new Error(`${managed.type} resolver is not exists!`);
}
return await this.resolvers.get(managed.type).resolveAsync(managed, this.props);
return await this.resolvers.get(managed.type).resolveAsync(managed);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/context/src/interfaces.ts
Expand Up @@ -158,8 +158,8 @@ export interface IManagedInstance {
*/
export interface IManagedResolver {
type: string;
resolve(managed: IManagedInstance, props: any): any;
resolveAsync(managed: IManagedInstance, props: any): Promise<any>;
resolve(managed: IManagedInstance): any;
resolveAsync(managed: IManagedInstance): Promise<any>;
}

export interface ObjectDefinitionOptions {
Expand Down
26 changes: 20 additions & 6 deletions packages/midway-core/src/container.ts
Expand Up @@ -109,16 +109,16 @@ class LoggerResolver implements IManagedResolver {
return TYPE_LOGGER;
}

resolve(managed: IManagedInstance, props: any): any {
resolve(managed: IManagedInstance): any {
const log: ManagedLogger = <ManagedLogger>managed;
if (log.name) {
return this.container.handlerMap.get(MidwayHandlerKey.LOGGER)(log.name);
}
return this.container.handlerMap.get(MidwayHandlerKey.LOGGER)(log.type);
}

async resolveAsync(managed: IManagedInstance, props: any): Promise<any> {
return this.resolve(managed, props);
async resolveAsync(managed: IManagedInstance): Promise<any> {
return this.resolve(managed);
}
}

Expand Down Expand Up @@ -150,20 +150,22 @@ class PluginResolver implements IManagedResolver {
return TYPE_PLUGIN;
}

resolve(managed: IManagedInstance, props: any): any {
resolve(managed: IManagedInstance): any {
const p = <ManagedPlugin>managed;
return this.container.handlerMap.get(MidwayHandlerKey.PLUGIN)(p.name);
}

async resolveAsync(managed: IManagedInstance, props: any): Promise<any> {
return this.resolve(managed, props);
async resolveAsync(managed: IManagedInstance): Promise<any> {
return this.resolve(managed);
}
}

export class MidwayContainer extends Container implements IContainer {
controllersIds: Array<string> = [];
middlewaresIds: Array<string> = [];
handlerMap: Map<string, (handlerKey: string) => any>;
// 仅仅用于兼容requestContainer的ctx
ctx = {};

init(): void {
this.handlerMap = new Map();
Expand All @@ -179,6 +181,18 @@ export class MidwayContainer extends Container implements IContainer {
this.parser.registerParser(new MiddlewareDefinitionParser(this));

this.registerEachCreatedHook();

// 防止直接从applicationContext.getAsync or get对象实例时依赖当前上下文信息出错
// ctx is in requestContainer
this.registerObject('ctx', this.ctx);
}
/**
* update current context in applicationContext
* for mock and other case
* @param ctx ctx
*/
updateContext(ctx) {
this.ctx = Object.assign({}, ctx || {});
}

/**
Expand Down
8 changes: 8 additions & 0 deletions packages/midway-mock/bootstrap.js
Expand Up @@ -6,6 +6,14 @@ const mock = require('./dist').mm;
const options = {};
const app = mock.app(options);

app.mockClassFunction = (className, methodName, fn) => {
const def = app.applicationContext.registry.getDefinition(className);
const clazz = def.path;
if (clazz && typeof clazz === 'function') {
app._mockFn(clazz.prototype, methodName, fn);
}
};

before(() => app.ready());
afterEach(mock.restore);

Expand Down
4 changes: 4 additions & 0 deletions packages/midway-mock/src/interface.ts
Expand Up @@ -9,4 +9,8 @@ export interface MidwayApplicationOptions {
}

export interface MidwayMockApplication extends MockApplication {
/**
* Mock class function
*/
mockClassFunction(className: string, methodName: string, fn: any): any;
}

0 comments on commit 4f07c6d

Please sign in to comment.