Kaynağa Gözat

完成AJAX模拟PUT, DELETE请求;将单元测试接口分开

Sand 8 yıl önce
ebeveyn
işleme
47486e5c24

+ 51 - 42
src/client/im.client.js

@ -2,6 +2,22 @@
 * IM客户端SDK。此SDK可以连接开发、测试或生产环境,根据需要配置环境参数以连接到不同的服务器。
 */
// Node.js模拟jQuery及ajax请求所需要的环境:document及XMLHttpRequest。
// 这些环境仅用于模拟,客户端在使用时候不需要真正引入
if (typeof process !== 'undefined') {
    var jsdom = require('jsdom').jsdom;
    var document = jsdom('<html></html>', {});
    var window = document.defaultView;
    var jQuery = require('jquery');
    var $ = jQuery(window);
    $.support.cors = true;
    XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
    $.ajaxSettings.xhr = function () {
        return new XMLHttpRequest();
    };
}
// 本地临时缓存Key
var LocalStorageKey = {
    userId: "im_userid"
@ -55,78 +71,82 @@ var ENDPOINTS = {
        Participant: '/sessions/:session_id/participants/:participant_id',
        ParticipantAvatar: '/session/:session_id/participants/:participant_id/avatars'
    },
    Search: {
    }
    Search: {}
};
// 将API路径加上主机名称
(function regularEndpoints() {
    for (var catalog in ENDPOINTS) {
        for(var path in catalog){
            ENDPOINTS.getProperty(catalog).setProperty(path, server + path);
        }
    }
})();
/*(function regularEndpoints() {
 for (var catalog in ENDPOINTS) {
 for(var path in catalog){
 ENDPOINTS.getProperty(catalog).setProperty(path, server + path);
 }
 }
 })();*/
var httpClient = {
    get: function (endpoint, data, successCallback, errorCallback) {
        $.ajax({
            type: "get",
            url: endpoint,
            url: server + endpoint,
            data: data,
            async: true,
            dataType: "json",
            success: function (data) {
                successCallback(data);
            },
            error: function (message) {
                errorCallback(message);
            error: function (xhr, status, error) {
                errorCallback(xhr, status, error);
            }
        });
    },
    post: function (endpoint, data, successCallback, errorCallback) {
        $.ajax({
            type: "post",
            url: endpoint,
            url: server + endpoint,
            data: data,
            async: true,
            dataType: "json",
            success: function (data) {
                successCallback(data);
            },
            error: function (message) {
                errorCallback(message);
            error: function (xhr, status, error) {
                errorCallback(xhr, status, error);
            }
        });
    },
    put: function (endpoint, data, successCallback, errorCallback) {
        $.ajax({
            type: "put",
            url: endpoint,
            type: "post",
            url: server + endpoint,
            data: data,
            async: true,
            dataType: "json",
            headers: {
                "X-HTTP-Method-Override": "PUT"
            },
            success: function (data) {
                successCallback(data);
            },
            error: function (message) {
                errorCallback(message);
            error: function (xhr, status, error) {
                errorCallback(xhr, status, error);
            }
        });
    },
    delete: function (endpoint, data, successCallback, errorCallback) {
        $.ajax({
            type: "delete",
            url: endpoint,
            type: "get",
            url: server + endpoint,
            data: data,
            async: true,
            dataType: "json",
            headers: {
                "X-HTTP-Method-Override": "DELETE"
            },
            success: function (data) {
                successCallback(data);
            },
            error: function (message) {
                errorCallback(message);
            error: function (xhr, status, error) {
                errorCallback(xhr, status, error);
            }
        });
    },
@ -165,9 +185,9 @@ var imClient = {
    Users: {
        // 登录
        login: function (userId, token, client_id, platform, success, failure) {
            plus.storage.setItem(LocalStorageKey.userId, userId);
            if (typeof plus !== 'undefined') plus.storage.setItem(LocalStorageKey.userId, userId);
            httpClient.post(ENDPOINTS.Login,
            httpClient.post(ENDPOINTS.Users.Login,
                {user_id: userId, token: token, client_id: client_id, platform: platform},
                success,
                failure);
@ -175,9 +195,9 @@ var imClient = {
        // 退出
        logout: function (userId, success, failure) {
            plus.storage.removeItem(LocalStorageKey.userId);
            if (typeof plus !== 'undefined') plus.storage.removeItem(LocalStorageKey.userId);
            httpClient.delete(ENDPOINTS.Logout,
            httpClient.delete(ENDPOINTS.Users.Logout,
                {user_id: userId},
                success,
                failure);
@ -185,23 +205,10 @@ var imClient = {
        // 更新用户状态
        updateStatus: function (userId, status, success, failure) {
            httpClient.put(ENDPOINTS.UserStatus.replace(UserPath, userId),
            httpClient.put(ENDPOINTS.Users.UserStatus.replace(UserPath, userId),
                {status: status},
                success,
                failure);
            $.ajax({
                type: "get",
                url: ENDPOINTS.UserStatus.replace(UserPath, userId),
                data: {user_id: userId, status: status},
                async: true,
                dataType: "json",
                success: function (data) {
                    console.log(JSON.stringify(data));
                },
                error: function (msg) {
                }
            });
        },
    },
    Sessions: {
@ -384,3 +391,5 @@ var imClient = {
    },
    Search: {}
};
module.exports = imClient;

+ 2 - 0
src/server/app.js

@ -11,6 +11,7 @@ let cookieParser = require('cookie-parser');
let bodyParser = require('body-parser');
let log = require('./util/log');
let redis = require('redis');
let methodOverride = require('method-override');
// server configurations
let configFile = require('./include/commons').CONFIG_FILE;
@ -35,6 +36,7 @@ app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(methodOverride(null, {methods: ['GET', 'POST']}));
// web pages and endpoint
UrlInitializer.initWebPages(app);

+ 3 - 1
src/server/endpoints/url.initializer.js

@ -1,6 +1,8 @@
/**
 * URL初始化。
 *
 * 除了初始化URL,还增加对版本的访问控制。
 *
 * author: Sand
 * since: 12/23/2016
 */
@ -27,7 +29,7 @@ class UrlInitializer{
    static initRestApi(app){
        app.use(function (req, res, next) {
            if(req.url.indexOf('/api/v1') >= 0){
                res.status(403).send({message: "API v1 is invalid since 1.2.8, please use API v2."});
                res.status(403).send({message: "API v1 is invalid since 2.0.0, please use API v2."});
            } else {
                next();
            }

+ 28 - 42
src/server/endpoints/v2/user.endpoint.js

@ -32,52 +32,17 @@ const APIv2 = require('../../include/endpoints').APIv2;
 *  client_id:个推的client id
 *  platform:平台类型,0为iOS,1为Android
 */
router.get(APIv2.Users.Login, function (req, res) {
    let userId = req.query.user_id;
    let token = req.query.token;
    let clientId = req.query.client_id;
    let platform = req.query.platform;
    if (userId == null) {
        throw {httpStatus: 406, message: 'Missing field: user_id.'};
    }
    if (token == null) {
        throw {httpStatus: 406, message: 'Missing field: token.'};
    }
    if (clientId == null) {
        throw {httpStatus: 406, message: 'Missing field: client_id.'};
    }
    if (platform == null) {
        throw {httpStatus: 406, message: 'Missing field: platform.'};
router.post(APIv2.Users.Login, function (req, res) {
    let appStatus = req.body;
    let testing = ObjectUtil.fieldsCheck(appStatus, "user_id", "token", "client_id", "platform");
    if (!testing.pass) {
        throw {httpStatus: 406, message: testing.message}
    }
    let users = new Users();
    ControllerUtil.regModelEventHandler(users, res);
    users.login(userId, platform, token, clientId);
});
/**
 * 退出。
 *
 * 请求URL:
 *  /users/logout?user_id=sand
 *
 * 参数:
 *  user_id:用户ID
 */
router.get(APIv2.Users.Logout, function (req, res) {
    let userId = req.query.user_id;
    if (userId == null) {
        throw {httpStatus: 406, message: 'Logout Failed. Missing field: user_id.'};
    }
    let userStatus = new Users();
    ControllerUtil.regModelEventHandler(userStatus, res);
    userStatus.logout(userId);
    users.login(appStatus.user_id, appStatus.platform, appStatus.token, appStatus.client_id);
});
/**
@ -89,7 +54,7 @@ router.get(APIv2.Users.Logout, function (req, res) {
 * POST参数格式:
 *  {status: 1}, app状态,0在后台,1在前台
 */
router.post(APIv2.Users.UserStatus, function (req, res) {
router.put(APIv2.Users.UserStatus, function (req, res) {
    let userId = req.param('user_id');
    let status = req.body;
    if (!ObjectUtil.isJsonObject(status)) {
@ -106,4 +71,25 @@ router.post(APIv2.Users.UserStatus, function (req, res) {
    userStatus.updateStatus(userId, status.status);
});
/**
 * 退出。
 *
 * 请求URL:
 *  /users/logout?user_id=sand
 *
 * 参数:
 *  user_id:用户ID
 */
router.delete(APIv2.Users.Logout, function (req, res) {
    let userId = req.query.user_id;
    if (userId == null) {
        throw {httpStatus: 406, message: 'Logout Failed. Missing field: user_id.'};
    }
    let userStatus = new Users();
    ControllerUtil.regModelEventHandler(userStatus, res);
    userStatus.logout(userId);
});
module.exports = router;

+ 13 - 7
src/server/models/user/users.js

@ -281,9 +281,12 @@ class Users extends RedisModel {
                    }
                });
                ModelUtil.emitData(self.eventEmitter, {});
                callback(null, null);
            }
        ]);
        ],
        function (err, res) {
            ModelUtil.emitData(self.eventEmitter, {});
        });
    }
    logout(userId) {
@ -298,16 +301,19 @@ class Users extends RedisModel {
                    let usersKey = REDIS_KEYS.Users;
                    let userKey = self.makeRedisKey(REDIS_KEYS.User, userId);
                    let userStatusKey = self.makeRedisKey(isPatient ? REDIS_KEYS.UserWechatStatus : REDIS_KEYS.UserAppStatus, userId);
                    redisConn.multiAsync()
                    redisConn.multi()
                        .del(usersKey)
                        .del(userKey)
                        .del(userStatusKey)
                        .execAsync().then(function (res) {
                    })
                            if(res.length > 0 && res[0] === 0){
                                ModelUtil.emitDataNotFound(self.eventEmitter, {message: "User not found."});
                            } else {
                                ModelUtil.emitData(self.eventEmitter, {});
                            }
                    });
                }],
            function (err, res) {
                ModelUtil.emitData(self.eventEmitter, {});
            }
            function (err, res) {}
        );
    }

+ 2 - 0
src/server/package.json

@ -15,6 +15,8 @@
    "debug": "~2.2.0",
    "express": "~4.12.4",
    "jade": "~1.9.2",
    "jquery": "^3.1.1",
    "method-override": "^2.3.7",
    "mocha": "~3.1.2",
    "mongoose": "^4.7.2",
    "morgan": "~1.5.3",

+ 1 - 1
src/server/resources/config/config.dev.js

@ -80,7 +80,7 @@ let sessionConfig = {
};
exports.app = 'IM.Server';
exports.version = '1.2.8';
exports.version = '2.0.0';
exports.debug = true;
exports.serverPort = 3008;
exports.sessionExpire = 1800;

+ 1 - 1
src/server/resources/config/config.prod.js

@ -74,7 +74,7 @@ let sessionConfig = {
};
exports.app = 'im.server';
exports.version = '1.2.7';
exports.version = '2.0.0';
exports.debug = true;
exports.serverPort = 3000;
exports.sessionExpire = 1800;

+ 1 - 1
src/server/resources/config/config.test.js

@ -70,7 +70,7 @@ let sessionConfig = {
    expireSessionCleanCount: 10             // 每次清理多少个过期会话
};
exports.app = 'im.server';
exports.version = '1.0.2.20160805';
exports.version = '2.0.0';
exports.debug = true;
exports.serverPort = 3000;
exports.sessionExpire = 1800;

+ 3 - 3
src/server/util/controller.util.js

@ -16,15 +16,15 @@ class ControllerUtil {
    static regModelEventHandler(model, response) {
        model.on(MODEL_EVENTS.OK, function (data) {
            response.status(200).send(data);
            response.status(200).json(data);
        });
        model.on(MODEL_EVENTS.DataNotFound, function (data) {
            response.status(404).send(data);
            response.status(404).json(data);
        });
        model.on(MODEL_EVENTS.Error, function (data) {
            response.status(500).send(data);
            response.status(500).json(data);
        });
    }
}

+ 0 - 108
test/client/im.client.Test.js

@ -1,108 +0,0 @@
/**
 * IM客户端单元测试。单元测试编写规则:至少对对每个接口执行正反例测试,若有条件可以增加接口的性能测试。
 *
 * @author sand
 * @since 2016/12/24
 */
let assert = require('assert');
// 测试会话用的数据
let Sessions = {
    MUC: {
        SessionId: "",
        Topics: [],
        DoctorA: "",
        DoctorB: "",
        Patient: ""
    },
    P2P: {
        SessionId: "",
        DoctorA: "",
        DoctorB: ""
    },
    Group: {
        SessionId: "",
        DoctorA: "",
        DoctorB: "",
        DoctorC: "",
        DoctorD: ""
    }
};
describe("IM SDK Unit Test", function () {
    /**
     * 用户API。测试范围:
     * 1 有效/无效用户ID登录/状态更新/退出
     */
    describe("User API", function () {
        describe("login", function () {
            it("should be 200 with valid user", function (done) {
                done();
            });
            it("should be 404 with invalid user", function (done) {
                done();
            });
        });
        describe("user status", function () {
            it("should be 200 with valid user", function (done) {
                done();
            });
            it("should be 404 with invalid user", function (done) {
                done();
            });
        });
        describe("logout", function () {
            it("should be 200 with valid user", function (done) {
                done();
            });
            it("should be 404 with invalid user", function (done) {
                done();
            });
        });
    });
    // Application API
    describe("Application API", function () {
        describe("get badge no", function () {
            it("should be 200 when with valid user", function (done) {
                done();
            });
        });
    });
    // 会话API
    describe("Session API", function () {
        describe("get sessions", function () {
            it("should be 200 when user login yet.", function (done) {
                done();
            });
        });
    });
    // 健康API
    describe("Health API", function () {
        describe("health", function () {
            it("should be 200 when system is allright", function (done) {
                done();
            });
        });
    });
    // 管理API
    describe("Management  API", function () {
        describe("db_status", function () {
            it("should be 200 while database is ok", function (done) {
                done();
            });
        });
    });
});

+ 53 - 0
test/client/im.client.application.Test.js

@ -0,0 +1,53 @@
/**
 * IM客户端单元测试。单元测试编写规则:至少对对每个接口执行正反例测试,若有条件可以增加接口的性能测试。
 *
 * @author sand
 * @since 2016/12/24
 */
"use strict";
var $ = require('jquery');
let assert = require('assert');
let imClient = require('../../src/client/im.client');
// 测试会话用的数据, test data
let TD = {
    MUC: {
        SessionId: "",
        Topics: [],
        DoctorA: "",
        DoctorB: "",
        Patient: ""
    },
    P2P: {
        SessionId: "",
        DoctorA: {
            id: "0de7295862dd11e69faffa163e8aee56",
            token: "0PFWlKmLBN9YzhCfFWVgYA",
            clientId: "H6FYbDejks6VjMmW3uH7V6",
            platform: 0
        },
        DoctorB: ""
    },
    Group: {
        SessionId: "",
        DoctorA: "",
        DoctorB: "",
        DoctorC: "",
        DoctorD: ""
    }
};
describe("IM SDK: Application Unit Test", function () {
    // Application API
    describe("Application API", function () {
        describe("get badge no", function () {
            it("return 200 when with valid user", function (done) {
                done();
            });
        });
    });
});

+ 31 - 0
test/client/im.client.health.Test.js

@ -0,0 +1,31 @@
/**
 * IM客户端单元测试。单元测试编写规则:至少对对每个接口执行正反例测试,若有条件可以增加接口的性能测试。
 *
 * @author sand
 * @since 2016/12/24
 */
"use strict";
var $ = require('jquery');
let assert = require('assert');
let imClient = require('../../src/client/im.client');
describe("IM SDK: health Unit Test", function () {
    // 健康API
    describe("Health API", function () {
        describe("health", function () {
            it("return 200 when system is all right", function (done) {
                done();
            });
        });
    });
    // 管理API
    describe("Management  API", function () {
        describe("db_status", function () {
            it("return 200 while database is ok", function (done) {
                done();
            });
        });
    });
});

+ 22 - 0
test/client/im.client.management.Test.js

@ -0,0 +1,22 @@
/**
 * IM客户端单元测试。单元测试编写规则:至少对对每个接口执行正反例测试,若有条件可以增加接口的性能测试。
 *
 * @author sand
 * @since 2016/12/24
 */
"use strict";
var $ = require('jquery');
let assert = require('assert');
let imClient = require('../../src/client/im.client');
describe("IM SDK: management Unit Test", function () {
    // 管理API
    describe("Management  API", function () {
        describe("db_status", function () {
            it("return 200 while database is ok", function (done) {
                done();
            });
        });
    });
});

+ 53 - 0
test/client/im.client.session.Test.js

@ -0,0 +1,53 @@
/**
 * IM客户端单元测试。单元测试编写规则:至少对对每个接口执行正反例测试,若有条件可以增加接口的性能测试。
 *
 * @author sand
 * @since 2016/12/24
 */
"use strict";
var $ = require('jquery');
let assert = require('assert');
let imClient = require('../../src/client/im.client');
// 测试会话用的数据, test data
let TD = {
    MUC: {
        SessionId: "",
        Topics: [],
        DoctorA: "",
        DoctorB: "",
        Patient: ""
    },
    P2P: {
        SessionId: "",
        DoctorA: {
            id: "0de7295862dd11e69faffa163e8aee56",
            token: "0PFWlKmLBN9YzhCfFWVgYA",
            clientId: "H6FYbDejks6VjMmW3uH7V6",
            platform: 0
        },
        DoctorB: ""
    },
    Group: {
        SessionId: "",
        DoctorA: "",
        DoctorB: "",
        DoctorC: "",
        DoctorD: ""
    }
};
describe("IM SDK Unit Test", function () {
    // 会话API
    describe("Session API", function () {
        describe("get sessions", function () {
            it("return 200 when user login yet.", function (done) {
                done();
            });
        });
    });
});

+ 91 - 0
test/client/im.client.user.Test.js

@ -0,0 +1,91 @@
/**
 * IM客户端单元测试。单元测试编写规则:至少对对每个接口执行正反例测试,若有条件可以增加接口的性能测试。
 *
 * @author sand
 * @since 2016/12/24
 */
"use strict";
var $ = require('jquery');
let assert = require('assert');
let imClient = require('../../src/client/im.client');
// 测试会话用的数据, test data
let TD = {
    DoctorA: {
        id: "0de7295862dd11e69faffa163e8aee56",
        token: "0PFWlKmLBN9YzhCfFWVgYA",
        clientId: "H6FYbDejks6VjMmW3uH7V6",
        platform: 0
    }
};
describe("IM SDK: user", function () {
    /**
     * 用户API。测试范围:
     * 1 有效/无效用户ID登录/状态更新/退出
     */
    describe("User API", function () {
        describe("login", function () {
            it("return 200 with valid user", function (done) {
                imClient.Users.login(TD.DoctorA.id, TD.DoctorA.token, TD.DoctorA.clientId, TD.DoctorA.platform,
                    function (data) {
                        assert.strictEqual(Object.keys(data).length, 0);
                        done();
                    },
                    function (xhr, status, error) {
                        assert.ok(false, xhr.responseJSON.message);
                        done();
                    });
            });
            it("return 404 with invalid user", function (done) {
                done();
            });
        });
        describe("updateStatus", function () {
            it("return 200 with valid user", function (done) {
                imClient.Users.updateStatus(TD.DoctorA.id, 1, function (data) {
                    done();
                },
                function (xhr, status, error) {
                    done();
                });
            });
            it("return 404 with invalid user", function (done) {
                imClient.Users.updateStatus("invalid_user_id", 1, function (data) {
                        done();
                    },
                    function (xhr, status, error) {
                        done();
                    });
            });
        });
        describe("logout", function () {
            it("return 200 with valid user", function (done) {
                imClient.Users.logout(TD.DoctorA.id, function (data) {
                        assert.strictEqual(Object.keys(data).length, 0);
                        done();
                    },
                    function (xhr, status, error) {
                        assert.strictEqual(status, "error");
                        done()
                    });
            });
            it("return 404 with invalid user id", function (done) {
                imClient.Users.logout("invalid_user_id", function (data) {
                        assert.ok(false, "Logout with invalid user id must NOT return success");
                        done();
                    },
                    function (xhr, status, error) {
                        assert.strictEqual(xhr.status, 404);
                        done()
                    });
            });
        });
    });
});

+ 3 - 0
test/server/package.json

@ -9,5 +9,8 @@
    "redis": "^2.6.3",
    "should": "^7.0.2",
    "supertest": "^1.0.1"
  },
  "dependencies": {
    "jquery": "^3.1.1"
  }
}