강동현

테스트 작성

...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
20 20
21 로비에서는 모든 방 목록을 확인하고 접속할 수 있습니다. 서버에 `roomList`를 전송하면 `RoomDescription[]`가 반환됩니다. 이 메세지는 모든 방에 관한 정보를 가지고 있습니다. 각 방은 고유한 `uuid`값으로 구분됩니다. 21 로비에서는 모든 방 목록을 확인하고 접속할 수 있습니다. 서버에 `roomList`를 전송하면 `RoomDescription[]`가 반환됩니다. 이 메세지는 모든 방에 관한 정보를 가지고 있습니다. 각 방은 고유한 `uuid`값으로 구분됩니다.
22 22
23 -특정한 방에 접속하기 위해서는 서버에 `joinRoom`을 보내면 됩니다. 요청이 성공하면 `RoomInfo`가 반환됩니다. `RoomInfo`에는 본인을 제외한 다른 플레이어들의 정보만이 담겨 있습니다. 23 +특정한 방에 접속하기 위해서는 서버에 `joinRoom`을 보내면 됩니다. 요청이 성공하면 `RoomInfo`가 반환됩니다. `RoomInfo`에는 본인을 포함한 모든 다른 플레이어들의 정보가 담겨 있습니다.
24 24
25 ### 방 25 ### 방
26 26
......
...@@ -66,7 +66,7 @@ export class Connection { ...@@ -66,7 +66,7 @@ export class Connection {
66 message: ServerInboundMessage<"login"> 66 message: ServerInboundMessage<"login">
67 ): ServerResponse<"login"> { 67 ): ServerResponse<"login"> {
68 this.user = new User(message.username, this); 68 this.user = new User(message.username, this);
69 - console.log(`User ${message.username} has logged in!`); 69 + // console.log(`User ${message.username} has logged in!`);
70 70
71 return { ok: true }; 71 return { ok: true };
72 } 72 }
......
1 -import ioclient, { Socket } from "socket.io-client";
2 -import { expect } from "chai";
3 -import { Server } from "./Server";
4 -import { response } from "express";
5 -import {
6 - RawMessage,
7 - ServerInboundMessage,
8 - ServerInboundMessageKey,
9 - ServerOutboundMessage,
10 - ServerOutboundMessageKey,
11 - ServerResponse,
12 -} from "../common";
13 -
14 -describe("server", () => {
15 - const PORT = 3000;
16 -
17 - var server: Server;
18 - var client1: Socket;
19 - var client2: Socket;
20 -
21 - before((done) => {
22 - let connected = 0;
23 -
24 - client1 = ioclient(`http://localhost:${PORT}`);
25 - client1.on("connect", () => ++connected == 2 && done());
26 -
27 - client2 = ioclient(`http://localhost:${PORT}`);
28 - client2.on("connect", () => ++connected == 2 && done());
29 -
30 - server = new Server(3000);
31 - });
32 -
33 - after(() => {
34 - server.close();
35 - client1.close();
36 - client2.close();
37 - });
38 -
39 - var roomUserUpdateMessage: ServerOutboundMessage<"updateRoomUser">;
40 - var roomChatMessage: ServerOutboundMessage<"chat">;
41 -
42 - const send = <T extends ServerInboundMessageKey>(
43 - socket: Socket,
44 - type: T,
45 - message: ServerInboundMessage<T>,
46 - callback: (response: ServerResponse<T>) => void
47 - ) => {
48 - socket.emit(
49 - "msg",
50 - {
51 - type: type as string,
52 - message: message,
53 - },
54 - callback
55 - );
56 - };
57 -
58 - step("register listeners", () => {
59 - client1.on("msg", (raw: RawMessage) => {
60 - if (raw.type == "updateRoomUser") roomUserUpdateMessage = raw.message;
61 - });
62 -
63 - client1.on("msg", (raw: RawMessage) => {
64 - if (raw.type == "chat") roomChatMessage = raw.message;
65 - });
66 - });
67 -
68 - step("login 1", (done) => {
69 - send(
70 - client1,
71 - "login",
72 - {
73 - username: "guest1",
74 - },
75 - (response) => {
76 - expect(response.ok).to.eq(true);
77 - done();
78 - }
79 - );
80 - });
81 -
82 - step("login 2", (done) => {
83 - send(
84 - client2,
85 - "login",
86 - {
87 - username: "guest2",
88 - },
89 - (response) => {
90 - expect(response.ok).to.eq(true);
91 - done();
92 - }
93 - );
94 - });
95 -
96 - var roomToJoin: string;
97 -
98 - step("room list", (done) => {
99 - send(client1, "roomList", {}, (response) => {
100 - expect(response.ok).to.eq(true);
101 - expect(response.result !== undefined).to.eq(true);
102 - if (response.result) {
103 - expect(response.result[0].name).to.eq("테스트 방 #1");
104 - roomToJoin = response.result[0].uuid;
105 - }
106 - done();
107 - });
108 - });
109 -
110 - step("room join 1", (done) => {
111 - send(client1, "joinRoom", { uuid: roomToJoin }, (response) => {
112 - expect(response.ok).to.eq(true);
113 - expect(response.result !== undefined).to.eq(true);
114 - if (response.result) {
115 - expect(response.result.uuid).to.eq(roomToJoin);
116 - expect(response.result.users.length).to.eq(1);
117 - expect(response.result.users[0].username).to.eq("guest1");
118 - }
119 - done();
120 - });
121 - });
122 -
123 - step("room join 2", (done) => {
124 - send(client2, "joinRoom", { uuid: roomToJoin }, (response) => {
125 - expect(response.ok).to.eq(true);
126 - expect(response.result !== undefined).to.eq(true);
127 - if (response.result) {
128 - expect(response.result.uuid).to.eq(roomToJoin);
129 - expect(response.result.users.length).to.eq(2);
130 - }
131 - done();
132 - });
133 - });
134 -
135 - // TODO: RoomUserUpdateMessage가 아직 도착하지 않았는데 실행되는 경우
136 - step("client 1 received user update", () => {
137 - expect(roomUserUpdateMessage !== undefined).to.eq(true);
138 - if (roomUserUpdateMessage) {
139 - expect(roomUserUpdateMessage.state).to.eq("added");
140 - expect(roomUserUpdateMessage.user.username).to.eq("guest2");
141 - }
142 - });
143 -
144 - step("client 2 send chat", (done) => {
145 - send(client2, "chat", { message: "Hello World" }, (response) => {
146 - expect(response.ok).to.eq(true);
147 - done();
148 - });
149 - });
150 -
151 - step("client 1 received chat", () => {
152 - expect(roomChatMessage !== undefined).to.eq(true);
153 - if (roomChatMessage) {
154 - expect(roomChatMessage.sender).to.eq("guest2");
155 - expect(roomChatMessage.message).to.eq("Hello World");
156 - }
157 - });
158 -
159 - step("client 2 leave", (done) => {
160 - send(client2, "leaveRoom", {}, (response) => {
161 - expect(response.ok).to.eq(true);
162 - done();
163 - });
164 - });
165 -
166 - step("client 1 received user update", () => {
167 - expect(roomUserUpdateMessage !== undefined).to.eq(true);
168 - if (roomUserUpdateMessage) {
169 - expect(roomUserUpdateMessage.state).to.eq("removed");
170 - expect(roomUserUpdateMessage.user.username).to.eq("guest2");
171 - }
172 - });
173 -});
1 +import { expect } from "chai";
2 +import { RoomManager } from "../room/RoomManager";
3 +import { DummySocket } from "./util/DummySocket";
4 +import { SocketTester } from "./util/SocketTester";
5 +
6 +describe("채팅", () => {
7 + const roomManager = new RoomManager();
8 + it("로그인하지 않은 유저는 요청할 수 없습니다", () => {
9 + const socket = new SocketTester(roomManager);
10 + const response = socket.test("chat", { message: "Hello World" });
11 + expect(response.ok).eq(false);
12 + });
13 + it("방에 접속하지 않은 유저는 요청할 수 없습니다", () => {
14 + const socket = new SocketTester(roomManager);
15 + socket.login("guest");
16 +
17 + const response = socket.test("chat", { message: "Hello World" });
18 + expect(response.ok).eq(false);
19 + });
20 + it("채팅을 보냅니다", () => {
21 + const socket = new SocketTester(roomManager);
22 + socket.login("guest");
23 +
24 + const room = roomManager.create("테스트", 2);
25 + expect(socket.test("joinRoom", { uuid: room.uuid }).ok).eq(true);
26 + expect(socket.test("chat", { message: "Hello World" }).ok).eq(true);
27 + });
28 + it("자신을 제외한 다른 사람들이 채팅을 받습니다", () => {
29 + const socket1 = new SocketTester(roomManager);
30 + socket1.login("guest1");
31 + const socket2 = new SocketTester(roomManager);
32 + socket2.login("guest2");
33 +
34 + const room = roomManager.create("테스트", 2);
35 + expect(socket1.test("joinRoom", { uuid: room.uuid }).ok).eq(true);
36 + expect(socket2.test("joinRoom", { uuid: room.uuid }).ok).eq(true);
37 + expect(socket1.test("chat", { message: "Hello World" }).ok).eq(true);
38 +
39 + expect(socket2.socket.received("chat").message).eq("Hello World");
40 + expect(socket2.socket.received("chat").sender).eq("guest1");
41 + socket1.socket.notReceived("chat");
42 + });
43 + it("빈 채팅은 보낼 수 없습니다", () => {
44 + const socket = new SocketTester(roomManager);
45 + socket.login("guest");
46 +
47 + const room = roomManager.create("테스트", 2);
48 + expect(socket.test("joinRoom", { uuid: room.uuid }).ok).eq(true);
49 + expect(socket.test("chat", { message: "" }).ok).eq(false);
50 + expect(socket.test("chat", { message: " " }).ok).eq(false);
51 + });
52 + it("글자수가 300자를 넘는 채팅은 보낼 수 없습니다", () => {
53 + const socket = new SocketTester(roomManager);
54 + socket.login("guest");
55 +
56 + const room = roomManager.create("테스트", 2);
57 + expect(socket.test("joinRoom", { uuid: room.uuid }).ok).eq(true);
58 + expect(socket.test("chat", { message: "A".repeat(300) }).ok).eq(true);
59 + expect(socket.test("chat", { message: "A".repeat(301) }).ok).eq(false);
60 + expect(socket.test("chat", { message: "가".repeat(300) }).ok).eq(true);
61 + expect(socket.test("chat", { message: "가".repeat(301) }).ok).eq(false);
62 + });
63 +});
1 import { expect } from "chai"; 1 import { expect } from "chai";
2 -import { Connection } from "../connection/Connection";
3 -import { SocketWrapper } from "../connection/SocketWrapper";
4 import { RoomManager } from "../room/RoomManager"; 2 import { RoomManager } from "../room/RoomManager";
5 -import { DummySocket } from "./util/DummySocket";
6 import { SocketTester } from "./util/SocketTester"; 3 import { SocketTester } from "./util/SocketTester";
7 4
8 describe("유효하지 않은 메세지", () => { 5 describe("유효하지 않은 메세지", () => {
6 + const roomManager = new RoomManager();
9 it("빈 메세지는 실패합니다", () => { 7 it("빈 메세지는 실패합니다", () => {
10 - const socket = new SocketTester(); 8 + const socket = new SocketTester(roomManager);
11 const response = socket.testAny({}); 9 const response = socket.testAny({});
12 expect(response.ok).eq(false); 10 expect(response.ok).eq(false);
13 }); 11 });
12 + it("json이 아닌 메세지는 실패합니다", () => {
13 + const socket = new SocketTester(roomManager);
14 + expect(socket.testAny("lol").ok).eq(false);
15 + expect(socket.testAny(3.14).ok).eq(false);
16 + expect(socket.testAny(false).ok).eq(false);
17 + expect(socket.testAny(null).ok).eq(false);
18 + expect(socket.testAny(undefined).ok).eq(false);
19 + });
14 it("유효하지 않은 타입의 메세지는 실패합니다", () => { 20 it("유효하지 않은 타입의 메세지는 실패합니다", () => {
15 - const socket = new SocketTester(); 21 + const socket = new SocketTester(roomManager);
16 const response = socket.testRaw({ type: "wtf", message: {} }); 22 const response = socket.testRaw({ type: "wtf", message: {} });
17 expect(response.ok).eq(false); 23 expect(response.ok).eq(false);
18 }); 24 });
19 - it("유효한 타입이지만 내용이 유효하지 않은 메세지는 실패합니다", () => { 25 + it("유효한 타입이지만 내용이 빈 메세지는 실패합니다", () => {
20 - const socket = new SocketTester(); 26 + const socket = new SocketTester(roomManager);
21 - const response = socket.testRaw({ type: "login", message: {} }); 27 + expect(socket.testRaw({ type: "login", message: {} }).ok).eq(false);
28 + expect(socket.testRaw({ type: "chat", message: {} }).ok).eq(false);
29 + });
30 + it("유효한 타입이지만 속성의 타입이 매칭되지 않는 메세지는 실패합니다", () => {
31 + const socket = new SocketTester(roomManager);
32 + expect(
33 + socket.testRaw({
34 + type: "login",
35 + message: { username: 1234 },
36 + }).ok
37 + ).eq(false);
38 + expect(
39 + socket.testRaw({
40 + type: "login",
41 + message: { username: {} },
42 + }).ok
43 + ).eq(false);
44 + expect(
45 + socket.testRaw({
46 + type: "login",
47 + message: { username: [false, true, false] },
48 + }).ok
49 + ).eq(false);
50 + });
51 + it("유효한 타입이지만 불필요한 속성이 포함된 메세지는 실패합니다", () => {
52 + const socket = new SocketTester(roomManager);
53 + const response = socket.testRaw({
54 + type: "login",
55 + message: { username: "guest", hello: "world" },
56 + });
22 expect(response.ok).eq(false); 57 expect(response.ok).eq(false);
23 }); 58 });
24 }); 59 });
......
1 +import { expect } from "chai";
2 +import { RoomManager } from "../room/RoomManager";
3 +import { DummySocket } from "./util/DummySocket";
4 +import { SocketTester } from "./util/SocketTester";
5 +
6 +describe("방 입장", () => {
7 + const roomManager = new RoomManager();
8 +
9 + it("로그인하지 않은 유저는 요청할 수 없습니다", () => {
10 + const socket = new SocketTester(roomManager);
11 + const room = roomManager.create("테스트", 2);
12 + const response = socket.test("joinRoom", { uuid: room.uuid });
13 + expect(response.ok).eq(false);
14 + });
15 + it("방에 입장합니다", () => {
16 + const socket = new SocketTester(roomManager);
17 + socket.login("guest1");
18 +
19 + const room = roomManager.create("테스트", 2);
20 +
21 + const response = socket.test("joinRoom", { uuid: room.uuid });
22 + expect(response.ok).eq(true);
23 + expect(response.result?.uuid).eq(room.uuid);
24 + expect(response.result?.name).eq(room.name);
25 + expect(response.result?.maxUsers).eq(room.maxUsers);
26 + expect(response.result?.users?.length).eq(1);
27 + expect(response.result?.users[0]?.username).eq("guest1");
28 + });
29 + it("방에 입장하면 유저 목록이 업데이트 됩니다", () => {
30 + const socket1 = new SocketTester(roomManager);
31 + const socket2 = new SocketTester(roomManager);
32 +
33 + socket1.login("guest1");
34 + socket2.login("guest2");
35 +
36 + const room = roomManager.create("테스트", 2);
37 +
38 + expect(socket1.test("joinRoom", { uuid: room.uuid }).ok).eq(true);
39 + expect(socket2.test("joinRoom", { uuid: room.uuid }).ok).eq(true);
40 + const updated = socket1.socket.received("updateRoomUser");
41 + expect(updated.state).eq("added");
42 + expect(updated.user.username).eq("guest2");
43 + });
44 + it("방에 이미 입장한 상태에서 다른 방에 입장할 수 없습니다", () => {
45 + const socket = new SocketTester(roomManager);
46 + socket.login("guest");
47 +
48 + const room1 = roomManager.create("테스트1", 2);
49 + const room2 = roomManager.create("테스트2", 2);
50 +
51 + expect(socket.test("joinRoom", { uuid: room1.uuid }).ok).eq(true);
52 + expect(socket.test("joinRoom", { uuid: room2.uuid }).ok).eq(false);
53 + });
54 + it("가득 찬 방에는 입장할 수 없습니다", () => {
55 + const socket1 = new SocketTester(roomManager);
56 + const socket2 = new SocketTester(roomManager);
57 +
58 + socket1.login("guest1");
59 + socket2.login("guest2");
60 +
61 + const room = roomManager.create("테스트", 1);
62 +
63 + expect(socket1.test("joinRoom", { uuid: room.uuid }).ok).eq(true);
64 + expect(socket2.test("joinRoom", { uuid: room.uuid }).ok).eq(false);
65 + });
66 +});
1 +import { expect } from "chai";
2 +import { RoomManager } from "../room/RoomManager";
3 +import { User } from "../user/User";
4 +import { DummySocket } from "./util/DummySocket";
5 +import { SocketTester } from "./util/SocketTester";
6 +
7 +describe("방 퇴장", () => {
8 + const roomManager = new RoomManager();
9 +
10 + it("로그인하지 않은 유저는 요청할 수 없습니다", () => {
11 + const socket = new SocketTester(roomManager);
12 + const response = socket.test("leaveRoom", {});
13 + expect(response.ok).eq(false);
14 + });
15 + it("방에 입장하지 않은 유저는 요청할 수 없습니다", () => {
16 + const socket = new SocketTester(roomManager);
17 + socket.login("guest");
18 +
19 + const response = socket.test("leaveRoom", {});
20 + expect(response.ok).eq(false);
21 + });
22 + it("방에서 퇴장합니다", () => {
23 + const socket = new SocketTester(roomManager);
24 + socket.login("guest");
25 +
26 + const room = roomManager.create("테스트", 2);
27 + expect(socket.test("joinRoom", { uuid: room.uuid }).ok).eq(true);
28 + expect(socket.test("leaveRoom", {}).ok).eq(true);
29 + });
30 + it("방에서 퇴장한 뒤 다시 요청을 보낼 수 없습니다", () => {
31 + const socket = new SocketTester(roomManager);
32 + socket.login("guest");
33 +
34 + const room = roomManager.create("테스트", 2);
35 + expect(socket.test("joinRoom", { uuid: room.uuid }).ok).eq(true);
36 + expect(socket.test("leaveRoom", {}).ok).eq(true);
37 + expect(socket.test("leaveRoom", {}).ok).eq(false);
38 + });
39 + it("방에서 퇴장하면 유저 목록이 업데이트 됩니다", () => {
40 + const socket1 = new SocketTester(roomManager);
41 + const socket2 = new SocketTester(roomManager);
42 +
43 + socket1.login("guest1");
44 + socket2.login("guest2");
45 +
46 + const room = roomManager.create("테스트", 2);
47 +
48 + expect(socket1.test("joinRoom", { uuid: room.uuid }).ok).eq(true);
49 + expect(socket2.test("joinRoom", { uuid: room.uuid }).ok).eq(true);
50 + expect(socket2.test("leaveRoom", {}).ok).eq(true);
51 + const updated = socket1.socket.received("updateRoomUser");
52 + expect(updated.state).eq("removed");
53 + expect(updated.user.username).eq("guest2");
54 + });
55 +});
1 +import { expect } from "chai";
2 +import { RoomManager } from "../room/RoomManager";
3 +import { SocketTester } from "./util/SocketTester";
4 +
5 +describe("로그인", () => {
6 + const roomManager = new RoomManager();
7 + it("로그인합니다", () => {
8 + const socket = new SocketTester(roomManager);
9 + const response = socket.test("login", { username: "guest" });
10 + expect(response.ok).eq(true);
11 + expect(socket.connection.user?.username).eq("guest");
12 + });
13 +});
1 +import { expect } from "chai";
2 +import { RoomManager } from "../room/RoomManager";
3 +import { DummySocket } from "./util/DummySocket";
4 +import { SocketTester } from "./util/SocketTester";
5 +
6 +describe("방 목록 요청", () => {
7 + const roomManager = new RoomManager();
8 + it("로그인하지 않은 유저는 요청할 수 없습니다.", () => {
9 + const socket = new SocketTester(roomManager);
10 + const response = socket.test("roomList", {});
11 + expect(response.ok).eq(false);
12 + });
13 + it("방 목록을 가져옵니다.", () => {
14 + const roomManager = new RoomManager();
15 + roomManager.create("테스트1", 4);
16 + roomManager.create("테스트2", 2);
17 +
18 + const socket = new SocketTester(roomManager);
19 + socket.login("guest");
20 +
21 + const response = socket.test("roomList", {});
22 + expect(response.ok).eq(true);
23 + expect(response.result?.length).eq(2);
24 + expect(response.result[0].name).eq("테스트1");
25 + expect(response.result[1].name).eq("테스트2");
26 + });
27 +});
1 -import { RawMessage, ServerResponse } from "../../../common"; 1 +import { expect } from "chai";
2 +import {
3 + RawMessage,
4 + ServerOutboundMessage,
5 + ServerOutboundMessageKey,
6 + ServerResponse,
7 +} from "../../../common";
2 import { SocketWrapper } from "../../connection/SocketWrapper"; 8 import { SocketWrapper } from "../../connection/SocketWrapper";
3 9
4 export class DummySocket implements SocketWrapper { 10 export class DummySocket implements SocketWrapper {
5 public handler?: (raw: RawMessage) => ServerResponse<any>; 11 public handler?: (raw: RawMessage) => ServerResponse<any>;
12 + public receivedMessages: RawMessage[] = [];
13 +
6 public setHandler(handler: (raw: RawMessage) => ServerResponse<any>) { 14 public setHandler(handler: (raw: RawMessage) => ServerResponse<any>) {
7 this.handler = handler; 15 this.handler = handler;
8 } 16 }
9 - public send(raw: RawMessage): void {} 17 +
18 + public send(raw: RawMessage): void {
19 + this.receivedMessages.push(raw);
20 + }
21 +
22 + private findMessageIndex<T extends ServerOutboundMessageKey>(key: T): number {
23 + for (let i = 0; i < this.receivedMessages.length; i++) {
24 + if (this.receivedMessages[i].type == key) {
25 + return i;
26 + }
27 + }
28 + return -1;
29 + }
30 +
31 + public received<T extends ServerOutboundMessageKey>(
32 + key: T
33 + ): ServerOutboundMessage<T> {
34 + const index = this.findMessageIndex(key);
35 + expect(index !== -1).eq(true);
36 +
37 + const message = this.receivedMessages[index];
38 + this.receivedMessages.splice(index, 1);
39 + return message.message;
40 + }
41 +
42 + public notReceived<T extends ServerOutboundMessageKey>(key: T): void {
43 + expect(this.findMessageIndex(key) === -1).eq(true);
44 + }
10 } 45 }
......
...@@ -10,11 +10,10 @@ import { DummySocket } from "./DummySocket"; ...@@ -10,11 +10,10 @@ import { DummySocket } from "./DummySocket";
10 10
11 export class SocketTester { 11 export class SocketTester {
12 public readonly connection: Connection; 12 public readonly connection: Connection;
13 - constructor( 13 + public readonly socket: DummySocket;
14 - public socket: DummySocket = new DummySocket(), 14 + constructor(roomManager: RoomManager) {
15 - roomManager: RoomManager = new RoomManager() 15 + this.socket = new DummySocket();
16 - ) { 16 + this.connection = new Connection(this.socket, roomManager);
17 - this.connection = new Connection(socket, roomManager);
18 } 17 }
19 18
20 public test<T extends ServerInboundMessageKey>( 19 public test<T extends ServerInboundMessageKey>(
...@@ -34,4 +33,8 @@ export class SocketTester { ...@@ -34,4 +33,8 @@ export class SocketTester {
34 public testAny(obj: any): ServerResponse<any> { 33 public testAny(obj: any): ServerResponse<any> {
35 return this.connection.handleRaw(obj); 34 return this.connection.handleRaw(obj);
36 } 35 }
36 +
37 + public login(username: string): void {
38 + this.test("login", { username });
39 + }
37 } 40 }
......