Authored by 王水玲

Merge branch 'develop' into feature/sale

1 { 1 {
2 "extends": "yoho", 2 "extends": "yoho",
3 - "rules": {  
4 - "no-unused-vars": [  
5 - "error",  
6 - {  
7 - "args": "after-used",  
8 - "vars": "all"  
9 - }  
10 - ] 3 + "parserOptions": {
  4 + "sourceType": "module"
11 } 5 }
12 } 6 }
@@ -12,22 +12,26 @@ if (config.useOneapm) { @@ -12,22 +12,26 @@ if (config.useOneapm) {
12 require('oneapm'); 12 require('oneapm');
13 } 13 }
14 14
15 -let express = require('express'),  
16 - path = require('path'),  
17 - bodyParser = require('body-parser'),  
18 - cookieParser = require('cookie-parser'),  
19 - favicon = require('serve-favicon'),  
20 - pkg = require('./package.json'); 15 +const express = require('express');
  16 +const path = require('path');
  17 +const bodyParser = require('body-parser');
  18 +const cookieParser = require('cookie-parser');
  19 +const favicon = require('serve-favicon');
  20 +const session = require('express-session');
  21 +const memcached = require('connect-memcached');
  22 +const pkg = require('./package.json');
21 23
22 -require('express-handlebars'); 24 +const app = express();
  25 +const MemcachedStore = memcached(session);
23 26
24 27
25 -let app = express();  
26 -  
27 // 向模板注入变量 28 // 向模板注入变量
28 app.locals.devEnv = app.get('env') === 'development'; 29 app.locals.devEnv = app.get('env') === 'development';
29 app.locals.version = pkg.version; 30 app.locals.version = pkg.version;
30 31
  32 +// 指定libray目录
  33 +global.library = path.resolve('./library');
  34 +
31 app.set('view engine', '.hbs'); 35 app.set('view engine', '.hbs');
32 36
33 app.use(favicon(path.join(__dirname, '/public/favicon.ico'))); 37 app.use(favicon(path.join(__dirname, '/public/favicon.ico')));
@@ -35,11 +39,22 @@ app.use(express.static(path.join(__dirname, 'public'))); @@ -35,11 +39,22 @@ app.use(express.static(path.join(__dirname, 'public')));
35 app.use(bodyParser.json()); 39 app.use(bodyParser.json());
36 app.use(bodyParser.urlencoded({extended: false})); 40 app.use(bodyParser.urlencoded({extended: false}));
37 app.use(cookieParser()); 41 app.use(cookieParser());
  42 +app.use(session({
  43 + secret: '3e5fec7deca0b8305cefe2ad9d90ff5e',
  44 + name: 'PHPSESSID',
  45 + prefix: 'yohobuy',
  46 + proxy: true,
  47 + resave: true,
  48 + saveUninitialized: true,
  49 + store: new MemcachedStore({
  50 + hosts: config.memcache.session
  51 + })
  52 +}));
38 53
39 // dispatcher 54 // dispatcher
40 require('./dispatch')(app); 55 require('./dispatch')(app);
41 56
42 // listener 57 // listener
43 -app.listen(6001, function() { 58 +app.listen(config.port, function() {
44 console.log('yohobuy start'); 59 console.log('yohobuy start');
45 }); 60 });
@@ -6,9 +6,9 @@ @@ -6,9 +6,9 @@
6 'use strict'; 6 'use strict';
7 const _ = require('lodash'); 7 const _ = require('lodash');
8 const channelModel = require('../models/channel'); 8 const channelModel = require('../models/channel');
9 -const helpers = require('../../../library/helpers');  
10 -const log = require('../../../library/logger');  
11 -const cookie = require('../../../library/cookie'); 9 +const helpers = require(`${global.library}/helpers`);
  10 +const log = require(`${global.library}/logger`);
  11 +const cookie = require(`${global.library}/cookie`);
12 12
13 const renderData = { 13 const renderData = {
14 module: 'channel', 14 module: 'channel',
@@ -24,7 +24,7 @@ app.engine('.hbs', hbs({ @@ -24,7 +24,7 @@ app.engine('.hbs', hbs({
24 defaultLayout: 'layout', 24 defaultLayout: 'layout',
25 layoutsDir: doraemon, 25 layoutsDir: doraemon,
26 partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`], 26 partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`],
27 - helpers: require('../../library/helpers') 27 + helpers: require(`${global.library}/helpers`)
28 })); 28 }));
29 29
30 // router 30 // router
@@ -5,11 +5,11 @@ @@ -5,11 +5,11 @@
5 */ 5 */
6 'use strict'; 6 'use strict';
7 const _ = require('lodash'); 7 const _ = require('lodash');
8 -const API = require('../../../library/api').ServiceAPI;  
9 -const sign = require('../../../library/sign');  
10 -const camelCase = require('../../../library/camel-case'); 8 +const ServiceAPI = require(`${global.library}/api`).ServiceAPI;
  9 +const sign = require(`${global.library}/sign`);
  10 +const camelCase = require(`${global.library}/camel-case`);
11 11
12 -const api = new API(); 12 +const api = new ServiceAPI();
13 13
14 const genderData = { 14 const genderData = {
15 boys: '1,3', 15 boys: '1,3',
@@ -19,7 +19,7 @@ exports.index = (req, res) => { @@ -19,7 +19,7 @@ exports.index = (req, res) => {
19 id: req.params.id, 19 id: req.params.id,
20 uid: uid, 20 uid: uid,
21 vipLevel: vipLevel, 21 vipLevel: vipLevel,
22 - ua: req.get('user-agent') ||  '' 22 + ua: req.get('user-agent') || ''
23 }).then((result) => { 23 }).then((result) => {
24 res.render('detail', { 24 res.render('detail', {
25 resultShow: JSON.stringify(result, null, 4), 25 resultShow: JSON.stringify(result, null, 4),
@@ -10,12 +10,14 @@ const isProduction = process.env.NODE_ENV === 'production'; @@ -10,12 +10,14 @@ const isProduction = process.env.NODE_ENV === 'production';
10 const isTest = process.env.NODE_ENV === 'test'; 10 const isTest = process.env.NODE_ENV === 'test';
11 11
12 module.exports = { 12 module.exports = {
  13 + port: 6001,
13 siteUrl: 'http://m.yohobuy.com', 14 siteUrl: 'http://m.yohobuy.com',
14 domains: { 15 domains: {
15 api: 'http://testapi.yoho.cn:28078/', // http://devapi.yoho.cn:58078/ http://testapi.yoho.cn:28078/ 16 api: 'http://testapi.yoho.cn:28078/', // http://devapi.yoho.cn:58078/ http://testapi.yoho.cn:28078/
16 - service: 'http://devapi.yoho.cn:58078/' 17 + service: 'http://testservice.yoho.cn:28077/'
17 }, 18 },
18 - useCache: true, 19 + useOneapm: false,
  20 + useCache: false,
19 memcache: { 21 memcache: {
20 master: ['192.168.102.168:12580'], 22 master: ['192.168.102.168:12580'],
21 slave: ['192.168.102.168:12580'], 23 slave: ['192.168.102.168:12580'],
@@ -26,12 +28,12 @@ module.exports = { @@ -26,12 +28,12 @@ module.exports = {
26 infoFile: { 28 infoFile: {
27 name: 'info', 29 name: 'info',
28 level: 'info', 30 level: 'info',
29 - filename: 'info.log' 31 + filename: 'log/info.log'
30 }, 32 },
31 errorFile: { 33 errorFile: {
32 name: 'error', 34 name: 'error',
33 level: 'error', 35 level: 'error',
34 - filename: 'error.log', 36 + filename: 'log/error.log',
35 handleExceptions: true 37 handleExceptions: true
36 }, 38 },
37 udp: { // send by udp 39 udp: { // send by udp
@@ -19,12 +19,10 @@ const serviceApi = config.domains.service; @@ -19,12 +19,10 @@ const serviceApi = config.domains.service;
19 const searchApi = config.domains.search; 19 const searchApi = config.domains.search;
20 20
21 21
22 -let ApiUrl; 22 +class Http {
23 23
24 -class API {  
25 -  
26 - constructor() {  
27 - ApiUrl = api; 24 + constructor(baseUrl) {
  25 + this.ApiUrl = baseUrl;
28 } 26 }
29 27
30 /** 28 /**
@@ -39,10 +37,11 @@ class API { @@ -39,10 +37,11 @@ class API {
39 */ 37 */
40 _requestFromAPI(options, cacheOption, reqId) { 38 _requestFromAPI(options, cacheOption, reqId) {
41 let timer = new Timer(); 39 let timer = new Timer();
  40 + let method = options.method || 'get';
42 41
43 timer.put('getApi');// 统计时间开始 42 timer.put('getApi');// 统计时间开始
44 43
45 - log.info(`get api: ${options.url}?${qs.stringify(options.qs)}`); 44 + log.info(`${method} api: ${options.url}?${qs.stringify(options.qs)}`);
46 return rp(options).then((result) => { 45 return rp(options).then((result) => {
47 let duration = timer.put('getApi');// 统计时间结束 46 let duration = timer.put('getApi');// 统计时间结束
48 47
@@ -61,10 +60,11 @@ class API { @@ -61,10 +60,11 @@ class API {
61 } 60 }
62 } 61 }
63 return result; 62 return result;
64 - }).catch((error)=>{ 63 + }).catch((error)=> {
65 let duration = timer.put('getApi');// 统计时间结束 64 let duration = timer.put('getApi');// 统计时间结束
66 65
67 - log.error(`get api fail: use: ${duration}ms, statusCode: ${error.statusCode}, error: ${error.message}`); 66 + log.error(`${method} api fail: use: ${duration}ms, statusCode:
  67 + ${error.statusCode}, error: ${error.message}`);
68 68
69 // 使用缓存的时候,读取二级缓存 69 // 使用缓存的时候,读取二级缓存
70 if (config.useCache) { 70 if (config.useCache) {
@@ -117,12 +117,14 @@ class API { @@ -117,12 +117,14 @@ class API {
117 */ 117 */
118 get(url, data, cacheOption) { 118 get(url, data, cacheOption) {
119 let options = { 119 let options = {
120 - url: `${ApiUrl}${url}`, 120 + url: `${this.ApiUrl}${url}`,
121 qs: data, 121 qs: data,
122 json: true, 122 json: true,
123 timeout: 3000 123 timeout: 3000
124 }; 124 };
125 125
  126 + console.log('in api : ' + config.useCache);
  127 +
126 // 从缓存获取数据 128 // 从缓存获取数据
127 if (config.useCache && cacheOption) { 129 if (config.useCache && cacheOption) {
128 return this._requestFromCache(options); 130 return this._requestFromCache(options);
@@ -138,7 +140,7 @@ class API { @@ -138,7 +140,7 @@ class API {
138 */ 140 */
139 post(url, data) { 141 post(url, data) {
140 let options = { 142 let options = {
141 - url: `${ApiUrl}${url}`, 143 + url: `${this.ApiUrl}${url}`,
142 form: data, 144 form: data,
143 method: 'post', 145 method: 'post',
144 json: true, 146 json: true,
@@ -151,22 +153,27 @@ class API { @@ -151,22 +153,27 @@ class API {
151 all(list) { 153 all(list) {
152 if (_.isArray(list)) { 154 if (_.isArray(list)) {
153 return Promise.all(list); 155 return Promise.all(list);
  156 + } else {
  157 + return Promise.reject(Error('the parameters of api all method should be Array!'));
154 } 158 }
155 - throw Error('the parameters of api all method should be Array!');  
156 } 159 }
157 } 160 }
158 161
159 -class ServiceAPI extends API { 162 +class API extends Http {
  163 + constructor() {
  164 + super(api);
  165 + }
  166 +}
  167 +
  168 +class ServiceAPI extends Http {
160 constructor() { 169 constructor() {
161 - super();  
162 - ApiUrl = serviceApi; 170 + super(serviceApi);
163 } 171 }
164 } 172 }
165 173
166 -class SearchAPI extends API { 174 +class SearchAPI extends Http {
167 constructor() { 175 constructor() {
168 - super();  
169 - ApiUrl = searchApi; 176 + super(searchApi);
170 } 177 }
171 } 178 }
172 179
@@ -5,8 +5,7 @@ @@ -5,8 +5,7 @@
5 */ 5 */
6 6
7 'use strict'; 7 'use strict';
8 -  
9 -const qs = require('querystring'); 8 +const _ = require('lodash');
10 const md5 = require('md5'); 9 const md5 = require('md5');
11 10
12 const privateKey = { 11 const privateKey = {
@@ -39,7 +38,13 @@ const packageSort = argument => { @@ -39,7 +38,13 @@ const packageSort = argument => {
39 * @return {string} 生成的签名字符串 38 * @return {string} 生成的签名字符串
40 */ 39 */
41 const makeSign = argument => { 40 const makeSign = argument => {
42 - return md5(qs.stringify(argument)).toLowerCase(); 41 + var qs = [];
  42 +
  43 + _.forEach(argument, function(value, key) {
  44 + qs.push(key + '=' + _.trim(value));
  45 + });
  46 +
  47 + return md5(qs.join('&')).toLowerCase();
43 }; 48 };
44 49
45 // 生成API签名,调用后端接口的时候有私钥校验 50 // 生成API签名,调用后端接口的时候有私钥校验
@@ -25,7 +25,7 @@ class Timer { @@ -25,7 +25,7 @@ class Timer {
25 if (labelTime) { 25 if (labelTime) {
26 let duration = process.hrtime(labelTime); 26 let duration = process.hrtime(labelTime);
27 27
28 - return this._round(duration[1]); 28 + return this._round(duration[0], duration[1]);
29 } else { 29 } else {
30 this.timers[label] = process.hrtime(); 30 this.timers[label] = process.hrtime();
31 } 31 }
@@ -35,8 +35,8 @@ class Timer { @@ -35,8 +35,8 @@ class Timer {
35 * 格式化成毫秒 35 * 格式化成毫秒
36 * @param {Number} value 纳秒 36 * @param {Number} value 纳秒
37 */ 37 */
38 - _round(value) {  
39 - return Math.round(value / 10000) / 100; 38 + _round(seconds, nanoseconds) {
  39 + return Math.round((seconds * 1e9 + nanoseconds) / 10000) / 100;
40 } 40 }
41 41
42 } 42 }
@@ -13,9 +13,9 @@ @@ -13,9 +13,9 @@
13 "online": "NODE_ENV=\"production\" node app.js", 13 "online": "NODE_ENV=\"production\" node app.js",
14 "debug": "DEBUG=\"express:*\" node app.js", 14 "debug": "DEBUG=\"express:*\" node app.js",
15 "lint-js": "./node_modules/.bin/eslint -c .eslintrc --cache --fix .", 15 "lint-js": "./node_modules/.bin/eslint -c .eslintrc --cache --fix .",
16 - "lint-css": "./node_modules/.bin/stylelint --config .stylelintrc public/**/*.css", 16 + "lint-css": "./node_modules/.bin/stylelint --config .stylelintrc public/scss/**/*.css",
17 "precommit": "node lint.js", 17 "precommit": "node lint.js",
18 - "test": "ava" 18 + "test": "./node_modules/.bin/nyc ./node_modules/.bin/ava"
19 }, 19 },
20 "ava": { 20 "ava": {
21 "tap": true, 21 "tap": true,
@@ -32,9 +32,11 @@ @@ -32,9 +32,11 @@
32 "dependencies": { 32 "dependencies": {
33 "bluebird": "^3.3.5", 33 "bluebird": "^3.3.5",
34 "body-parser": "^1.15.0", 34 "body-parser": "^1.15.0",
  35 + "connect-memcached": "^0.2.0",
35 "cookie-parser": "^1.4.1", 36 "cookie-parser": "^1.4.1",
36 "express": "^4.13.1", 37 "express": "^4.13.1",
37 "express-handlebars": "^3.0.0", 38 "express-handlebars": "^3.0.0",
  39 + "express-session": "^1.13.0",
38 "influxdb-winston": "^1.0.1", 40 "influxdb-winston": "^1.0.1",
39 "lodash": "^4.12.0", 41 "lodash": "^4.12.0",
40 "md5": "^2.1.0", 42 "md5": "^2.1.0",
@@ -44,14 +46,15 @@ @@ -44,14 +46,15 @@
44 "request-promise": "^3.0.0", 46 "request-promise": "^3.0.0",
45 "serve-favicon": "^2.3.0", 47 "serve-favicon": "^2.3.0",
46 "winston": "^2.2.0", 48 "winston": "^2.2.0",
47 - "winston-daily-rotate-file": "^1.0.1",  
48 - "yoho-handlebars": "0.0.1" 49 + "winston-daily-rotate-file": "^1.0.1"
49 }, 50 },
50 "devDependencies": { 51 "devDependencies": {
51 "autoprefixer": "^6.3.6", 52 "autoprefixer": "^6.3.6",
52 "ava": "^0.14.0", 53 "ava": "^0.14.0",
  54 + "babel-cli": "^6.8.0",
  55 + "babel-preset-es2015": "^6.6.0",
53 "babel-register": "^6.8.0", 56 "babel-register": "^6.8.0",
54 - "eslint": "^2.9.0", 57 + "eslint": "^2.10.2",
55 "eslint-config-yoho": "^1.0.1", 58 "eslint-config-yoho": "^1.0.1",
56 "gulp": "^3.9.1", 59 "gulp": "^3.9.1",
57 "gulp-cssnano": "^2.1.2", 60 "gulp-cssnano": "^2.1.2",
@@ -62,6 +65,7 @@ @@ -62,6 +65,7 @@
62 "husky": "^0.11.4", 65 "husky": "^0.11.4",
63 "mocha": "^2.4.5", 66 "mocha": "^2.4.5",
64 "nodemon": "1.9.2", 67 "nodemon": "1.9.2",
  68 + "nyc": "^6.4.3",
65 "postcss-assets": "^4.0.1", 69 "postcss-assets": "^4.0.1",
66 "postcss-cachebuster": "^0.1.2", 70 "postcss-cachebuster": "^0.1.2",
67 "postcss-calc": "^5.2.1", 71 "postcss-calc": "^5.2.1",
@@ -78,14 +82,15 @@ @@ -78,14 +82,15 @@
78 "rewire": "^2.5.1", 82 "rewire": "^2.5.1",
79 "shelljs": "^0.7.0", 83 "shelljs": "^0.7.0",
80 "stylelint": "^6.3.3", 84 "stylelint": "^6.3.3",
81 - "stylelint-config-yoho": "^1.2.2", 85 + "stylelint-config-yoho": "^1.2.3",
82 "webpack": "^1.13.0", 86 "webpack": "^1.13.0",
83 "webpack-dev-server": "^1.14.1", 87 "webpack-dev-server": "^1.14.1",
84 "webpack-stream": "^3.1.0", 88 "webpack-stream": "^3.1.0",
85 - "yoho-fastclick": "0.0.1",  
86 - "yoho-hammer": "0.0.1",  
87 - "yoho-jquery": "0.0.3",  
88 - "yoho-jquery-lazyload": "0.0.2",  
89 - "yoho-swiper": "0.0.1" 89 + "yoho-fastclick": "^1.0.6",
  90 + "yoho-hammer": "^2.0.7",
  91 + "yoho-handlebars": "^4.0.5",
  92 + "yoho-jquery": "^1.9.1",
  93 + "yoho-jquery-lazyload": "^1.9.7",
  94 + "yoho-swiper": "^3.3.1"
90 } 95 }
91 } 96 }
  1 +/**
  2 + * http api 测试
  3 + *
  4 + * @author: jiangfeng<jeff.jiang@yoho.cn>
  5 + * @date: 2016/05/17
  6 + */
  7 +'use strict';
  8 +
  9 +const test = require('ava');
  10 +
  11 +// const rewire = require('rewire');
  12 +
  13 +// const shelljs = require('shelljs');
  14 +const sign = require('../../library/sign');
  15 +
  16 +// let config = rewire('../../config/common');
  17 +
  18 +
  19 +const API = require('../../library/api').API;
  20 +const ServiceAPI = require('../../library/api').ServiceAPI;
  21 +const SearchAPI = require('../../library/api').SearchAPI;
  22 +
  23 +const getUrl = 'operations/api/v6/category/getCategory';
  24 +
  25 +
  26 +// test.before('create log folder', (t) => {
  27 +// shelljs.mkdir('log');
  28 +// t.pass();
  29 +// });
  30 +//
  31 +// test.after('delete log folder', (t) => {
  32 +// shelljs.rm('-rf', 'log');
  33 +// t.pass();
  34 +// });
  35 +
  36 +test('api constructor test', (t) => {
  37 + let api = new ServiceAPI();
  38 + let api2 = new API();
  39 + let api3 = new SearchAPI();
  40 +
  41 + t.true(api !== null);
  42 + t.true(api2 !== null);
  43 + t.true(api3 !== null);
  44 +});
  45 +
  46 +test('api get test', t => {
  47 + let api = new ServiceAPI();
  48 +
  49 + return api.get(getUrl, sign.apiSign({})).then(result => {
  50 + if (result && (result.code === 200 || result.code === 500)) {
  51 + t.pass();
  52 + } else {
  53 + t.fail();
  54 + }
  55 + });
  56 +});
  57 +
  58 +test('api get use cache test', t => {
  59 + let api = new ServiceAPI();
  60 +
  61 + return api.get(getUrl, sign.apiSign({}), true).then(result => {
  62 + if (result && (result.code === 200 || result.code === 500)) {
  63 + t.pass();
  64 + } else {
  65 + t.fail();
  66 + }
  67 + });
  68 +});
  69 +
  70 +test('api post test', t => {
  71 + let api = new ServiceAPI();
  72 +
  73 + return api.post(getUrl, sign.apiSign({})).then(result => {
  74 + if (result && (result.code === 200 || result.code === 500)) {
  75 + t.pass();
  76 + } else {
  77 + t.fail();
  78 + }
  79 + });
  80 +});
  81 +
  82 +test('api multiple call test', (t) => {
  83 + let api = new ServiceAPI();
  84 + let multi = [api.get(getUrl, sign.apiSign({})), api.get(getUrl, sign.apiSign({}))];
  85 +
  86 + return api.all(multi).then(result => {
  87 + if (result.length === 2) {
  88 + t.pass();
  89 + } else {
  90 + t.fail();
  91 + }
  92 + });
  93 +});
  94 +
  95 +test('api multiple fail call test', (t) => {
  96 + let api = new ServiceAPI();
  97 +
  98 + return api.all(1).catch((e) => {
  99 + if (e) {
  100 + t.pass();
  101 + } else {
  102 + t.fail();
  103 + }
  104 + });
  105 +});
  106 +
  107 +
  1 +/**
  2 + * cache 测试
  3 + *
  4 + * @author: jf<jeff.jiang@yoho.cn>
  5 + * @date: 2016/5/18
  6 + */
  7 +
  8 +'use strict';
  9 +
  10 +import test from 'ava';
  11 +
  12 +import cache from '../../library/cache';
  13 +
  14 +let testKey = 'test_unit_key:' + (new Date()).getTime();
  15 +let testValue = 'anotherValue';
  16 +let anotherKey = 'test_unit_key2:' + (new Date()).getTime();
  17 +let anotherValue = {a: 1};
  18 +
  19 +let slaveTestKey = 'test_unit_key3:' + (new Date()).getTime();
  20 +let slaveTestValue = 'anotherValue3';
  21 +
  22 +test.before('set test key', (t) => {
  23 + cache.set(testKey, testValue);
  24 + cache.set(anotherKey, anotherValue);
  25 + t.pass();
  26 +});
  27 +
  28 +test.after('del test key', (t) => {
  29 + cache.del(testKey);
  30 + cache.del(anotherKey);
  31 + t.pass();
  32 +});
  33 +
  34 +test('cache get test', (t) => {
  35 + return cache.get(testKey).then((v) => {
  36 + t.is(v, testValue);
  37 + });
  38 +});
  39 +
  40 +test('cache get multi test', (t) => {
  41 + cache.set(anotherKey, anotherValue);
  42 + return cache.getMulti([testKey, anotherKey]).then((values) => {
  43 + console.log(values);
  44 + t.is(values[testKey], testValue);
  45 + t.is(values[anotherKey], JSON.stringify(anotherValue));
  46 + });
  47 +});
  48 +
  49 +test('cache get from slave test', (t) => {
  50 + return cache.getFromSlave(testKey).then((v) => {
  51 + t.is(v, testValue);
  52 + });
  53 +});
  54 +
  55 +test('cache get multi from slave test', (t) => {
  56 + cache.set(anotherKey, anotherValue);
  57 + return cache.getMultiFromSlave([testKey, anotherKey]).then((values) => {
  58 + t.is(values[testKey], testValue);
  59 + t.is(values[anotherKey], JSON.stringify(anotherValue));
  60 + });
  61 +});
  62 +
  63 +test('cache set to slave', (t) => {
  64 + return cache.setSlave(slaveTestKey, slaveTestValue).then(() => {
  65 + return cache.getFromSlave(slaveTestKey);
  66 + }).then((v) => {
  67 + t.is(v, slaveTestValue);
  68 + cache.del(slaveTestKey);
  69 + });
  70 +});
  1 +/**
  2 + * 对象键名驼峰测试
  3 + *
  4 + * @author: jiangfeng<jeff.jiang@yoho.cn>
  5 + * @date: 2016/05/17
  6 + */
  7 +
  8 +import {test} from 'ava';
  9 +
  10 +const camelCase = require('../../library/camel-case');
  11 +
  12 +test('camel case object', t => {
  13 + let o = {
  14 + A_B: 'ab_cd'
  15 + };
  16 +
  17 + t.is(camelCase(o).aB, 'ab_cd');
  18 +});
  19 +
  20 +test('camel case array', t => {
  21 + let arr = [{
  22 + A_B: 'ab_cd'
  23 + }];
  24 +
  25 + t.is(camelCase(arr)[0].aB, 'ab_cd');
  26 +});
1 -const headerModel = require('../../doraemon/models/header');  
2 -  
3 -const test = require('ava').test;  
4 -  
5 -test('test setNavHeader method', t => {  
6 - const headerData = headerModel.setNavHeader('逛');  
7 -  
8 - t.is(headerData.navTitle, '逛');  
9 - t.true(headerData.backUrl);  
10 - t.true(headerData.navBtn);  
11 -});  
  1 +/**
  2 + * library helpers 类单元测试
  3 + * @author jeff.jiang<jeff.jiang@yoho.cn>
  4 + * @date 2016/05/17
  5 + */
  6 +
  7 +'use strict';
  8 +
  9 +const test = require('ava');
  10 +const helpers = require('../../library/helpers');
  11 +
  12 +test('qiniu image url handle', t => {
  13 + let url = 'http://img11.static.yhbimg.com/yhb-img01/2016/04/18/03/016d50b20cfdec5a91c614b68546bc9d72.jpg?imageView2/{mode}/w/{width}/h/{height}';
  14 + let expected = 'http://img11.static.yhbimg.com/yhb-img01/2016/04/18/03/016d50b20cfdec5a91c614b68546bc9d72.jpg?imageView2/2/w/400/h/300';
  15 +
  16 + t.is(helpers.image(url, 400, 300), expected);
  17 +});
  18 +
  19 +test('uri format', t => {
  20 + let uri = '/test';
  21 + let qs = { name: 'yoho' };
  22 + let mod = 'list';
  23 + let expected = '//list.m.yohobuy.com/test?name=yoho';
  24 +
  25 + t.is(helpers.url(uri, qs, mod), expected);
  26 +});
  27 +
  28 +test('upper char to lowercase', t => {
  29 + let str = 'ABc';
  30 + let expected = 'abc';
  31 +
  32 + t.is(helpers.lowerCase(str), expected);
  33 +});
  34 +
  35 +test('lower char to uppercase', t => {
  36 + let str = 'abc!';
  37 + let expected = 'ABC!';
  38 +
  39 + t.is(helpers.upperCase(str), expected);
  40 +});
  1 +/**
  2 + * logger 工具类测试
  3 + */
  4 +
  5 +const test = require('ava');
  6 +const shelljs = require('shelljs');
  7 +const logger = require('../../library/logger');
  8 +
  9 +const today = () => {
  10 + let now = new Date();
  11 + let s = now.getFullYear();
  12 +
  13 + if (now.getMonth() < 10) {
  14 + s += '-0' + now.getMonth();
  15 + } else {
  16 + s += now.getMonth();
  17 + }
  18 + if (now.getDay() < 10) {
  19 + s += '-0' + now.getDay();
  20 + } else {
  21 + s += now.getDay();
  22 + }
  23 + return s;
  24 +};
  25 +
  26 +// test.before('create log folder', t => {
  27 +// shelljs.mkdir('log');
  28 +// t.pass();
  29 +// });
  30 +//
  31 +// test.after('clean test log file ', t => {
  32 +// shelljs.rm('-rf', 'log');
  33 +// t.pass();
  34 +// });
  35 +
  36 +test.cb('logger test', t => {
  37 + shelljs.rm('-f', 'log/*.log.*');
  38 + logger.info('xxx', () => {
  39 + shelljs.ls('log/info.log.*').some(s => {
  40 + console.log('generate log file:' + s);
  41 + return s === 'info.log.' + today();
  42 + });
  43 + t.end();
  44 + });
  45 +});
  46 +
  47 +
  1 +/**
  2 + * 签名类测试
  3 + *
  4 + * @author: jiangfeng<jeff.jiang@yoho.cn>
  5 + * @date: 2016/05/17
  6 + */
  7 +
  8 +const test = require('ava');
  9 +const sign = require('../../library/sign');
  10 +
  11 +test('app sign test', t => {
  12 + let params = {
  13 + client_type: 'h5', // eslint-disable-line
  14 + a: 1,
  15 + b: 'b'
  16 + };
  17 + let signedParams = sign.apiSign(params);
  18 +
  19 + t.true(sign.checkSign(signedParams));
  20 +});
  1 +/**
  2 + * Timer 计时类测试
  3 + *
  4 + * @author: jiangfeng<jeff.jiang@yoho.cn>
  5 + * @date: 2016/05/17
  6 + */
  7 +
  8 +const test = require('ava');
  9 +const Timer = require('../../library/timer');
  10 +
  11 +const sleep = (timeout) => {
  12 + return new Promise((resolve) => {
  13 + setTimeout(() => {
  14 + resolve();
  15 + }, timeout);
  16 + });
  17 +};
  18 +
  19 +test.cb('timer class ', t => {
  20 + let timer = new Timer();
  21 +
  22 + timer.put('test');
  23 + sleep(300).then(() => {
  24 + let diff = timer.put('test');
  25 +
  26 + t.true(diff >= 300);
  27 + t.end();
  28 + });
  29 +});