423 lines
12 KiB
JavaScript
423 lines
12 KiB
JavaScript
const projectModel = require('../models/project.js');
|
|
const interfaceColModel = require('../models/interfaceCol.js');
|
|
const interfaceCaseModel = require('../models/interfaceCase.js');
|
|
const interfaceModel = require('../models/interface.js');
|
|
const interfaceCatModel = require('../models/interfaceCat.js');
|
|
const followModel = require('../models/follow.js');
|
|
const userModel = require('../models/user.js');
|
|
const yapi = require('../yapi.js');
|
|
const baseController = require('./base.js');
|
|
const {
|
|
handleParams,
|
|
crossRequest,
|
|
handleCurrDomain,
|
|
checkNameIsExistInArray
|
|
} = require('../../common/postmanLib');
|
|
const { handleParamsValue, ArrayToObject } = require('../../common/utils.js');
|
|
const renderToHtml = require('../utils/reportHtml');
|
|
const HanldeImportData = require('../../common/HandleImportData');
|
|
const _ = require('underscore');
|
|
const createContex = require('../../common/createContext')
|
|
|
|
/**
|
|
* {
|
|
* postman: require('./m')
|
|
* }
|
|
*/
|
|
const importDataModule = {};
|
|
|
|
class openController extends baseController {
|
|
constructor(ctx) {
|
|
super(ctx);
|
|
this.projectModel = yapi.getInst(projectModel);
|
|
this.interfaceColModel = yapi.getInst(interfaceColModel);
|
|
this.interfaceCaseModel = yapi.getInst(interfaceCaseModel);
|
|
this.interfaceModel = yapi.getInst(interfaceModel);
|
|
this.interfaceCatModel = yapi.getInst(interfaceCatModel);
|
|
this.followModel = yapi.getInst(followModel);
|
|
this.userModel = yapi.getInst(userModel);
|
|
this.handleValue = this.handleValue.bind(this);
|
|
this.schemaMap = {
|
|
runAutoTest: {
|
|
'*id': 'number',
|
|
project_id: 'string',
|
|
token: 'string',
|
|
mode: {
|
|
type: 'string',
|
|
default: 'html'
|
|
},
|
|
email: {
|
|
type: 'boolean',
|
|
default: false
|
|
},
|
|
download: {
|
|
type: 'boolean',
|
|
default: false
|
|
},
|
|
closeRemoveAdditional: true
|
|
},
|
|
importData: {
|
|
'*type': 'string',
|
|
url: 'string',
|
|
'*token': 'string',
|
|
json: 'string',
|
|
project_id: 'string',
|
|
merge: {
|
|
type: 'string',
|
|
default: 'normal'
|
|
}
|
|
}
|
|
};
|
|
yapi.emitHook('import_data', importDataModule);
|
|
}
|
|
|
|
async importData(ctx) {
|
|
let type = ctx.params.type;
|
|
let content = ctx.params.json;
|
|
let project_id = ctx.params.project_id;
|
|
let dataSync = ctx.params.merge;
|
|
|
|
let warnMessage = ''
|
|
|
|
/**
|
|
* 因为以前接口文档写错了,做下兼容
|
|
*/
|
|
try{
|
|
if(!dataSync &&ctx.params.dataSync){
|
|
warnMessage = 'importData Api 已废弃 dataSync 传参,请联系管理员将 dataSync 改为 merge.'
|
|
dataSync = ctx.params.dataSync
|
|
}
|
|
}catch(e){}
|
|
|
|
let token = ctx.params.token;
|
|
if (!type || !importDataModule[type]) {
|
|
return (ctx.body = yapi.commons.resReturn(null, 40022, '不存在的导入方式'));
|
|
}
|
|
|
|
if (!content && !ctx.params.url) {
|
|
return (ctx.body = yapi.commons.resReturn(null, 40022, 'json 或者 url 参数,不能都为空'));
|
|
}
|
|
try {
|
|
let request = require("request");// let Promise = require('Promise');
|
|
let syncGet = function (url){
|
|
return new Promise(function(resolve, reject){
|
|
request.get({url : url}, function(error, response, body){
|
|
if(error){
|
|
reject(error);
|
|
}else{
|
|
resolve(body);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
if(ctx.params.url){
|
|
content = await syncGet(ctx.params.url);
|
|
}else if(content.indexOf('http://') === 0 || content.indexOf('https://') === 0){
|
|
content = await syncGet(content);
|
|
}
|
|
content = JSON.parse(content);
|
|
} catch (e) {
|
|
return (ctx.body = yapi.commons.resReturn(null, 40022, 'json 格式有误:' + e));
|
|
}
|
|
|
|
let menuList = await this.interfaceCatModel.list(project_id);
|
|
/**
|
|
* 防止分类被都被删除时取不到 selectCatid
|
|
* 如果没有分类,增加一个默认分类
|
|
*/
|
|
if (menuList.length === 0) {
|
|
const catInst = yapi.getInst(interfaceCatModel);
|
|
const menu = await catInst.save({
|
|
name: '默认分类',
|
|
project_id: project_id,
|
|
desc: '默认分类',
|
|
uid: this.getUid(),
|
|
add_time: yapi.commons.time(),
|
|
up_time: yapi.commons.time()
|
|
});
|
|
menuList.push(menu);
|
|
}
|
|
let selectCatid = menuList[0]._id;
|
|
let projectData = await this.projectModel.get(project_id);
|
|
let res = await importDataModule[type](content);
|
|
|
|
let successMessage;
|
|
let errorMessage = [];
|
|
await HanldeImportData(
|
|
res,
|
|
project_id,
|
|
selectCatid,
|
|
menuList,
|
|
projectData.basePath,
|
|
dataSync,
|
|
err => {
|
|
errorMessage.push(err);
|
|
},
|
|
msg => {
|
|
successMessage = msg;
|
|
},
|
|
() => {},
|
|
token,
|
|
yapi.WEBCONFIG.port
|
|
);
|
|
|
|
if (errorMessage.length > 0) {
|
|
return (ctx.body = yapi.commons.resReturn(null, 404, errorMessage.join('\n')));
|
|
}
|
|
ctx.body = yapi.commons.resReturn(null, 0, successMessage + warnMessage);
|
|
}
|
|
|
|
async projectInterfaceData(ctx) {
|
|
ctx.body = 'projectInterfaceData';
|
|
}
|
|
|
|
handleValue(val, global) {
|
|
let globalValue = ArrayToObject(global);
|
|
let context = Object.assign({}, {global: globalValue}, this.records);
|
|
return handleParamsValue(val, context);
|
|
}
|
|
|
|
handleEvnParams(params) {
|
|
let result = [];
|
|
Object.keys(params).map(item => {
|
|
if (/env_/gi.test(item)) {
|
|
let curEnv = yapi.commons.trim(params[item]);
|
|
let value = { curEnv, project_id: item.split('_')[1] };
|
|
result.push(value);
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
async runAutoTest(ctx) {
|
|
if (!this.$tokenAuth) {
|
|
return (ctx.body = yapi.commons.resReturn(null, 40022, 'token 验证失败'));
|
|
}
|
|
// console.log(1231312)
|
|
const token = ctx.query.token;
|
|
|
|
const projectId = ctx.params.project_id;
|
|
const startTime = new Date().getTime();
|
|
const records = (this.records = {});
|
|
const reports = (this.reports = {});
|
|
const testList = [];
|
|
let id = ctx.params.id;
|
|
let curEnvList = this.handleEvnParams(ctx.params);
|
|
|
|
let colData = await this.interfaceColModel.get(id);
|
|
if (!colData) {
|
|
return (ctx.body = yapi.commons.resReturn(null, 40022, 'id值不存在'));
|
|
}
|
|
|
|
let projectData = await this.projectModel.get(projectId);
|
|
|
|
let caseList = await yapi.commons.getCaseList(id);
|
|
if (caseList.errcode !== 0) {
|
|
ctx.body = caseList;
|
|
}
|
|
caseList = caseList.data;
|
|
for (let i = 0, l = caseList.length; i < l; i++) {
|
|
let item = caseList[i];
|
|
let projectEvn = await this.projectModel.getByEnv(item.project_id);
|
|
|
|
item.id = item._id;
|
|
let curEnvItem = _.find(curEnvList, key => {
|
|
return key.project_id == item.project_id;
|
|
});
|
|
|
|
item.case_env = curEnvItem ? curEnvItem.curEnv || item.case_env : item.case_env;
|
|
item.req_headers = this.handleReqHeader(item.req_headers, projectEvn.env, item.case_env);
|
|
item.pre_script = projectData.pre_script;
|
|
item.after_script = projectData.after_script;
|
|
item.env = projectEvn.env;
|
|
let result;
|
|
// console.log('item',item.case_env)
|
|
try {
|
|
result = await this.handleTest(item);
|
|
} catch (err) {
|
|
result = err;
|
|
}
|
|
|
|
reports[item.id] = result;
|
|
records[item.id] = {
|
|
params: result.params,
|
|
body: result.res_body
|
|
};
|
|
testList.push(result);
|
|
}
|
|
|
|
function getMessage(testList) {
|
|
let successNum = 0,
|
|
failedNum = 0,
|
|
len = 0,
|
|
msg = '';
|
|
testList.forEach(item => {
|
|
len++;
|
|
if (item.code === 0) {
|
|
successNum++;
|
|
}
|
|
else {
|
|
failedNum++;
|
|
}
|
|
});
|
|
if (failedNum === 0) {
|
|
msg = `一共 ${len} 测试用例,全部验证通过`;
|
|
} else {
|
|
msg = `一共 ${len} 测试用例,${successNum} 个验证通过, ${failedNum} 个未通过。`;
|
|
}
|
|
|
|
return { msg, len, successNum, failedNum };
|
|
}
|
|
|
|
const endTime = new Date().getTime();
|
|
const executionTime = (endTime - startTime) / 1000;
|
|
|
|
let reportsResult = {
|
|
message: getMessage(testList),
|
|
runTime: executionTime + 's',
|
|
numbs: testList.length,
|
|
list: testList
|
|
};
|
|
|
|
if (ctx.params.email === true && reportsResult.message.failedNum !== 0) {
|
|
let autoTestUrl = `${
|
|
ctx.request.origin
|
|
}/api/open/run_auto_test?id=${id}&token=${token}&mode=${ctx.params.mode}`;
|
|
yapi.commons.sendNotice(projectId, {
|
|
title: `YApi自动化测试报告`,
|
|
content: `
|
|
<html>
|
|
<head>
|
|
<title>测试报告</title>
|
|
<meta charset="utf-8" />
|
|
<body>
|
|
<div>
|
|
<h3>测试结果:</h3>
|
|
<p>${reportsResult.message.msg}</p>
|
|
<h3>测试结果详情如下:</h3>
|
|
<p>${autoTestUrl}</p>
|
|
</div>
|
|
</body>
|
|
</html>`
|
|
});
|
|
}
|
|
let mode = ctx.params.mode || 'html';
|
|
if(ctx.params.download === true) {
|
|
ctx.set('Content-Disposition', `attachment; filename=test.${mode}`);
|
|
}
|
|
if (ctx.params.mode === 'json') {
|
|
return (ctx.body = reportsResult);
|
|
} else {
|
|
return (ctx.body = renderToHtml(reportsResult));
|
|
}
|
|
}
|
|
|
|
async handleTest(interfaceData) {
|
|
let requestParams = {};
|
|
let options;
|
|
options = handleParams(interfaceData, this.handleValue, requestParams);
|
|
let result = {
|
|
id: interfaceData.id,
|
|
name: interfaceData.casename,
|
|
path: interfaceData.path,
|
|
code: 400,
|
|
validRes: []
|
|
};
|
|
try {
|
|
options.taskId = this.getUid();
|
|
let data = await crossRequest(options, interfaceData.pre_script, interfaceData.after_script,createContex(
|
|
this.getUid(),
|
|
interfaceData.project_id,
|
|
interfaceData.interface_id
|
|
));
|
|
let res = data.res;
|
|
|
|
result = Object.assign(result, {
|
|
status: res.status,
|
|
statusText: res.statusText,
|
|
url: data.req.url,
|
|
method: data.req.method,
|
|
data: data.req.data,
|
|
headers: data.req.headers,
|
|
res_header: res.header,
|
|
res_body: res.body
|
|
});
|
|
if (options.data && typeof options.data === 'object') {
|
|
requestParams = Object.assign(requestParams, options.data);
|
|
}
|
|
|
|
let validRes = [];
|
|
|
|
let responseData = Object.assign(
|
|
{},
|
|
{
|
|
status: res.status,
|
|
body: res.body,
|
|
header: res.header,
|
|
statusText: res.statusText
|
|
}
|
|
);
|
|
|
|
await this.handleScriptTest(interfaceData, responseData, validRes, requestParams);
|
|
result.params = requestParams;
|
|
if (validRes.length === 0) {
|
|
result.code = 0;
|
|
result.validRes = [{ message: '验证通过' }];
|
|
} else if (validRes.length > 0) {
|
|
result.code = 1;
|
|
result.validRes = validRes;
|
|
}
|
|
} catch (data) {
|
|
result = Object.assign(options, result, {
|
|
res_header: data.header,
|
|
res_body: data.body || data.message,
|
|
status: null,
|
|
statusText: data.message,
|
|
code: 400
|
|
});
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
async handleScriptTest(interfaceData, response, validRes, requestParams) {
|
|
|
|
try {
|
|
let test = await yapi.commons.runCaseScript({
|
|
response: response,
|
|
records: this.records,
|
|
script: interfaceData.test_script,
|
|
params: requestParams
|
|
}, interfaceData.col_id, interfaceData.interface_id, this.getUid());
|
|
if (test.errcode !== 0) {
|
|
test.data.logs.forEach(item => {
|
|
validRes.push({
|
|
message: item
|
|
});
|
|
});
|
|
}
|
|
} catch (err) {
|
|
validRes.push({
|
|
message: 'Error: ' + err.message
|
|
});
|
|
}
|
|
}
|
|
|
|
handleReqHeader(req_header, envData, curEnvName) {
|
|
let currDomain = handleCurrDomain(envData, curEnvName);
|
|
|
|
let header = currDomain.header;
|
|
header.forEach(item => {
|
|
if (!checkNameIsExistInArray(item.name, req_header)) {
|
|
item.abled = true;
|
|
req_header.push(item);
|
|
}
|
|
});
|
|
req_header = req_header.filter(item => {
|
|
return item && typeof item === 'object';
|
|
});
|
|
return req_header;
|
|
}
|
|
}
|
|
|
|
module.exports = openController;
|