Skip to content

Commit 74c5b9e

Browse files
authored
Merge pull request #13 from spherical-go/develop
Add game closing and more cases
2 parents 3534d2f + 6d774bb commit 74c5b9e

File tree

4 files changed

+478
-9
lines changed

4 files changed

+478
-9
lines changed

polyclash/server.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ def player_canceled(game, role):
6464

6565

6666
def delayed_start(game_id):
67-
time.sleep(3)
6867
storage.start_game()
6968
socketio.emit('start', {'message': 'Game has started'}, room=game_id)
7069
logger.info(f'game started... {game_id}')
@@ -112,7 +111,7 @@ def index():
112111
table_of_games += f"<li>viewer: {key}</li>"
113112
html = f"""
114113
<h1>Welcome to PolyClash</h1>
115-
<p>Token: {server_token}</p>
114+
<p>Server token: {server_token}</p>
116115
<h2>List of games</h2>
117116
<ul>
118117
{table_of_games}
@@ -122,6 +121,11 @@ def index():
122121
return html, 200
123122

124123

124+
@app.route('/sphgo/list', methods=['GET'])
125+
def list_games():
126+
return jsonify({'rooms': storage.list_rooms()}), 200
127+
128+
125129
@app.route('/sphgo/new', methods=['POST'])
126130
@api_call
127131
def new():

polyclash/util/storage.py

+32-3
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def get_plays(self, game_id):
135135
return self.games[game_id]['plays']
136136

137137
def list_rooms(self):
138-
return self.games.keys()
138+
return list([key for key in self.games.keys()])
139139

140140
def close_room(self, game_id):
141141
game = self.games[game_id]
@@ -254,9 +254,13 @@ def create_room(self):
254254
self.redis.hset(f'games:{game_id}', 'ready:white', str(False))
255255
self.redis.hset(f'games:{game_id}', 'started', str(False))
256256

257+
self.redis.expire(f'games:{game_id}', 3600 * 24 * 3)
258+
257259
# self.redis.rpush(f'games:{game_id}:viewers', '')
258260
# self.redis.rpush(f'games:{game_id}:plays', '')
259261

262+
self.reaper()
263+
260264
return dict(game_id=game_id, black_key=black_key, white_key=white_key, viewer_key=viewer_key)
261265

262266
def contains(self, key_or_token):
@@ -284,7 +288,23 @@ def list_rooms(self):
284288
])
285289

286290
def close_room(self, game_id):
287-
pass
291+
if self.redis.exists(f'games:{game_id}'):
292+
self.redis.hdel('rooms', self.redis.hget(f'games:{game_id}', 'keys:black'))
293+
self.redis.hdel('rooms', self.redis.hget(f'games:{game_id}', 'keys:white'))
294+
self.redis.hdel('rooms', self.redis.hget(f'games:{game_id}', 'keys:viewer'))
295+
self.redis.hdel('rooms', self.redis.hget(f'games:{game_id}', 'players:black'))
296+
self.redis.hdel('rooms', self.redis.hget(f'games:{game_id}', 'players:white'))
297+
if self.redis.exists(f'games:{game_id}:viewer'):
298+
for viewer_id in self.redis.lrange(f'games:{game_id}:viewers', 0, -1):
299+
self.redis.hdel('rooms', viewer_id.decode('utf-8'))
300+
301+
self.redis.delete(f'games:{game_id}')
302+
self.redis.lrem('games', 1, game_id)
303+
304+
if self.redis.exists(f'games:{game_id}:viewer'):
305+
self.redis.delete(f'games:{game_id}:viewer')
306+
if self.redis.exists(f'games:{game_id}:plays'):
307+
self.redis.delete(f'games:{game_id}:plays')
288308

289309
def exists(self, game_id):
290310
return game_id in list([item.decode('utf-8') for item in self.redis.lrange('games', 0, -1)])
@@ -318,7 +338,8 @@ def create_viewer(self, key):
318338
token = secrets.token_hex(USER_TOKEN_LENGTH // 2)
319339
game_id = self.get_game_id(key)
320340
self.redis.hset('rooms', token, game_id)
321-
self.redis.hset(f'games:{game_id}', f'players:viewer', token)
341+
self.redis.rpush(f'games:{game_id}:viewer', token)
342+
self.redis.expire(f'games:{game_id}:viewer', 3600 * 24 * 3)
322343

323344
def get_role(self, key_or_token):
324345
game_id = self.get_game_id(key_or_token)
@@ -345,6 +366,14 @@ def is_started(self, game_id):
345366

346367
def add_play(self, game_id, play):
347368
self.redis.rpush(f'games:{game_id}:plays', json.dumps(play))
369+
self.redis.expire(f'games:{game_id}:plays', 3600 * 24 * 3)
370+
371+
def reaper(self):
372+
for game_id in self.list_rooms():
373+
# if game_id is not represented in the key of games:{game_id}
374+
# then it means the game is over and we should clean up
375+
if not self.redis.exists(f'games:{game_id}'):
376+
self.close_room(game_id)
348377

349378

350379
def test_redis_connection(host='localhost', port=6379, db=0):

tests/test_server.py

+220-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import time
12
import pytest
2-
33
import polyclash.server as server
44

55
from flask_socketio import SocketIO
@@ -110,7 +110,7 @@ def test_game_ready(storage, test_client, socketio_client):
110110
assert result6.json['status']['black']
111111

112112

113-
def test_play_game(storage, test_client, socketio_client):
113+
def test_game_ready2(storage, test_client, socketio_client):
114114
result0 = test_client.post('/sphgo/new', json={'key': server_token})
115115
assert result0.status_code == 200
116116
assert result0.json['black_key']
@@ -152,5 +152,223 @@ def test_play_game(storage, test_client, socketio_client):
152152
assert result8.json['status']['white']
153153

154154

155+
def test_game_play(storage, test_client, socketio_client):
156+
result0 = test_client.post('/sphgo/new', json={'key': server_token})
157+
assert result0.status_code == 200
158+
assert result0.json['black_key']
159+
assert result0.json['white_key']
160+
161+
result1 = test_client.post('/sphgo/join', json={'token': result0.json['black_key']})
162+
assert result1.status_code == 200
163+
assert result1.json['status']['black']
164+
165+
result3 = test_client.post('/sphgo/join', json={'token': result0.json['white_key']})
166+
assert result3.status_code == 200
167+
assert result3.json['status']['white']
168+
169+
result5 = test_client.post('/sphgo/ready', json={'token': result0.json['black_key']})
170+
assert result5.status_code == 200
171+
assert result5.json['status']['black']
172+
173+
result7 = test_client.post('/sphgo/ready', json={'token': result0.json['white_key']})
174+
assert result7.status_code == 200
175+
assert result7.json['status']['black']
176+
177+
result9 = test_client.post('/sphgo/play', json={'token': result0.json['black_key'], 'role': 'black', 'steps': 0, 'play': [5, 6, 7, 8, 9]})
178+
assert result9.status_code == 200
179+
180+
result10 = test_client.post('/sphgo/play', json={'token': result0.json['white_key'], 'role': 'white', 'steps': 1, 'play': [0, 1, 2, 3, 4]})
181+
assert result10.status_code == 200
182+
183+
184+
def test_game_play_wrong_turn1(storage, test_client, socketio_client):
185+
result0 = test_client.post('/sphgo/new', json={'key': server_token})
186+
assert result0.status_code == 200
187+
assert result0.json['black_key']
188+
assert result0.json['white_key']
189+
190+
result1 = test_client.post('/sphgo/join', json={'token': result0.json['black_key']})
191+
assert result1.status_code == 200
192+
assert result1.json['status']['black']
193+
194+
result3 = test_client.post('/sphgo/join', json={'token': result0.json['white_key']})
195+
assert result3.status_code == 200
196+
assert result3.json['status']['white']
197+
198+
result5 = test_client.post('/sphgo/ready', json={'token': result0.json['black_key']})
199+
assert result5.status_code == 200
200+
assert result5.json['status']['black']
201+
202+
result7 = test_client.post('/sphgo/ready', json={'token': result0.json['white_key']})
203+
assert result7.status_code == 200
204+
assert result7.json['status']['black']
205+
206+
result9 = test_client.post('/sphgo/play', json={'token': result0.json['black_key'], 'role': 'black', 'steps': 0, 'play': [5, 6, 7, 8, 9]})
207+
assert result9.status_code == 200
208+
209+
result10 = test_client.post('/sphgo/play', json={'token': result0.json['black_key'], 'role': 'white', 'steps': 1, 'play': [0, 1, 2, 3, 4]})
210+
assert result10.status_code == 400
211+
212+
213+
def test_game_play_wrong_turn2(storage, test_client, socketio_client):
214+
result0 = test_client.post('/sphgo/new', json={'key': server_token})
215+
assert result0.status_code == 200
216+
assert result0.json['black_key']
217+
assert result0.json['white_key']
218+
219+
result1 = test_client.post('/sphgo/join', json={'token': result0.json['black_key']})
220+
assert result1.status_code == 200
221+
assert result1.json['status']['black']
222+
223+
result3 = test_client.post('/sphgo/join', json={'token': result0.json['white_key']})
224+
assert result3.status_code == 200
225+
assert result3.json['status']['white']
226+
227+
result5 = test_client.post('/sphgo/ready', json={'token': result0.json['black_key']})
228+
assert result5.status_code == 200
229+
assert result5.json['status']['black']
230+
231+
result7 = test_client.post('/sphgo/ready', json={'token': result0.json['white_key']})
232+
assert result7.status_code == 200
233+
assert result7.json['status']['black']
234+
235+
result9 = test_client.post('/sphgo/play', json={'token': result0.json['black_key'], 'role': 'black', 'steps': 0, 'play': [5, 6, 7, 8, 9]})
236+
assert result9.status_code == 200
237+
238+
result10 = test_client.post('/sphgo/play', json={'token': result0.json['white_key'], 'role': 'white', 'steps': 1, 'play': [0, 1, 2, 3, 4]})
239+
assert result10.status_code == 200
240+
241+
result11 = test_client.post('/sphgo/play', json={'token': result0.json['white_key'], 'role': 'white', 'steps': 2, 'play': [10, 11, 12, 13, 14]})
242+
assert result11.status_code == 400
243+
244+
245+
246+
def test_game_play_wrong_steps1(storage, test_client, socketio_client):
247+
result0 = test_client.post('/sphgo/new', json={'key': server_token})
248+
assert result0.status_code == 200
249+
assert result0.json['black_key']
250+
assert result0.json['white_key']
251+
252+
result1 = test_client.post('/sphgo/join', json={'token': result0.json['black_key']})
253+
assert result1.status_code == 200
254+
assert result1.json['status']['black']
255+
256+
result3 = test_client.post('/sphgo/join', json={'token': result0.json['white_key']})
257+
assert result3.status_code == 200
258+
assert result3.json['status']['white']
259+
260+
result5 = test_client.post('/sphgo/ready', json={'token': result0.json['black_key']})
261+
assert result5.status_code == 200
262+
assert result5.json['status']['black']
263+
264+
result7 = test_client.post('/sphgo/ready', json={'token': result0.json['white_key']})
265+
assert result7.status_code == 200
266+
assert result7.json['status']['black']
267+
268+
result9 = test_client.post('/sphgo/play', json={'token': result0.json['black_key'], 'role': 'black', 'steps': 1, 'play': [5, 6, 7, 8, 9]})
269+
assert result9.status_code == 400
270+
271+
272+
def test_game_play_wrong_steps2(storage, test_client, socketio_client):
273+
result0 = test_client.post('/sphgo/new', json={'key': server_token})
274+
assert result0.status_code == 200
275+
assert result0.json['black_key']
276+
assert result0.json['white_key']
277+
278+
result1 = test_client.post('/sphgo/join', json={'token': result0.json['black_key']})
279+
assert result1.status_code == 200
280+
assert result1.json['status']['black']
281+
282+
result3 = test_client.post('/sphgo/join', json={'token': result0.json['white_key']})
283+
assert result3.status_code == 200
284+
assert result3.json['status']['white']
285+
286+
result5 = test_client.post('/sphgo/ready', json={'token': result0.json['black_key']})
287+
assert result5.status_code == 200
288+
assert result5.json['status']['black']
289+
290+
result7 = test_client.post('/sphgo/ready', json={'token': result0.json['white_key']})
291+
assert result7.status_code == 200
292+
assert result7.json['status']['black']
293+
294+
result9 = test_client.post('/sphgo/play', json={'token': result0.json['black_key'], 'role': 'black', 'steps': 0, 'play': [5, 6, 7, 8, 9]})
295+
assert result9.status_code == 200
296+
297+
result10 = test_client.post('/sphgo/play', json={'token': result0.json['white_key'], 'role': 'white', 'steps': 1, 'play': [0, 1, 2, 3, 4]})
298+
assert result10.status_code == 200
299+
300+
result11 = test_client.post('/sphgo/play', json={'token': result0.json['black_key'], 'role': 'black', 'steps': 1, 'play': [10, 11, 12, 13, 14]})
301+
assert result11.status_code == 400
302+
303+
304+
def test_game_play_no_hang(storage, test_client, socketio_client):
305+
result0 = test_client.post('/sphgo/new', json={'key': server_token})
306+
assert result0.status_code == 200
307+
assert result0.json['black_key']
308+
assert result0.json['white_key']
309+
310+
result1 = test_client.post('/sphgo/join', json={'token': result0.json['black_key']})
311+
assert result1.status_code == 200
312+
assert result1.json['status']['black']
313+
314+
result3 = test_client.post('/sphgo/join', json={'token': result0.json['white_key']})
315+
assert result3.status_code == 200
316+
assert result3.json['status']['white']
317+
318+
result5 = test_client.post('/sphgo/ready', json={'token': result0.json['black_key']})
319+
assert result5.status_code == 200
320+
assert result5.json['status']['black']
321+
322+
result7 = test_client.post('/sphgo/ready', json={'token': result0.json['white_key']})
323+
assert result7.status_code == 200
324+
assert result7.json['status']['black']
325+
326+
result9 = test_client.post('/sphgo/play', json={'token': result0.json['black_key'], 'role': 'black', 'steps': 0, 'play': [5, 6, 7, 8, 9]})
327+
assert result9.status_code == 200
328+
329+
result10 = test_client.post('/sphgo/play', json={'token': result0.json['white_key'], 'role': 'white', 'steps': 1, 'play': [0, 1, 2, 3, 4]})
330+
assert result10.status_code == 200
331+
332+
result11 = test_client.post('/sphgo/play', json={'token': result0.json['black_key'], 'role': 'black', 'steps': 1, 'play': [10, 11, 12, 13, 14]})
333+
assert result11.status_code == 400
334+
335+
result12 = test_client.post('/sphgo/play', json={'token': result0.json['black_key'], 'role': 'black', 'steps': 2, 'play': [10, 11, 12, 13, 14]})
336+
assert result12.status_code == 200
337+
338+
339+
def test_game_close(storage, test_client, socketio_client):
340+
result0 = test_client.post('/sphgo/new', json={'key': server_token})
341+
assert result0.status_code == 200
342+
assert result0.json['black_key']
343+
assert result0.json['white_key']
344+
345+
result1 = test_client.post('/sphgo/join', json={'token': result0.json['black_key']})
346+
assert result1.status_code == 200
347+
assert result1.json['status']['black']
348+
349+
result3 = test_client.post('/sphgo/join', json={'token': result0.json['white_key']})
350+
assert result3.status_code == 200
351+
assert result3.json['status']['white']
352+
353+
result5 = test_client.post('/sphgo/ready', json={'token': result0.json['black_key']})
354+
assert result5.status_code == 200
355+
assert result5.json['status']['black']
356+
357+
result7 = test_client.post('/sphgo/ready', json={'token': result0.json['white_key']})
358+
assert result7.status_code == 200
359+
assert result7.json['status']['black']
360+
361+
result9 = test_client.post('/sphgo/play', json={'token': result0.json['black_key'], 'role': 'black', 'steps': 0, 'play': [5, 6, 7, 8, 9]})
362+
assert result9.status_code == 200
363+
364+
result10 = test_client.post('/sphgo/play', json={'token': result0.json['white_key'], 'role': 'white', 'steps': 1, 'play': [0, 1, 2, 3, 4]})
365+
assert result10.status_code == 200
366+
367+
result11 = test_client.post('/sphgo/close', json={'token': result0.json['white_key']})
368+
assert result11.status_code == 200
369+
370+
result12 = test_client.get('/sphgo/list')
371+
assert result0.json['game_id'] not in result12.json['rooms']
372+
155373
if __name__ == '__main__':
156374
pytest.main()

0 commit comments

Comments
 (0)