steam-condenser 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/README.md +2 -1
  2. data/Rakefile +10 -1
  3. data/lib/steam-condenser/version.rb +1 -1
  4. data/lib/steam/community/app_news.rb +0 -0
  5. data/lib/steam/community/game_leaderboard.rb +199 -0
  6. data/lib/steam/community/game_leaderboard_entry.rb +43 -0
  7. data/lib/steam/community/game_stats.rb +16 -0
  8. data/lib/steam/community/steam_game.rb +18 -0
  9. data/lib/steam/community/steam_group.rb +9 -4
  10. data/lib/steam/community/steam_id.rb +45 -41
  11. data/lib/steam/community/tf2/tf2_beta_inventory.rb +22 -0
  12. data/lib/steam/community/tf2/tf2_golden_wrench.rb +0 -0
  13. data/lib/steam/community/tf2/tf2_stats.rb +10 -4
  14. data/lib/steam/community/web_api.rb +0 -0
  15. data/lib/steam/servers/master_server.rb +2 -1
  16. data/lib/steam/servers/server.rb +1 -1
  17. data/lib/steam/sockets/rcon_socket.rb +0 -1
  18. data/lib/steam/sockets/steam_socket.rb +2 -1
  19. data/steam-condenser.gemspec +5 -4
  20. data/test/core_ext/test_stringio.rb +59 -0
  21. data/test/fixtures/invalid.xml +2 -0
  22. data/test/fixtures/sonofthor.xml +882 -0
  23. data/test/fixtures/status_goldsrc +3 -0
  24. data/test/fixtures/status_source +3 -0
  25. data/test/fixtures/valve-members.xml +231 -0
  26. data/test/helper.rb +37 -0
  27. data/test/steam/communtiy/test_steam_group.rb +83 -0
  28. data/test/steam/communtiy/test_steam_id.rb +85 -0
  29. data/test/steam/communtiy/test_web_api.rb +98 -0
  30. data/test/steam/servers/test_game_server.rb +308 -0
  31. data/test/steam/servers/test_goldsrc_server.rb +59 -0
  32. data/test/steam/servers/test_master_server.rb +131 -0
  33. data/test/steam/servers/test_server.rb +72 -0
  34. data/test/steam/servers/test_source_server.rb +140 -0
  35. data/test/steam/sockets/test_goldsrc_socket.rb +127 -0
  36. data/test/steam/sockets/test_master_server_socket.rb +41 -0
  37. data/test/steam/sockets/test_rcon_socket.rb +109 -0
  38. data/test/steam/sockets/test_source_socket.rb +77 -0
  39. data/test/steam/sockets/test_steam_socket.rb +97 -0
  40. metadata +94 -34
  41. data/Gemfile.lock +0 -22
  42. data/test/query_tests.rb +0 -70
  43. data/test/rcon_tests.rb +0 -78
  44. data/test/steam/communtiy/steam_community_test_suite.rb +0 -12
  45. data/test/steam/communtiy/steam_group_tests.rb +0 -44
  46. data/test/steam/communtiy/steam_id_tests.rb +0 -49
  47. data/test/steam_community_tests.rb +0 -45
  48. data/test/stringio_additions_tests.rb +0 -77
@@ -0,0 +1,98 @@
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2011, Sebastian Staudt
5
+
6
+ require 'helper'
7
+ require 'steam/community/web_api'
8
+
9
+ class TestWebApi < Test::Unit::TestCase
10
+
11
+ context 'The Web API' do
12
+
13
+ setup do
14
+ WebApi.api_key = '0123456789ABCDEF0123456789ABCDEF'
15
+ end
16
+
17
+ should 'allow access to the API key' do
18
+ assert_equal '0123456789ABCDEF0123456789ABCDEF', WebApi.api_key
19
+ end
20
+
21
+ should 'allow to set the API key' do
22
+ WebApi.api_key = 'FEDCBA9876543210FEDCBA9876543210'
23
+
24
+ assert_equal 'FEDCBA9876543210FEDCBA9876543210', WebApi.api_key
25
+ end
26
+
27
+ should 'fail to set an invalid API key' do
28
+ error = assert_raises WebApiError do
29
+ WebApi.api_key = 'test'
30
+ end
31
+ assert_equal 'This is not a valid Steam Web API key.', error.message
32
+ end
33
+
34
+ should 'provide easy access to JSON data' do
35
+ WebApi.expects(:get).with :json, 'interface', 'method', 2, { :test => 'param' }
36
+
37
+ WebApi.json 'interface', 'method', 2, { :test => 'param' }
38
+ end
39
+
40
+ should 'provide easy access to parsed JSON data' do
41
+ data = mock
42
+ WebApi.expects(:json).with('interface', 'method', 2, { :test => 'param' }).
43
+ returns data
44
+ MultiJson.expects(:decode).with(data, { :symbolize_keys => true }).
45
+ returns({ :result => { :status => 1 }})
46
+
47
+ assert_equal({ :status => 1 }, WebApi.json!('interface', 'method', 2, { :test => 'param' }))
48
+ end
49
+
50
+ should 'raise an error if the parsed JSON data is an error message' do
51
+ data = mock
52
+ WebApi.expects(:json).with('interface', 'method', 2, { :test => 'param' }).
53
+ returns data
54
+ MultiJson.expects(:decode).with(data, { :symbolize_keys => true }).
55
+ returns({ :result => { :status => 2, :statusDetail => 'error' } })
56
+
57
+ error = assert_raises WebApiError do
58
+ WebApi.json! 'interface', 'method', 2, { :test => 'param' }
59
+ end
60
+ assert_equal 'The Web API request failed with the following error: error (status code: 2).', error.message
61
+ end
62
+
63
+ should 'load data from the Steam Community Web API' do
64
+ data = mock :read => 'data'
65
+ WebApi.expects(:open).with do |url, options|
66
+ options == { :proxy => true } &&
67
+ url.start_with?('http://api.steampowered.com/interface/method/v0002/?') &&
68
+ (url.split('?').last.split('&') & %w{test=param format=json key=0123456789ABCDEF0123456789ABCDEF}).size == 3
69
+ end.returns data
70
+
71
+ assert_equal 'data', WebApi.get(:json, 'interface', 'method', 2, { :test => 'param' })
72
+ end
73
+
74
+ should 'handle unauthorized access error when loading data' do
75
+ io = mock :status => [401]
76
+ http_error = OpenURI::HTTPError.new '', io
77
+ WebApi.expects(:open).raises http_error
78
+
79
+ error = assert_raises WebApiError do
80
+ WebApi.get :json, 'interface', 'method', 2, { :test => 'param' }
81
+ end
82
+ assert_equal 'Your Web API request has been rejected. You most likely did not specify a valid Web API key.', error.message
83
+ end
84
+
85
+ should 'handle generic HTTP errors when loading data' do
86
+ io = mock :status => [[404, 'Not found']]
87
+ http_error = OpenURI::HTTPError.new '', io
88
+ WebApi.expects(:open).raises http_error
89
+
90
+ error = assert_raises WebApiError do
91
+ WebApi.get :json, 'interface', 'method', 2, { :test => 'param' }
92
+ end
93
+ assert_equal 'The Web API request has failed due to an HTTP error: Not found (status code: 404).', error.message
94
+ end
95
+
96
+ end
97
+
98
+ end
@@ -0,0 +1,308 @@
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2011, Sebastian Staudt
5
+
6
+ require 'helper'
7
+ require 'steam/servers/game_server'
8
+
9
+ class TestGameServer < Test::Unit::TestCase
10
+
11
+ context 'A generic game server' do
12
+
13
+ class GenericGameServer
14
+ include GameServer
15
+ end
16
+
17
+ setup do
18
+ Socket.stubs(:getaddrinfo).
19
+ with('game', 27015, Socket::AF_INET, Socket::SOCK_DGRAM).
20
+ returns [[nil, nil, 'game', '127.0.0.1']]
21
+ @socket = mock
22
+
23
+ @server = GenericGameServer.new 'game', 27015
24
+ @server.instance_variable_set :@socket, @socket
25
+ end
26
+
27
+ should 'send packets using its client socket' do
28
+ packet = mock
29
+ @socket.expects(:send).with packet
30
+
31
+ @server.send :send_request, packet
32
+ end
33
+
34
+ should 'get replies using its client socket' do
35
+ packet = mock
36
+ @socket.expects(:reply).returns packet
37
+
38
+ assert_equal packet, @server.send(:reply)
39
+ end
40
+
41
+ should 'be able to calculate the latency of the server' do
42
+ @server.expects(:send_request).with do |packet|
43
+ packet.is_a? A2S_INFO_Packet
44
+ end
45
+ @server.expects(:reply).with { || sleep 0.05 }
46
+
47
+ @server.update_ping
48
+ assert_operator @server.instance_variable_get(:@ping), :>=, 50
49
+ end
50
+
51
+ should 'be able to get a challenge from the server' do
52
+ @server.expects(:handle_response_for_request).with :challenge
53
+
54
+ @server.update_challenge_number
55
+ end
56
+
57
+ should 'be able to get information about server' do
58
+ @server.expects(:handle_response_for_request).with :info
59
+
60
+ @server.update_server_info
61
+ end
62
+
63
+ should 'be able to get the server rules' do
64
+ @server.expects(:handle_response_for_request).with :rules
65
+
66
+ @server.update_rules
67
+ end
68
+
69
+ should 'be able to get the players on the server' do
70
+ @server.expects(:handle_response_for_request).with :players
71
+
72
+ @server.update_players
73
+ end
74
+
75
+ should 'provide a convenience wrapper for basic server methods' do
76
+ @server.expects :update_ping
77
+ @server.expects :update_server_info
78
+ @server.expects :update_challenge_number
79
+
80
+ @server.init
81
+ end
82
+
83
+ should 'know if its RCON connection is authenticated' do
84
+ assert_equal @server.instance_variable_get(:@rcon_authenticated),
85
+ @server.rcon_authenticated?
86
+ end
87
+
88
+ should 'cache the ping of the server' do
89
+ @server.expects :update_ping
90
+
91
+ @server.ping
92
+
93
+ @server.instance_variable_set :@ping, 0
94
+
95
+ @server.ping
96
+ end
97
+
98
+ should 'cache the players on the server' do
99
+ @server.expects :update_players
100
+
101
+ @server.players
102
+
103
+ @server.instance_variable_set :@player_hash, 0
104
+
105
+ @server.players
106
+ end
107
+
108
+ should 'cache the server rules' do
109
+ @server.expects :update_rules
110
+
111
+ @server.rules
112
+
113
+ @server.instance_variable_set :@rules_hash, 0
114
+
115
+ @server.rules
116
+ end
117
+
118
+ should 'cache the server information' do
119
+ @server.expects :update_server_info
120
+
121
+ @server.server_info
122
+
123
+ @server.instance_variable_set :@info_hash, 0
124
+
125
+ @server.server_info
126
+ end
127
+
128
+ context 'be able to get additional information about the players on a Source server' do
129
+
130
+ setup do
131
+ status = fixture 'status_source'
132
+
133
+ @someone = mock
134
+ @somebody = mock
135
+ player_hash = { 'someone' => @someone, 'somebody' => @somebody }
136
+ @server.instance_variable_set :@player_hash, player_hash
137
+
138
+ @server.expects(:handle_response_for_request).with :players
139
+ @server.expects(:rcon_exec).with('status').returns status
140
+
141
+ someone_data = { :name => 'someone', :userid => '1', :uniqueid => 'STEAM_0:0:123456', :score => '10', :time => '3:52', :ping => '12', :loss => '0', :state => 'active' }
142
+ somebody_data = { :name => 'somebody', :userid => '2', :uniqueid => 'STEAM_0:0:123457', :score => '3', :time => '2:42', :ping => '34', :loss => '0', :state => 'active' }
143
+
144
+ attributes = mock
145
+ GameServer.expects(:player_status_attributes).
146
+ with('userid name uniqueid score connected ping loss state').
147
+ returns attributes
148
+ GameServer.expects(:split_player_status).
149
+ with(attributes, '1 "someone" STEAM_0:0:123456 10 3:52 12 0 active').
150
+ returns somebody_data
151
+ GameServer.expects(:split_player_status).
152
+ with(attributes, '2 "somebody" STEAM_0:0:123457 3 2:42 34 0 active').
153
+ returns someone_data
154
+
155
+ @somebody.expects(:add_info).with somebody_data
156
+ @someone.expects(:add_info).with someone_data
157
+ end
158
+
159
+ should 'with the RCON password' do
160
+ @server.expects(:rcon_auth).with 'password'
161
+
162
+ @server.update_players 'password'
163
+ end
164
+
165
+ should 'if the RCON connection is authenticated' do
166
+ @server.instance_variable_set :@rcon_authenticated, true
167
+
168
+ @server.update_players
169
+ end
170
+
171
+ end
172
+
173
+ context 'be able to get additional information about the players on a GoldSrc server' do
174
+
175
+ setup do
176
+ status = fixture 'status_goldsrc'
177
+
178
+ @someone = mock
179
+ @somebody = mock
180
+ player_hash = { 'someone' => @someone, 'somebody' => @somebody }
181
+ @server.instance_variable_set :@player_hash, player_hash
182
+
183
+ @server.expects(:handle_response_for_request).with :players
184
+ @server.expects(:rcon_exec).with('status').returns status
185
+
186
+ someone_data = { :name => 'someone', :userid => '1', :uniqueid => 'STEAM_0:0:123456', :score => '10', :time => '3:52', :ping => '12', :loss => '0', :adr => '0' }
187
+ somebody_data = { :name => 'somebody', :userid => '2', :uniqueid => 'STEAM_0:0:123457', :score => '3', :time => '2:42', :ping => '34', :loss => '0', :adr => '0' }
188
+
189
+ attributes = mock
190
+ GameServer.expects(:player_status_attributes).
191
+ with('name userid uniqueid frag time ping loss adr').
192
+ returns attributes
193
+ GameServer.expects(:split_player_status).
194
+ with(attributes, '1 "someone" 1 STEAM_0:0:123456 10 3:52 12 0 0').
195
+ returns somebody_data
196
+ GameServer.expects(:split_player_status).
197
+ with(attributes, '2 "somebody" 2 STEAM_0:0:123457 3 2:42 34 0 0').
198
+ returns someone_data
199
+
200
+ @somebody.expects(:add_info).with somebody_data
201
+ @someone.expects(:add_info).with someone_data
202
+ end
203
+
204
+ should 'with the RCON password' do
205
+ @server.expects(:rcon_auth).with 'password'
206
+
207
+ @server.update_players 'password'
208
+ end
209
+
210
+ should 'if the RCON connection is authenticated' do
211
+ @server.instance_variable_set :@rcon_authenticated, true
212
+
213
+ @server.update_players
214
+ end
215
+
216
+ end
217
+
218
+ should 'handle challenge requests' do
219
+ @server.expects(:send_request).with do |packet|
220
+ packet.is_a? A2S_SERVERQUERY_GETCHALLENGE_Packet
221
+ end
222
+
223
+ packet = mock
224
+ packet.expects(:kind_of?).with(S2A_INFO_BasePacket).returns false
225
+ packet.expects(:kind_of?).with(S2A_PLAYER_Packet).returns false
226
+ packet.expects(:kind_of?).with(S2A_RULES_Packet).returns false
227
+ packet.expects(:kind_of?).with(S2C_CHALLENGE_Packet).twice.returns true
228
+
229
+ packet.expects(:challenge_number).returns 1234
230
+ @server.expects(:reply).returns packet
231
+
232
+ @server.handle_response_for_request :challenge
233
+
234
+ assert_equal 1234, @server.instance_variable_get(:@challenge_number)
235
+ end
236
+
237
+ should 'handle info requests' do
238
+ @server.expects(:send_request).with do |packet|
239
+ packet.is_a? A2S_INFO_Packet
240
+ end
241
+
242
+ packet = mock
243
+ packet.expects(:kind_of?).with(S2A_INFO_BasePacket).twice.returns true
244
+ packet.expects(:info_hash).returns({ :test => 'test' })
245
+ @server.expects(:reply).returns packet
246
+
247
+ @server.handle_response_for_request :info
248
+
249
+ assert_equal({ :test => 'test' }, @server.instance_variable_get(:@info_hash))
250
+ end
251
+
252
+ should 'server rule requests' do
253
+ @server.expects(:send_request).with do |packet|
254
+ packet.is_a? A2S_RULES_Packet
255
+ end
256
+
257
+ packet = mock
258
+ packet.expects(:kind_of?).with(S2A_INFO_BasePacket).returns false
259
+ packet.expects(:kind_of?).with(S2A_PLAYER_Packet).returns false
260
+ packet.expects(:kind_of?).with(S2A_RULES_Packet).twice.returns true
261
+ packet.expects(:rules_hash).returns({ :test => 'test' })
262
+ @server.expects(:reply).returns packet
263
+
264
+ @server.handle_response_for_request :rules
265
+
266
+ assert_equal({ :test => 'test' }, @server.instance_variable_get(:@rules_hash))
267
+ end
268
+
269
+ should 'player requests' do
270
+ @server.expects(:send_request).with do |packet|
271
+ packet.is_a? A2S_PLAYER_Packet
272
+ end
273
+
274
+ packet = mock
275
+ packet.expects(:kind_of?).with(S2A_INFO_BasePacket).returns false
276
+ packet.expects(:kind_of?).with(S2A_PLAYER_Packet).twice.returns true
277
+ packet.expects(:player_hash).returns({ :test => 'test' })
278
+ @server.expects(:reply).returns packet
279
+
280
+ @server.handle_response_for_request :players
281
+
282
+ assert_equal({ :test => 'test' }, @server.instance_variable_get(:@player_hash))
283
+ end
284
+
285
+ should 'handle unexpected answers and retry' do
286
+ @server.expects(:send_request).twice.with do |packet|
287
+ packet.is_a? A2S_PLAYER_Packet
288
+ end
289
+
290
+ packet1 = mock
291
+ packet1.expects(:kind_of?).with(S2A_INFO_BasePacket).returns true
292
+ packet1.expects(:kind_of?).with(S2A_PLAYER_Packet).returns false
293
+ packet1.expects(:info_hash).returns({ :test => 'test1' })
294
+ packet2 = mock
295
+ packet2.expects(:kind_of?).with(S2A_INFO_BasePacket).returns false
296
+ packet2.expects(:kind_of?).with(S2A_PLAYER_Packet).twice.returns true
297
+ packet2.expects(:player_hash).returns({ :test => 'test2' })
298
+ @server.expects(:reply).twice.returns(packet1).returns packet2
299
+
300
+ @server.handle_response_for_request :players
301
+
302
+ assert_equal({ :test => 'test1' }, @server.instance_variable_get(:@info_hash))
303
+ assert_equal({ :test => 'test2' }, @server.instance_variable_get(:@player_hash))
304
+ end
305
+
306
+ end
307
+
308
+ end
@@ -0,0 +1,59 @@
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2011, Sebastian Staudt
5
+
6
+ require 'helper'
7
+ require 'steam/servers/goldsrc_server'
8
+
9
+ class TestGoldSrcServer < Test::Unit::TestCase
10
+
11
+ context 'The user' do
12
+
13
+ should 'be able to get a master server for GoldSrc servers' do
14
+ master = mock
15
+ MasterServer.expects(:new).with(*MasterServer::GOLDSRC_MASTER_SERVER).
16
+ returns master
17
+
18
+ assert_equal master, GoldSrcServer.master
19
+ end
20
+
21
+ end
22
+
23
+ context 'A GoldSrc server' do
24
+
25
+ setup do
26
+ Socket.stubs(:getaddrinfo).
27
+ with('goldsrc', 27015, Socket::AF_INET, Socket::SOCK_DGRAM).
28
+ returns [[nil, nil, 'goldsrc', '127.0.0.1']]
29
+
30
+ @server = GoldSrcServer.new 'goldsrc', 27015
31
+ end
32
+
33
+ should 'create a client socket upon initialization' do
34
+ socket = mock
35
+ GoldSrcSocket.expects(:new).with('127.0.0.1', 27015, false).returns socket
36
+
37
+ @server.init_socket
38
+
39
+ assert_same socket, @server.instance_variable_get(:@socket)
40
+ end
41
+
42
+ should 'save the RCON password for further use' do
43
+ assert @server.rcon_auth 'password'
44
+ assert_equal 'password', @server.instance_variable_get(:@rcon_password)
45
+ end
46
+
47
+ should 'send RCON commands with the password' do
48
+ socket = mock
49
+ socket.expects(:rcon_exec).with('password', 'command').returns 'test '
50
+
51
+ @server.instance_variable_set :@rcon_password, 'password'
52
+ @server.instance_variable_set :@socket, socket
53
+
54
+ assert_equal 'test', @server.rcon_exec('command')
55
+ end
56
+
57
+ end
58
+
59
+ end