Skip to content

Instantly share code, notes, and snippets.

@pxsta
Created October 28, 2012 08:30
Show Gist options
  • Save pxsta/3968061 to your computer and use it in GitHub Desktop.
Save pxsta/3968061 to your computer and use it in GitHub Desktop.
mochaとsuperagentを用いてexpressのアプリのセッション周りのテスト
"use strict";
var express = require('express')
, http = require('http')
, path = require('path')
, io = require('socket.io')
, connect = require("express/node_modules/connect")
, Session = express.session.Session
, app = module.exports = express();
//メモリストアかRedisのどちらかでセッションを保存
//var sessionStore = new express.session.MemoryStore()
var RedisStore = require('connect-redis')(express)
, sessionStore = new RedisStore();
app.configure(function() {
app.set('port', process.env.PORT || 3000);
//セッションの署名に使われるキー
app.set('secretKey', 'mySecret');
//cookieにexpressのsessionIDを保存する際のキー
app.set('cookieSessionKey', 'sid');
//POSTの値を受け取れるようにする
app.use(express.bodyParser());
//expressでセッション管理を行う
app.use(express.cookieParser(app.get('secretKey')));
app.use(express.session({
key : app.get('cookieSessionKey'),
store : sessionStore
}));
//テスト用
app.set("sessionStore",sessionStore);
});
app.get('/', function(req, res) {
res.sendfile(__dirname + '/index.html');
});
//ログイン処理
app.post('/user/login', function(req, res) {
var postData = {
userID : req.body.userID,
password : req.body.password
};
//passがtestならログイン成功させる
if ( typeof postData.userID !== 'undefined' && typeof postData.password !== 'undefined' && postData.password.toString() === 'test') {
//sessionにユーザーID保存
req.session.userID = postData.userID.toString();
res.redirect('/chat');
}
else {
console.log('login failed');
res.redirect('/');
}
});
//ログアウト処理
app.get('/user/logout',function(req,res){
req.session.destroy(function(err) {
if(err){
console.log(err);
}
res.redirect('/');
});
});
//チャットページ
app.get('/chat', function(req, res) {
//セッションにuserIDがあったらログイン済みとする
if ( typeof req.session.userID !== 'undefined' && req.session.userID) {
res.sendfile(__dirname + '/chat.html');
}
else {
res.redirect('/');
}
});
io = io.listen(http.createServer(app).listen(app.get('port')), function() {
console.log("Express server & socket.io listening on port " + app.get('port'));
});
//socket.ioのコネクション認証時にexpressのセッションIDを元にログイン済みか確認する
io.set('authorization', function(handshakeData, callback) {
if (handshakeData.headers.cookie) {
//cookieを取得
var cookie = require('cookie').parse(decodeURIComponent(handshakeData.headers.cookie));
cookie = connect.utils.parseSignedCookies(cookie, app.get('secretKey'));
var sessionID = cookie[app.get('cookieSessionKey')];
// セッションをから取得
sessionStore.get(sessionID, function(err, session) {
if (err) {
//セッションが取得できなかったら
console.dir(err);
callback(err.message, false);
}
else if (!session) {
console.log('session not found');
callback('session not found', false);
}
else {
console.log("authorization success");
// socket.ioからもセッションを参照できるようにする
handshakeData.cookie = cookie;
handshakeData.sessionID = sessionID;
handshakeData.sessionStore = sessionStore;
handshakeData.session = new Session(handshakeData, session);
callback(null, true);
}
});
}
else {
//cookieが見つからなかった時
return callback('cookie not found', false);
}
});
io.sockets.on('connection', function(socket) {
// Expressのセッションをsocket.ioから参照する
console.log('session data', socket.handshake.session);
socket.on("chat", function(message) {
io.sockets.emit("message", socket.handshake.session.userID + " " + message);
});
//Expressのセッションを定期的に更新する
var sessionReloadIntervalID = setInterval(function() {
socket.handshake.session.reload(function() {
socket.handshake.session.touch().save();
});
}, 60 * 2 * 1000);
socket.on("disconnect", function(message) {
clearInterval(sessionReloadIntervalID);
});
});
"use strict";
var url = require('url')
, connect = require("express/node_modules/connect")
, should = require('should')
, assert = require('assert')
, superagent = require('superagent')
, app = require('../app.js');
describe('HTTP Server Test', function() {
//テストに使用するユーザーを作成
var testUser = superagent.agent();
//テスト前処理
before(function(done) {
//セッションストアのデータをすべて消す
app.get("sessionStore").client.flushdb(done);
});
it('ログインページにアクセスできるはず', function(done) {
testUser.get('http://localhost:3000/').end(function(err, res) {
should.not.exist(err);
should.equal(res.statusCode, 200);
done();
});
});
it('ログイン前にチャットページにアクセスしたらログインページにリダイレクトされるはず', function(done) {
testUser.get('http://localhost:3000/chat').end(function(err, res) {
should.not.exist(err);
res.redirects.should.not.be.empty;
should.equal(url.parse(res.redirects[0], false, true).pathname, "/");
done();
});
});
it('ログインに失敗したらログインページにリダイレクトされるはず', function(done) {
//ログインページでのpost処理
testUser.post('http://localhost:3000/user/login').send({
userID : 'test',
password : 'bad_password'
}).end(function(err, res) {
should.not.exist(err);
res.redirects.should.not.be.empty;
should.equal(url.parse(res.redirects[0], false, true).pathname, "/");
done();
});
});
it('ログインに成功したらセッションストレージにユーザー名が保存されているはず', function(done) {
testUser.post('http://localhost:3000/user/login').send({
userID : 'test',
password : 'test'
}).end(function(err, res) {
should.not.exist(err);
//sessionStoreにsessionデータが保存されているはず
var header_cookie = res.req._headers.cookie;
var cookie = require('cookie').parse(decodeURIComponent(header_cookie));
cookie = connect.utils.parseSignedCookies(cookie, app.get('secretKey'));
var sessionID = cookie[app.get('cookieSessionKey')];
app.get("sessionStore").get(sessionID,function(err,session){
should.not.exist(err);
//userIDがログイン時のものと一致するはず
should.equal(session.userID,"test");
done();
});
});
});
it('ログイン後はチャットページに直接アクセスしても表示されるはず', function(done) {
testUser.get('http://localhost:3000/chat').end(function(err, res) {
should.not.exist(err);
should.equal(res.statusCode, 200);
should.equal(res.req.path, "/chat");
done();
});
});
it('ログアウト後はログインページにリダイレクトされるはず', function(done) {
testUser.get('http://localhost:3000/user/logout').end(function(err, res) {
should.not.exist(err);
res.redirects.should.not.be.empty;
should.equal(url.parse(res.redirects[0], false, true).pathname, "/");
done();
});
});
it('ログアウト後はチャットページに直接アクセスしてもログインページにリダイレクトされるはず', function(done) {
testUser.get('http://localhost:3000/chat').end(function(err, res) {
should.not.exist(err);
res.redirects.should.not.be.empty;
should.equal(url.parse(res.redirects[0], false, true).pathname, "/");
done();
});
});
//テスト後処理
after(function(done) {
app.get("sessionStore").client.flushdb(done);
});
});
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Socket.io-Express3.0.0rc3 session sample</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
</head>
<body>
<h1>Socket.io-Express3.0.0rc3 session sample</h1>
<div id="nav">
<a href="/user/logout">logout</a>
</div>
<div id="chat">
<div id="board"></div>
<textarea id="textarea"></textarea>
<button id="btn-send">send</button>
</div>
</body>
<script type="text/javascript">
var socket = io.connect();
socket.on("message", function(message) {
$("#board").append("<p>" + message + "</p>");
});
var sendMessage = function() {
var message = $("#textarea").val();
$("#textarea").val("");
socket.emit("chat", message);
};
$(document).ready(function() {
$('textarea#textarea').bind('keypress', function(e) {
if (e.keyCode == 13) {
sendMessage();
}
});
$("#btn-send").click(function() {
sendMessage();
});
});
</script>
</html>
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Socket.io-Express3.0.0rc3 session sample</title>
</head>
<body>
<h1>Socket.io-Express3.0.0rc3 session sample</h1>
<div id="login">
<form action="/user/login" method="post">
ID: <input type="text" name="userID" value="test"/> <br/>
PASS: <input type="text" name="password" value ="test"/>
<input type="submit" value="login" />
</form>
</div>
</body>
</html>
--reporter spec
{
"name": "socketio-express3-chat",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app"
},
"engines": {
"node": "0.8.7",
"npm": "1.1.49"
},
"dependencies": {
"express": "3.0.0rc3",
"socket.io": "0.9.10",
"cookie": "0.0.4",
"connect-redis": "~1.4.4",
"should": "~1.2.0",
"superagent": "~0.9.7"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment