gamekey 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ module Gamekey
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,854 @@
1
+ require 'defaults'
2
+ require 'net/http'
3
+ require 'json'
4
+ require 'colorize'
5
+
6
+ require 'auth'
7
+
8
+ #
9
+ # This class defines the reference tests for the Gamekey Service.
10
+ # Dart implementation must pass exactly the same test cases.
11
+ #
12
+ class GamekeyReferenceTests
13
+
14
+ # Host to test
15
+ attr_reader :host
16
+
17
+ # Constructor to create a Gamekey service.
18
+ #
19
+ def initialize(host: Defaults::TESTHOST)
20
+ @host = host
21
+
22
+ @user = 'New One'
23
+ @pwd = 'secret'
24
+
25
+ @game = 'New Game'
26
+ @secret = 'secret'
27
+
28
+ end
29
+
30
+ # Generates a standardized error string for better identification
31
+ # of failed test cases.
32
+ #
33
+ def error(operation, resource, id)
34
+ "Testcase [#{id}] failed, #{operation} on #{resource}: "
35
+ end
36
+
37
+
38
+ #
39
+ # Checks, that creating a new user (POST /user) works as specified.
40
+ #
41
+ def createUser
42
+
43
+ uri = URI("#{@host}/user")
44
+ send = DateTime.now
45
+ res = Net::HTTP.post_form(uri, 'name' => @user, 'pwd' => @pwd)
46
+
47
+ return "#{error('POST', '/user', "PU-1")} Could not create user '#{@user}' (should return HTTP code 200, was #{res.code})".red unless (res.code == "200")
48
+ begin
49
+ user = JSON.parse(res.body)
50
+ return "#{error('POST', '/user', "PU-2")} Created user has wrong name. Should be '#{user}', was #{user['name']}.".red unless user['name'] == @user
51
+ return "#{error('POST', '/user', "PU-3")} Created user must have an id. Id was #{user['id']}.".red if user['id'] == nil
52
+
53
+ signature = Auth::signature(user['id'], @pwd)
54
+ return "#{error('POST', '/user', "PU-4")} Created user must have a valid signature. Should be '#{signature}' (was '#{user['signature']}')".red unless signature == user['signature']
55
+
56
+ created = DateTime.iso8601(user['created'])
57
+ return "#{error('POST', '/user', "PU-5")} Created user should have an ISO 8601 encoded creation timestamp.".red if created.to_time.to_i < send.to_time.to_i
58
+
59
+ @id = user['id']
60
+ rescue
61
+ return ([
62
+ "#{error('POST', '/user', "PU-6")}",
63
+ "POST on /register/user must return a valid JSON answer.",
64
+ "",
65
+ "---",
66
+ "#{res.body}",
67
+ "---",
68
+ "",
69
+ "This seems",
70
+ "- no valid JSON",
71
+ "- or creation timestamp is not ISO 8601 encoded."
72
+ ] * "\n").red
73
+ end
74
+
75
+ "Fine: Create user works".green
76
+ end
77
+
78
+ #
79
+ # Checks that listing users (GET /users) works as specified.
80
+ #
81
+ def listUsers
82
+ uri = URI("#{@host}/users")
83
+ res = Net::HTTP.get_response(uri)
84
+
85
+ begin
86
+
87
+ users = JSON.parse(res.body)
88
+
89
+ return "#{error('GET', '/users', "GU-1")} Only users should be returned.".red unless users.all? { |u| u['type'].downcase == 'user' }
90
+ return "#{error('GET', '/users', "GU-2")} Each user should have a name.".red unless users.all? { |u| u['name'] != nil }
91
+ return "#{error('GET', '/users', "GU-3")} Each user should have a id.".red unless users.all? { |u| u['id'] != nil }
92
+ return "#{error('GET', '/users', "GU-4")} Each user should have a signature.".red unless users.all? { |u| u['signature'] != nil }
93
+ return "#{error('GET', '/users', "GU-5")} No user should include played games".red if users.any? { |u| u['games'] != nil }
94
+
95
+ rescue
96
+ return ([
97
+ "#{error('GET', '/users', "GU-6")}",
98
+ "List users did not return a valid JSON answer:",
99
+ "#{res.body}"
100
+ ] * "\n").red
101
+
102
+ end
103
+ "Fine: List users works".green
104
+ end
105
+
106
+ #
107
+ # Checks that retrieving user data (GET /user/<id>) works as specified.
108
+ #
109
+ def readUser
110
+
111
+ # Check that users can queried by id
112
+
113
+ uri = URI("#{@host}/user/#{@id}")
114
+ res = Net::HTTP.get_response(uri)
115
+
116
+ return "#{error('GET', '/user/id', "GUI-1")} Only authenticated users should get user resource (code should be 401, was #{res.code})\n#{res.body}".red unless res.code == "401"
117
+
118
+ uri.query = URI.encode_www_form('id' => @id, 'pwd' => @pwd)
119
+ res = Net::HTTP.get_response(uri)
120
+
121
+ return "#{error('GET', '/user/id', "GUI-2")} Authenticated and registered user should get its personal user resource".red unless res.code == "200"
122
+
123
+ begin
124
+
125
+ user = JSON.parse(res.body)
126
+ return "#{error('GET', '/user/id', "GUI-3")} Name should be '#{@user}', was '#{user['name']}'".red unless user['name'] == @user
127
+ return "#{error('GET', '/user/id', "GUI-4")} Id should be '#{@id}', was '#{user['id']}'".red unless user['id'] == @id
128
+ return "#{error('GET', '/user/id', "GUI-5")} Type should be 'user', was '#{user['type']}'".red unless user['type'] == 'user'
129
+ return "#{error('GET', '/user/id', "GUI-6")} Answer should contain played games (ids)".red if user['games'] == nil
130
+
131
+ rescue
132
+ return ([
133
+ "#{error('GET', '/user/id', "GUI-7")}",
134
+ "Get user did not return a valid JSON answer:",
135
+ "#{res.body}"
136
+ ] * "\n").red
137
+ end
138
+
139
+ # Check that users can queried by name (name must be URI encoded)
140
+
141
+ uri = URI(@host)
142
+ http = Net::HTTP.new(uri.host, uri.port)
143
+
144
+ request = Net::HTTP::Get.new("/user/#{URI.encode(@user)}")
145
+ request.set_form_data({
146
+ "pwd" => "#{@pwd}",
147
+ 'byname' => 'wrong'
148
+ })
149
+ res = http.request(request)
150
+ return "#{error('GET', '/user/name', "GUI-8")} wrong byname parameter should end in status code 400 (Bad Request), was #{res.code}".red unless res.code == "400"
151
+
152
+ request = Net::HTTP::Get.new("/user/#{URI.encode(@user)}")
153
+ request.set_form_data({
154
+ "pwd" => "#{@pwd}",
155
+ 'byname' => 'true'
156
+ })
157
+ res = http.request(request)
158
+ begin
159
+
160
+ user = JSON.parse(res.body)
161
+ return "#{error('GET', '/user/name', "GUI-9")} Name should be '#{@user}', was '#{user['name']}'".red unless user['name'] == @user
162
+ return "#{error('GET', '/user/name', "GUI-10")} Id should be '#{@id}', was '#{user['id']}'".red unless user['id'] == @id
163
+ return "#{error('GET', '/user/name', "GUI-11")} Type should be 'user', was '#{user['type']}'".red unless user['type'] == 'user'
164
+ return "#{error('GET', '/user/name', "GUI-12")} Answer should contain played games (ids)".red if user['games'] == nil
165
+
166
+ rescue
167
+ return ([
168
+ "#{error('GET', '/user/name', "GUI-13")}",
169
+ "Get user did not return a valid JSON answer:",
170
+ "#{res.body}"
171
+ ] * "\n").red
172
+ end
173
+
174
+
175
+ "Fine: Read user works".green
176
+
177
+ end
178
+
179
+ #
180
+ # Checks that updating user data (PUT /user/<id>) works as specified.
181
+ #
182
+ def updateUser
183
+
184
+ uri = URI(@host)
185
+ http = Net::HTTP.new(uri.host, uri.port)
186
+
187
+ unauth_request = Net::HTTP::Put.new("/user/#{@id}")
188
+ unauth_request.set_form_data({
189
+ "name" => "New Name",
190
+ "mail" => "this.is@mail.com"
191
+ })
192
+
193
+ res = http.request(unauth_request)
194
+ return "#{error('PUT', '/user/id', "PU-1")} Only authenticated users should update their user resource (code should be 401, was #{res.code})".red unless res.code == "401"
195
+
196
+ new_name = "New Name"
197
+ new_mail = "this.is@mail.com"
198
+ new_pwd = "new password"
199
+ auth_request = Net::HTTP::Put.new("/user/#{@id}")
200
+ auth_request.set_form_data({
201
+ "pwd" => "#{@pwd}",
202
+ "name" => new_name,
203
+ "mail" => new_mail,
204
+ "newpwd" => new_pwd
205
+ })
206
+ res = http.request(auth_request)
207
+
208
+ begin
209
+ user = JSON.parse(res.body)
210
+ return "#{error('PUT', '/user/id', "PU-2")} Name should be '#{new_name}', was '#{user['name']}'".red unless user['name'] == new_name
211
+ return "#{error('PUT', '/user/id', "PU-3")} Mail should be '#{new_mail}', was '#{user['mail']}'".red unless user['mail'] == new_mail
212
+
213
+ return "#{error('PUT', '/user/id', "PU-4")} Id should be '#{@id}', was '#{user['id']}'.".red unless user['id'] == @id
214
+ return "#{error('PUT', '/user/id', "PU-5")} Type should be 'user', was '#{user['type']}'.".red unless user['type'] == 'user'
215
+ return "#{error('PUT', '/user/id', "PU-6")} Answer should contain no played games (ids).".red if user['games'] != nil
216
+ return "#{error('PUT', '/user/id', "PU-7")} Signature should be updated on password change.".red unless Auth::authentic?(user, new_pwd)
217
+
218
+ rescue Exception => ex
219
+ return ([
220
+ "#{error('PUT', '/user/id', "PU-8")}",
221
+ "Update user did not return a valid JSON answer.",
222
+ "Instead, we got exception: #{ex}",
223
+ "#{res.body}"
224
+ ] * "\n").red
225
+
226
+ end
227
+
228
+ "Fine: Update user works".green
229
+ end
230
+
231
+ #
232
+ # Checks that deleteing user data (DELETE /user/<id>) works as specified.
233
+ #
234
+ def deleteUser
235
+ uri = URI(@host)
236
+ http = Net::HTTP.new(uri.host, uri.port)
237
+
238
+ unauth_request = Net::HTTP::Delete.new("/user/#{@id}")
239
+
240
+ res = http.request(unauth_request)
241
+ return "#{error('DELETE', '/user/id', "DU-1")} Only authenticated users should delete their user resource (code should be 401, was #{res.code})".red unless res.code == "401"
242
+
243
+ auth_request = Net::HTTP::Delete.new("/user/#{@id}")
244
+ auth_request.set_form_data({
245
+ "pwd" => "new password",
246
+ })
247
+
248
+ res = http.request(auth_request)
249
+ return "#{error('DELETE', '/user/id', "DU-2")} Authenticated users should delete their user resource (code should be 200, was #{res.code})".red unless res.code == "200"
250
+
251
+ auth_request = Net::HTTP::Delete.new("/user/#{@id}")
252
+ auth_request.set_form_data({
253
+ "secret" => "new password",
254
+ })
255
+
256
+ res = http.request(auth_request)
257
+ return "#{error('DELETE', '/user/id', "DU-3")} Deletion of users should be idempotent (code should be 200, was #{res.code})\n#{res.body}".red unless res.code == "200"
258
+
259
+ "Fine: Delete user works".green
260
+ end
261
+
262
+ #
263
+ # Performs some stress tests on user resources.
264
+ #
265
+ def stressUser
266
+ uri = URI(@host)
267
+ http = Net::HTTP.new(uri.host, uri.port)
268
+
269
+ 1000.times do |i|
270
+ request = Net::HTTP::Post.new("/user")
271
+ name = "John Doe #{i}"
272
+ request.set_form_data({
273
+ "name" => name,
274
+ "pwd" => ""
275
+ })
276
+ res = http.request(request)
277
+ return "#{error('POST', '/user', "SU-1")} Creating user with name '#{name}' failed while stress testing.\n#{res.body}".red unless res.code == "200"
278
+ end
279
+
280
+ list_users = Net::HTTP::Get.new("/users")
281
+ res = http.request(list_users);
282
+ users = JSON.parse(res.body)
283
+
284
+ return "#{error('GET', '/users', "SU-2")} #{users.count} users have been created. Should be 1000.".red unless users.count == 1000
285
+
286
+ users.each do |user|
287
+ delete_user = Net::HTTP::Delete.new("/user/#{user['id']}")
288
+ delete_user.set_form_data({
289
+ "pwd" => ""
290
+ })
291
+ res = http.request(delete_user)
292
+ return "#{error('DELETE', '/user/id', "SU-3")} Deleting user with id '#{user['name']} (#{user['id']})' failed while stress testing.\n#{res.body}".red unless res.code == "200"
293
+ end
294
+
295
+ "Fine: Stress testing of user resources works".green
296
+ end
297
+
298
+ #
299
+ # Groups all user resource related test cases.
300
+ #
301
+ def userResourceHandling
302
+ puts "Checking user resource handling"
303
+ puts createUser
304
+ puts listUsers
305
+ puts readUser
306
+ puts updateUser
307
+ puts deleteUser
308
+ puts stressUser
309
+ end
310
+
311
+ #
312
+ # Checks that creating a game (POST /game) works as specified.
313
+ #
314
+ def createGame
315
+
316
+ uri = URI(@host)
317
+ http = Net::HTTP.new(uri.host, uri.port)
318
+
319
+ request = Net::HTTP::Post.new("/game")
320
+ request.set_form_data({
321
+ 'name' => @game,
322
+ 'secret' => @secret
323
+ })
324
+
325
+ send = DateTime.now
326
+ res = http.request(request)
327
+
328
+ return "#{error('POST', '/game', "PG-1")} Could not create game '#{@game}' (should return HTTP code 200, was #{res.code})\n #{res.body}".red unless (res.code == "200")
329
+
330
+ begin
331
+ game = JSON.parse(res.body)
332
+ return "#{error('POST', '/game', "PG-2")} Created game has wrong name. Should be '#{@game}', was #{game['name']}.".red unless game['name'] == @game
333
+ return "#{error('POST', '/game', "PG-3")} Created game must have an id. Id was #{game['id']}.".red if game['id'] == nil
334
+
335
+ signature = Auth::signature(game['id'], @pwd)
336
+ return "#{error('POST', '/game', "PG-4")} Created game must have a valid signature. Should be '#{signature}' (was '#{game['signature']}')".red unless signature == game['signature']
337
+
338
+ created = DateTime.iso8601(game['created'])
339
+ return "#{error('POST', '/game', "PG-4")} Created game should have an ISO 8601 encoded creation timestamp.".red if created.to_time.to_i < send.to_time.to_i
340
+
341
+ @gid = game['id']
342
+ rescue
343
+ return ([
344
+ "#{error('POST', '/game', "PG-5")}",
345
+ "POST on /game must return a valid JSON answer.",
346
+ "",
347
+ "---",
348
+ "#{res.body}",
349
+ "---",
350
+ "",
351
+ "This seems",
352
+ "- no valid JSON",
353
+ "- or creation timestamp is not ISO 8601 encoded."
354
+ ] * "\n").red
355
+ end
356
+
357
+ "Fine: Create game works".green
358
+ end
359
+
360
+ #
361
+ # Checks that listing all games (GET /games) works as specified.
362
+ #
363
+ def listGames
364
+ uri = URI(@host)
365
+ http = Net::HTTP.new(uri.host, uri.port)
366
+ request = Net::HTTP::Get.new("/games")
367
+
368
+ res = http.request(request)
369
+
370
+ begin
371
+
372
+ games = JSON.parse(res.body)
373
+
374
+ return "#{error('GET', '/games', "GG-1")} Only games should be returned.".red unless games.all? { |g| g['type'].downcase == 'game' }
375
+ return "#{error('GET', '/games', "GG-2")} Each game should have a name.".red unless games.all? { |g| g['name'] != nil }
376
+ return "#{error('GET', '/games', "GG-3")} Each game should have a id.".red unless games.all? { |g| g['id'] != nil }
377
+ return "#{error('GET', '/games', "GG-4")} Each game should have a signature.".red unless games.all? { |g| g['signature'] != nil }
378
+ return "#{error('GET', '/games', "GG-5")} No game should include users".red if games.any? { |g| g['users'] != nil }
379
+
380
+ rescue
381
+ return ([
382
+ "#{error('GET', '/games', "GG-6")}",
383
+ "List games did not return a valid JSON answer:",
384
+ "#{res.body}"
385
+ ] * "\n").red
386
+
387
+ end
388
+ "Fine: List games works".green
389
+ end
390
+
391
+ #
392
+ # Checks that retrieving game data (GET /game/<id>) works as specified.
393
+ #
394
+ def readGame
395
+ uri = URI(@host)
396
+ http = Net::HTTP.new(uri.host, uri.port)
397
+ request = Net::HTTP::Get.new("/game/#{@gid}")
398
+ res = http.request(request)
399
+
400
+ return "#{error('GET', '/game/id', "GGI-1")} Only authenticated games should get game resource (code should be 401, was #{res.code})\n#{res.body}".red unless res.code == "401"
401
+
402
+ request = Net::HTTP::Get.new("/game/#{@gid}")
403
+ request.set_form_data({
404
+ "secret" => "#{@secret}",
405
+ })
406
+ res = http.request(request)
407
+
408
+ return "#{error('GET', '/game/id', "GGI-2")} Authenticated and registered games should get their game resource\n#{res.body}".red unless res.code == "200"
409
+
410
+ begin
411
+
412
+ game = JSON.parse(res.body)
413
+ return "#{error('GET', '/game/id', "GGI-3")} Name should be '#{@game}', was '#{game['name']}'".red unless game['name'] == @game
414
+ return "#{error('GET', '/game/id', "GGI-4")} Id should be '#{@id}', was '#{game['id']}'".red unless game['id'] == @gid
415
+ return "#{error('GET', '/game/id', "GGI-5")} Type should be 'game', was '#{game['type']}'".red unless game['type'] == 'game'
416
+ return "#{error('GET', '/game/id', "GGI-6")} Answer should contain users (ids) that played the game.\n#{game}".red if game['users'] == nil
417
+
418
+ rescue
419
+ return ([
420
+ "#{error('GET', '/game/id', "GGI-7")}",
421
+ "Get game did not return a valid JSON answer:",
422
+ "#{res.body}"
423
+ ] * "\n").red
424
+ end
425
+
426
+ "Fine: Read game works".green
427
+ end
428
+
429
+ #
430
+ # Checks that updating game data (PUT /game/<id>) works as specified.
431
+ #
432
+ def updateGame
433
+
434
+ uri = URI(@host)
435
+ http = Net::HTTP.new(uri.host, uri.port)
436
+
437
+ unauth_request = Net::HTTP::Put.new("/game/#{@gid}")
438
+ unauth_request.set_form_data({
439
+ "name" => "New Game Name",
440
+ })
441
+
442
+ res = http.request(unauth_request)
443
+ return "#{error('PUT', '/game/id', "PUG-1")} Only authenticated games should update their game resource (code should be 401, was #{res.code})\n#{res.body}".red unless res.code == "401"
444
+
445
+ new_name = "New Game Name"
446
+ new_secret = "new secret"
447
+ new_url = "http://www.example.games/new+game+name"
448
+ auth_request = Net::HTTP::Put.new("/game/#{@gid}")
449
+ auth_request.set_form_data({
450
+ "secret" => "#{@secret}",
451
+ "name" => new_name,
452
+ "url" => new_url,
453
+ "newsecret" => new_secret
454
+ })
455
+ res = http.request(auth_request)
456
+
457
+ begin
458
+ game = JSON.parse(res.body)
459
+ return "#{error('PUT', '/game/id', "PUG-2")} Name should be '#{new_name}', was '#{game['name']}'".red unless game['name'] == new_name
460
+ return "#{error('PUT', '/game/id', "PUG-2")} Url should be '#{new_url}', was '#{game['url']}'".red unless game['url'] == new_url
461
+
462
+ return "#{error('PUT', '/game/id', "PUG-3")} Id should be '#{@gid}', was '#{game['id']}'.".red unless game['id'] == @gid
463
+ return "#{error('PUT', '/game/id', "PUG-4")} Type should be 'game', was '#{game['type']}'.".red unless game['type'] == 'game'
464
+ return "#{error('PUT', '/game/id', "PUG-5")} Answer should contain no users (ids) that played the game.".red if game['users'] != nil
465
+ return "#{error('PUT', '/game/id', "PUG-6")} Signature should be updated on secret change.".red unless Auth::authentic?(game, new_secret)
466
+
467
+ rescue Exception => ex
468
+ return ([
469
+ "#{error('PUT', '/game/id', "PUG-7")}",
470
+ "Update game did not return a valid JSON answer.",
471
+ "Instead, we got exception: #{ex}",
472
+ "#{res.body}"
473
+ ] * "\n").red
474
+
475
+ end
476
+
477
+ "Fine: Update game works".green
478
+ end
479
+
480
+ #
481
+ # Checks that deleting a game (DELETE /game/<id>) works as specified.
482
+ #
483
+ def deleteGame
484
+ uri = URI(@host)
485
+ http = Net::HTTP.new(uri.host, uri.port)
486
+
487
+ unauth_request = Net::HTTP::Delete.new("/game/#{@gid}")
488
+
489
+ res = http.request(unauth_request)
490
+ return "#{error('DELETE', '/game/id', "DG-1")} Only authenticated game should delete their game resource (code should be 401, was #{res.code})\n#{res.body}".red unless res.code == "401"
491
+
492
+ auth_request = Net::HTTP::Delete.new("/game/#{@gid}")
493
+ auth_request.set_form_data({
494
+ "secret" => "new secret",
495
+ })
496
+
497
+ res = http.request(auth_request)
498
+ return "#{error('DELETE', '/game/id', "DG-2")} Authenticated games should delete their game resource (code should be 200, was #{res.code})\n#{res.body}".red unless res.code == "200"
499
+
500
+ auth_request = Net::HTTP::Delete.new("/game/#{@gid}")
501
+ auth_request.set_form_data({
502
+ "secret" => "new secret",
503
+ })
504
+
505
+ res = http.request(auth_request)
506
+ return "#{error('DELETE', '/game/id', "DG-3")} Deletion of games should be idempotent (code should be 200, was #{res.code})\n#{res.body}".red unless res.code == "200"
507
+
508
+ "Fine: Delete game works".green
509
+ end
510
+
511
+ #
512
+ # Performs some stress tests on game resources.
513
+ #
514
+ def stressGame
515
+ uri = URI(@host)
516
+ http = Net::HTTP.new(uri.host, uri.port)
517
+
518
+ 1000.times do |i|
519
+ request = Net::HTTP::Post.new("/game")
520
+ name = "A Cool Game, #{i}th Edition"
521
+ request.set_form_data({
522
+ "name" => name,
523
+ "pwd" => ""
524
+ })
525
+ res = http.request(request)
526
+ return "#{error('POST', '/game', "SG-1")} Creating game with name '#{name}' failed while stress testing.\n#{res.body}".red unless res.code == "200"
527
+ end
528
+
529
+ list_games = Net::HTTP::Get.new("/games")
530
+ res = http.request(list_games);
531
+ games = JSON.parse(res.body)
532
+
533
+ return "#{error('GET', '/games', "SG-2")} Only #{games.count} users have been created. Should be 1000.".red unless games.count == 1000
534
+
535
+ games.each do |game|
536
+ delete_game = Net::HTTP::Delete.new("/game/#{game['id']}")
537
+ delete_game.set_form_data({
538
+ "pwd" => ""
539
+ })
540
+ res = http.request(delete_game)
541
+ return "#{error('DELETE', '/game/id', "SG-3")} Deleting user with id '#{game['name']} (#{game['id']})' failed while stress testing.\n#{res.body}".red unless res.code == "200"
542
+ end
543
+
544
+ "Fine: Stress testing of game resources works".green
545
+ end
546
+
547
+ #
548
+ # Groups all user resource related test cases.
549
+ #
550
+ def gameResourceHandling
551
+ puts "Checking game resource handling"
552
+ puts createGame
553
+ puts listGames
554
+ puts readGame
555
+ puts updateGame
556
+ puts deleteGame
557
+ puts stressGame
558
+ end
559
+
560
+ #
561
+ # Helper routine to prepare some test users for
562
+ # game user resource relation tests.
563
+ #
564
+ def prepareUsers
565
+ uri = URI(@host)
566
+ http = Net::HTTP.new(uri.host, uri.port)
567
+
568
+ users = []
569
+
570
+ 3.times do |i|
571
+ create_user = Net::HTTP::Post.new("/user")
572
+ name = "User #{i + 1}"
573
+ create_user.set_form_data({
574
+ 'name' => name,
575
+ 'pwd' => "xyz"
576
+ })
577
+ res = http.request(create_user)
578
+ return "#{error('POST', '/user', "TESTUSER-1")} Could not create user '#{name}', #{res.body}".red unless res.code == "200"
579
+
580
+ users << JSON.parse(res.body)
581
+
582
+ end
583
+
584
+ users
585
+
586
+ end
587
+
588
+ #
589
+ # Helper routine to prepare some test games for
590
+ # game user resource relation tests.
591
+ #
592
+ def prepareGames
593
+ uri = URI(@host)
594
+ http = Net::HTTP.new(uri.host, uri.port)
595
+
596
+ games = []
597
+
598
+ 3.times do |i|
599
+ create_game = Net::HTTP::Post.new("/game")
600
+ name = "Game #{i + 1}"
601
+ create_game.set_form_data({
602
+ 'name' => name,
603
+ 'secret' => "xyz"
604
+ })
605
+ res = http.request(create_game)
606
+ return "#{error('POST', '/user', "TESTGAME-1")} Could not create game '#{name}', #{res.body}".red unless res.code == "200"
607
+
608
+ games << JSON.parse(res.body)
609
+
610
+ end
611
+
612
+ games
613
+
614
+ end
615
+
616
+ #
617
+ # Checks that deleting a game should delete all game related game states.
618
+ #
619
+ def deleteGameEntity(game)
620
+ uri = URI(@host)
621
+ http = Net::HTTP.new(uri.host, uri.port)
622
+
623
+ delete_game = Net::HTTP::Delete.new("/game/#{game['id']}")
624
+ delete_game.set_form_data({ 'secret' => 'xyz' })
625
+ res = http.request(delete_game)
626
+ return "#{error('DELETE', '/game/id', "DELETETESTGAME-1")} Could not delete game '#{game['name']}',\n#{res.body}".red unless res.code == "200"
627
+ "Fine: Deleted game '#{game['id']}' successfully.".green
628
+
629
+ end
630
+
631
+ #
632
+ # Checks that deleting a user should delete all user related game states.
633
+ #
634
+ def deleteUserEntity(user)
635
+ uri = URI(@host)
636
+ http = Net::HTTP.new(uri.host, uri.port)
637
+
638
+ delete_user = Net::HTTP::Delete.new("/user/#{user['id']}")
639
+ delete_user.set_form_data({ 'pwd' => 'xyz' })
640
+ res = http.request(delete_user)
641
+ return "#{error('DELETE', '/user/id', "DELETETESTUSER-1")} Could not delete user '#{user['name']}',\n#{res.body}".red unless res.code == "200"
642
+ "Fine: Deleted user '#{user['id']}' successfully.".green
643
+ end
644
+
645
+ #
646
+ # Checks that storing game states of a user playing a game works as intended.
647
+ #
648
+ def storeGamestate(game, user, n, state)
649
+ uri = URI(@host)
650
+ http = Net::HTTP.new(uri.host, uri.port)
651
+
652
+ gameid = game['id']
653
+ userid = user['id']
654
+
655
+ unauth_store_state = Net::HTTP::Post.new("/gamestate/#{gameid}/#{userid}")
656
+ unauth_store_state.set_form_data({
657
+ 'state' => JSON.pretty_generate(state)
658
+ })
659
+ res = http.request(unauth_store_state)
660
+ return "#{error('POST', '/gamestate/gid/uid', "PGS-1")} Store a state should only work for authenticated games, code expected 401, was #{res.code},\n#{res.body}".red unless res.code == "401"
661
+
662
+ store_state = Net::HTTP::Post.new("/gamestate/#{gameid}/#{userid}")
663
+ store_state.set_form_data({
664
+ 'secret' => 'xyz' ,
665
+ 'state' => JSON.pretty_generate(state)
666
+ })
667
+
668
+ n.times do
669
+ res = http.request(store_state)
670
+ return "#{error('POST', '/gamestate/gid/uid', "PGS-2")} Could not store state for game '#{gameid}' and user '#{userid}',\n#{res.body}".red unless res.code == "200"
671
+ end
672
+
673
+ unauth_get_states = Net::HTTP::Get.new("/gamestate/#{gameid}/#{userid}")
674
+ res = http.request(unauth_get_states)
675
+ return "#{error('GET', '/gamestate/gid/uid', "PGS-3")} Getting a state should only work for authenticated games, code expected 401, was #{res.code},\n#{res.body}".red unless res.code == "401"
676
+
677
+ get_states = Net::HTTP::Get.new("/gamestate/#{gameid}/#{userid}")
678
+ get_states.set_form_data({'secret' => 'xyz'})
679
+ res = http.request(get_states)
680
+ return "#{error('GET', '/gamestate/gid/uid', "PGS-4")} Getting stored states should work for authenticated games, code expected 200, was #{res.code},\n#{res.body}".red unless res.code == "200"
681
+
682
+ begin
683
+ states = JSON.parse(res.body)
684
+
685
+ return "#{error('GET', '/gamestate/gid/uid', "PGS-5")} Expected to retrieve #{n} gamestates, got #{states.count}".red unless states.count == n
686
+ return "#{error('GET', '/gamestate/gid/uid', "PGS-6")} Only gamestates should be returned.".red unless states.all? { |u| u['type'].downcase == 'gamestate' }
687
+ return "#{error('GET', '/gamestate/gid/uid', "PGS-7")} Each gamestate should have a gameid.".red unless states.all? { |u| u['gameid'] != nil }
688
+ return "#{error('GET', '/gamestate/gid/uid', "PGS-8")} Each gamestate should contain the game name.".red unless states.all? { |u| u['gamename'] != nil }
689
+ return "#{error('GET', '/gamestate/gid/uid', "PGS-9")} Each gamestate should have a userid.".red unless states.all? { |u| u['userid'] != nil }
690
+ return "#{error('GET', '/gamestate/gid/uid', "PGS-10")} Each gamestate should contain the user name.".red unless states.all? { |u| u['username'] != nil }
691
+ return "#{error('GET', '/gamestate/gid/uid', "PGS-11")} Each gamestate should have a creation timestamp.".red unless states.all? { |u| u['created'] != nil }
692
+ return "#{error('GET', '/gamestate/gid/uid', "PGS-12")} Each gamestate should have a JSON encoded state.".red unless states.all? { |u| u['state'] != nil }
693
+
694
+ now = Time.now.to_time.to_i
695
+ return "#{error('GET', '/gamestate/gid/uid', "PGS-13")} Each gamestate should be created in the past and should be indicated by an ISO 8601 encoded timestamp.".red if states.any? { |u| DateTime.iso8601(u['created']).to_time.to_i > now }
696
+
697
+ rescue Exception => ex
698
+ return "#{error('GET', '/gamestate/gid/uid', "PGS-14")} Retrieved state was not JSON encoded,\n #{res.body}\n#{ex}".red
699
+ end
700
+
701
+ "Fine: Stored #{n} states successfully.".green
702
+ end
703
+
704
+ #
705
+ # Checks that stored game states of a user playing a game can be listed as intended.
706
+ #
707
+ def listGameStates(game, user, n)
708
+
709
+ gameid = game['id']
710
+ userid = user['id']
711
+
712
+ uri = URI(@host)
713
+ http = Net::HTTP.new(uri.host, uri.port)
714
+
715
+ unauth_get_state = Net::HTTP::Get.new("/gamestate/#{gameid}/#{userid}")
716
+ res = http.request(unauth_get_state)
717
+ return "#{error('GET', '/gamestate/gid/uid', "GGS-1")} Getting game states should only work for authenticated games, code expected 401, was #{res.code},\n#{res.body}".red unless res.code == "401"
718
+
719
+ get_state = Net::HTTP::Get.new("/gamestate/#{gameid}/#{userid}")
720
+ get_state.set_form_data({ 'secret' => 'xyz' })
721
+
722
+ res = http.request(get_state)
723
+ return "#{error('GET', '/gamestate/gid/uid', "GGS-2")} Getting stored states should work for authenticated games, code expected 200, was #{res.code},\n#{res.body}".red unless res.code == "200"
724
+
725
+ begin
726
+ states = JSON.parse(res.body)
727
+
728
+ return "#{error('GET', '/gamestate/gid/uid', "GGS-3")} Expected to retrieve #{n} gamestates, got #{states.count}".red unless states.count == n
729
+ return "#{error('GET', '/gamestate/gid/uid', "GGS-4")} Only gamestates should be returned.".red unless states.all? { |u| u['type'].downcase == 'gamestate' }
730
+ return "#{error('GET', '/gamestate/gid/uid', "GGS-5")} Each gamestate should have a gameid.".red unless states.all? { |u| u['gameid'] != nil }
731
+ return "#{error('GET', '/gamestate/gid/uid', "GGS-6")} Each gamestate should contain the game name.".red unless states.all? { |u| u['gamename'] != nil }
732
+ return "#{error('GET', '/gamestate/gid/uid', "GGS-7")} Each gamestate should have a userid.".red unless states.all? { |u| u['userid'] != nil }
733
+ return "#{error('GET', '/gamestate/gid/uid', "GGS-8")} Each gamestate should contain the user name.".red unless states.all? { |u| u['username'] != nil }
734
+ return "#{error('GET', '/gamestate/gid/uid', "GGS-9")} Each gamestate should have a creation timestamp.".red unless states.all? { |u| u['created'] != nil }
735
+ return "#{error('GET', '/gamestate/gid/uid', "GGS-10")} Each gamestate should have a JSON encoded state.".red unless states.all? { |u| u['state'] != nil }
736
+
737
+ now = Time.now.to_time.to_i
738
+ return "#{error('GET', '/gamestate/gid/uid', "GGS-11")} Each gamestate should be created in the past and should be indicated by an ISO 8601 encoded timestamp.".red if states.any? { |u| DateTime.iso8601(u['created']).to_time.to_i > now }
739
+
740
+ rescue Exception => ex
741
+ return "#{error('GET', '/gamestate/gid/uid', "GGS-12")} Retrieved state was not JSON encoded,\n #{res.body}\n#{ex}".red
742
+ end
743
+
744
+ "Fine: Retrieved #{n} states successfully.".green
745
+
746
+ end
747
+
748
+ #
749
+ # Checks that a user having gamestates related to game should be indicated to play the game.
750
+ #
751
+ def checkUserPlays(user, games)
752
+ uri = URI(@host)
753
+ http = Net::HTTP.new(uri.host, uri.port)
754
+
755
+ gameids = games.map { |g| g['id'] }
756
+ userid = user['id']
757
+
758
+ get_states = Net::HTTP::Get.new("/user/#{userid}")
759
+ get_states.set_form_data({'pwd' => 'xyz'})
760
+ res = http.request(get_states)
761
+
762
+ return "#{error('GET', '/user/id', "UP-1")} Could not get user id #{userid},\n#{res.body}".red unless res.code == "200"
763
+
764
+ user = JSON.parse(res.body)
765
+ return "#{error('GET', '/user/id', "UP-2")} Expected user #{userid} to play #{gameids}, received #{user['games']}".red unless (gameids - user['games']).empty? && (user['games'] - gameids).empty?
766
+
767
+ "Fine: Checked that user #{userid} plays games #{gameids}.".green
768
+ end
769
+
770
+ #
771
+ # Checks that all gamestates stored can be listed.
772
+ #
773
+ def checkUserGameStates(user, game, n)
774
+ uri = URI(@host)
775
+ http = Net::HTTP.new(uri.host, uri.port)
776
+
777
+ gameid = game['id']
778
+ userid = user['id']
779
+
780
+ get_states = Net::HTTP::Get.new("/gamestate/#{gameid}/#{userid}")
781
+ get_states.set_form_data({'secret' => 'xyz', 'pwd' => 'xyz'})
782
+
783
+
784
+ res = http.request(get_states)
785
+ return "#{error('GET', '/gamestate/gid/uid', "GUS-1")} Could not get gamestates for game id #{gameid} and userid '#{userid}',\n#{res.body}".red unless res.code == "200"
786
+
787
+ states = JSON.parse(res.body)
788
+ return "#{error('GET', '/gamestate/gid/uid', "GUS-2")} Expected to retrieve #{n} gamestates, got #{states.count}".red unless states.count == n
789
+
790
+ state = states.shift
791
+ while (state != nil)
792
+ follower = states.shift
793
+ if (follower != nil)
794
+ return "#{error('GET', '/gamestate/gid/uid', "GUS-3")} Gamestates should be returned by decreasing creation order".red unless Time.parse(state['created']) > Time.parse(follower['created'])
795
+ end
796
+ state = follower
797
+ end
798
+
799
+ "Fine: Checked that gamestates are returned in decreasing creation timestamp order.".green
800
+
801
+ end
802
+
803
+ #
804
+ # Groups all gamestate resource related test cases.
805
+ #
806
+ def gamestateResourceHandling
807
+
808
+ users = prepareUsers
809
+ games = prepareGames
810
+
811
+ puts "Checking gamestate resource handling"
812
+ puts storeGamestate(games[0], users[0], 3, Defaults::TESTLIST)
813
+ puts storeGamestate(games[1], users[0], 2, Defaults::TESTHASH)
814
+ puts storeGamestate(games[1], users[1], 1, Defaults::TESTHASH)
815
+
816
+ puts checkUserGameStates(users[0], games[0], 3)
817
+ puts checkUserGameStates(users[0], games[1], 2)
818
+ puts checkUserGameStates(users[1], games[1], 1)
819
+
820
+ puts listGameStates(games[0], users[0], 3)
821
+ puts listGameStates(games[1], users[0], 2)
822
+ puts listGameStates(games[1], users[1], 1)
823
+ puts listGameStates(games[2], users[2], 0)
824
+
825
+ puts checkUserPlays(users[0], [games[0], games[1]])
826
+ puts checkUserPlays(users[1], [games[1]])
827
+ puts checkUserPlays(users[2], [])
828
+
829
+ puts deleteGameEntity(games[2])
830
+
831
+ puts checkUserPlays(users[0], [games[0], games[1]])
832
+ puts checkUserPlays(users[1], [games[1]])
833
+ puts checkUserPlays(users[2], [])
834
+
835
+ puts deleteUserEntity(users[2])
836
+
837
+ puts checkUserPlays(users[0], [games[0], games[1]])
838
+ puts checkUserPlays(users[1], [games[1]])
839
+
840
+ puts deleteGameEntity(games[1])
841
+
842
+ puts checkUserPlays(users[0], [games[0]])
843
+ puts checkUserPlays(users[1], [])
844
+
845
+ puts deleteGameEntity(games[0])
846
+ puts checkUserPlays(users[0], [])
847
+ puts checkUserPlays(users[1], [])
848
+
849
+ puts deleteUserEntity(users[1])
850
+ puts deleteUserEntity(users[0])
851
+
852
+ end
853
+
854
+ end