bigbluebutton-api-ruby 0.0.10 → 0.0.11
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.
- data/.gitignore +1 -1
- data/.rspec +1 -0
- data/.rvmrc +6 -0
- data/CHANGELOG.rdoc +8 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +20 -0
- data/bigbluebutton-api-ruby.gemspec +1 -1
- data/lib/{bigbluebutton-api.rb → bigbluebutton_api.rb} +82 -145
- data/lib/bigbluebutton_exception.rb +13 -0
- data/lib/bigbluebutton_formatter.rb +76 -0
- data/spec/bigbluebutton_api_spec.rb +386 -0
- data/spec/bigbluebutton_exception_spec.rb +25 -0
- data/spec/bigbluebutton_formatter_spec.rb +143 -0
- data/spec/spec_helper.rb +13 -0
- data/test/test.rb +13 -1
- metadata +16 -6
data/.gitignore
CHANGED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 0.0.11
|
2
|
+
|
3
|
+
* The file "bigbluebutton-api" was renamed to "bigbluebutton_api". All "require" calls must be updated.
|
4
|
+
* Splitted the library in more files (more modular) and created rspec tests for it.
|
5
|
+
* Added a BigBlueButtonApi.timeout attribute to timeout get requests and avoid blocks when the server is down. Defaults to 2 secs.
|
6
|
+
* New method last_http_response to access the last HTTP response object.
|
7
|
+
* Automatically detects the BBB server version if not informed by the user.
|
8
|
+
|
1
9
|
== 0.0.10
|
2
10
|
|
3
11
|
* Returning hash now will *always* have these 3 values: :returncode (boolean), :messageKey (string) and :message (string).
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.3)
|
5
|
+
nokogiri (1.4.1)
|
6
|
+
rspec (2.6.0)
|
7
|
+
rspec-core (~> 2.6.0)
|
8
|
+
rspec-expectations (~> 2.6.0)
|
9
|
+
rspec-mocks (~> 2.6.0)
|
10
|
+
rspec-core (2.6.4)
|
11
|
+
rspec-expectations (2.6.0)
|
12
|
+
diff-lcs (~> 1.1.2)
|
13
|
+
rspec-mocks (2.6.0)
|
14
|
+
|
15
|
+
PLATFORMS
|
16
|
+
ruby
|
17
|
+
|
18
|
+
DEPENDENCIES
|
19
|
+
nokogiri (= 1.4.1)
|
20
|
+
rspec (~> 2.6)
|
@@ -2,7 +2,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'bigbluebutton-api-ruby'
|
5
|
-
s.version = '0.0.
|
5
|
+
s.version = '0.0.11'
|
6
6
|
s.extra_rdoc_files = ['README.rdoc', 'LICENSE', 'CHANGELOG.rdoc']
|
7
7
|
s.summary = 'Provides an interface to the BigBlueButton web meeting API (https://github.com/mconf/bigbluebutton-api-ruby)'
|
8
8
|
s.description = s.summary
|
@@ -5,26 +5,15 @@ require 'digest/sha1'
|
|
5
5
|
require 'rubygems'
|
6
6
|
require 'nokogiri'
|
7
7
|
require 'hash_to_xml'
|
8
|
+
require 'bigbluebutton_exception'
|
9
|
+
require 'bigbluebutton_formatter'
|
8
10
|
|
9
11
|
module BigBlueButton
|
10
12
|
|
11
|
-
class BigBlueButtonException < Exception
|
12
|
-
attr_accessor :key
|
13
|
-
|
14
|
-
def to_s
|
15
|
-
unless key.blank?
|
16
|
-
super.to_s + ", messageKey: #{key}"
|
17
|
-
else
|
18
|
-
super
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
13
|
# This class provides access to the BigBlueButton API. BigBlueButton
|
25
14
|
# is an open source project that provides web conferencing for distance
|
26
15
|
# education (http://code.google.com/p/bigbluebutton/wiki/API). This API
|
27
|
-
# was developed to support the following version of BBB: 0.
|
16
|
+
# was developed to support the following version of BBB: 0.7, 0.8 (soon)
|
28
17
|
#
|
29
18
|
# Sample usage of the API is as follows:
|
30
19
|
# 1) Create a meeting with the create_meeting call
|
@@ -42,8 +31,6 @@ module BigBlueButton
|
|
42
31
|
# Copyright:: Copyright (c) 2010 Joe Kinsella
|
43
32
|
# License:: Distributes under same terms as Ruby
|
44
33
|
#
|
45
|
-
# TODO: Automatically detect API version using request to index - added in 0.7
|
46
|
-
#
|
47
34
|
# Considerations about the returning hash:
|
48
35
|
# * The XML returned by BBB is converted to a Hash. See the desired method's documentation for examples.
|
49
36
|
# * Three values will *always* exist in the hash: :returncode (boolean), :messageKey (string) and :message (string)
|
@@ -58,54 +45,38 @@ module BigBlueButton
|
|
58
45
|
#
|
59
46
|
class BigBlueButtonApi
|
60
47
|
|
61
|
-
attr_accessor :url, :supported_versions, :salt, :version, :debug
|
48
|
+
attr_accessor :url, :supported_versions, :salt, :version, :debug, :timeout
|
62
49
|
|
63
50
|
# Initializes an instance
|
64
51
|
# url:: URL to a BigBlueButton server (e.g. http://demo.bigbluebutton.org/bigbluebutton/api)
|
65
52
|
# salt:: Secret salt for this server
|
66
|
-
# version:: API version: 0.
|
53
|
+
# version:: API version: 0.7 (valid for 0.7, 0.71 and 0.71a)
|
67
54
|
def initialize(url, salt, version='0.7', debug=false)
|
68
|
-
@supported_versions = ['0.7'
|
69
|
-
unless @supported_versions.include?(version)
|
70
|
-
raise BigBlueButtonException.new("BigBlueButton error: Invalid API version #{version}. Supported versions: #{@supported_versions.join(', ')}")
|
71
|
-
end
|
55
|
+
@supported_versions = ['0.7']
|
72
56
|
@url = url
|
73
57
|
@salt = salt
|
74
58
|
@debug = debug
|
75
|
-
@
|
76
|
-
puts "BigBlueButtonAPI: Using version #{@version}" if @debug
|
77
|
-
end
|
59
|
+
@timeout = 2 # 2 seconds timeout for get requests
|
78
60
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
warn "#{caller[0]}: moderator_url is deprecated and will soon be removed, please use join_meeting_url instead."
|
84
|
-
join_meeting_url(meeting_id, user_name, password, user_id, web_voice_conf)
|
85
|
-
end
|
61
|
+
@version = version || get_api_version
|
62
|
+
unless @supported_versions.include?(@version)
|
63
|
+
raise BigBlueButtonException.new("BigBlueButton error: Invalid API version #{version}. Supported versions: #{@supported_versions.join(', ')}")
|
64
|
+
end
|
86
65
|
|
87
|
-
|
88
|
-
# Use join_meeting_url
|
89
|
-
def attendee_url(meeting_id, user_name, password,
|
90
|
-
user_id = nil, web_voice_conf = nil)
|
91
|
-
warn "#{caller[0]}: attendee_url is deprecated and will soon be removed, please use join_meeting_url instead."
|
92
|
-
join_meeting_url(meeting_id, user_name, password, user_id, web_voice_conf)
|
66
|
+
puts "BigBlueButtonAPI: Using version #{@version}" if @debug
|
93
67
|
end
|
94
68
|
|
95
69
|
# Returns the url used to join the meeting
|
96
70
|
# meeting_id:: Unique identifier for the meeting
|
97
71
|
# user_name:: Name of the user
|
98
72
|
# password:: Password for this meeting - used to set the user as moderator or attendee
|
99
|
-
# user_id:: Unique identifier for this user
|
100
|
-
# web_voice_conf:: Custom voice-extension for users using VoIP
|
73
|
+
# user_id:: Unique identifier for this user
|
74
|
+
# web_voice_conf:: Custom voice-extension for users using VoIP
|
101
75
|
def join_meeting_url(meeting_id, user_name, password,
|
102
76
|
user_id = nil, web_voice_conf = nil)
|
103
77
|
|
104
|
-
params = { :meetingID => meeting_id, :password => password, :fullName => user_name
|
105
|
-
|
106
|
-
params[:userID] = user_id
|
107
|
-
params[:webVoiceConf] = web_voice_conf
|
108
|
-
end
|
78
|
+
params = { :meetingID => meeting_id, :password => password, :fullName => user_name,
|
79
|
+
:userID => user_id, :webVoiceConf => web_voice_conf }
|
109
80
|
get_url(:join, params)
|
110
81
|
end
|
111
82
|
|
@@ -118,7 +89,7 @@ module BigBlueButton
|
|
118
89
|
# welcome_message:: Welcome message to display in chat window
|
119
90
|
# dialin_number:: Dial in number for conference using a regular phone
|
120
91
|
# logout_url:: URL to return user to after exiting meeting
|
121
|
-
# voice_bridge:: Voice conference number
|
92
|
+
# voice_bridge:: Voice conference number
|
122
93
|
#
|
123
94
|
# === Return examples (for 0.7)
|
124
95
|
#
|
@@ -139,7 +110,6 @@ module BigBlueButton
|
|
139
110
|
# :message=>"This conference was already in existence and may currently be in progress."
|
140
111
|
# }
|
141
112
|
#
|
142
|
-
# TODO check if voice_bridge exists in 0.64
|
143
113
|
def create_meeting(meeting_name, meeting_id, moderator_password = nil, attendee_password = nil,
|
144
114
|
welcome_message = nil, dial_number = nil, logout_url = nil,
|
145
115
|
max_participants = nil, voice_bridge = nil)
|
@@ -147,15 +117,16 @@ module BigBlueButton
|
|
147
117
|
params = { :name => meeting_name, :meetingID => meeting_id,
|
148
118
|
:moderatorPW => moderator_password, :attendeePW => attendee_password,
|
149
119
|
:welcome => welcome_message, :dialNumber => dial_number,
|
150
|
-
:logoutURL => logout_url, :maxParticpants => max_participants
|
151
|
-
|
120
|
+
:logoutURL => logout_url, :maxParticpants => max_participants,
|
121
|
+
:voiceBridge => voice_bridge }
|
152
122
|
|
153
123
|
response = send_api_request(:create, params)
|
154
124
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
125
|
+
formatter = BigBlueButtonFormatter.new(response)
|
126
|
+
formatter.to_string(:meetingID)
|
127
|
+
formatter.to_string(:moderatorPW)
|
128
|
+
formatter.to_string(:attendeePW)
|
129
|
+
formatter.to_boolean(:hasBeenForciblyEnded)
|
159
130
|
|
160
131
|
response
|
161
132
|
end
|
@@ -183,7 +154,7 @@ module BigBlueButton
|
|
183
154
|
# meeting_id:: Unique identifier for the meeting
|
184
155
|
def is_meeting_running?(meeting_id)
|
185
156
|
hash = send_api_request(:isMeetingRunning, { :meetingID => meeting_id } )
|
186
|
-
hash
|
157
|
+
BigBlueButtonFormatter.new(hash).to_boolean(:running)
|
187
158
|
end
|
188
159
|
|
189
160
|
# Warning: As of this version of the gem, this call does not work
|
@@ -196,16 +167,11 @@ module BigBlueButton
|
|
196
167
|
# meeting_id:: Unique identifier for the meeting
|
197
168
|
# user_name:: Name of the user
|
198
169
|
# password:: Moderator or attendee password for this meeting
|
199
|
-
# user_id:: Unique identifier for this user
|
200
|
-
# web_voice_conf:: Custom voice-extension for users using VoIP
|
170
|
+
# user_id:: Unique identifier for this user
|
171
|
+
# web_voice_conf:: Custom voice-extension for users using VoIP
|
201
172
|
def join_meeting(meeting_id, user_name, password, user_id = nil, web_voice_conf = nil)
|
202
|
-
params = { :meetingID => meeting_id, :password => password, :fullName => user_name
|
203
|
-
|
204
|
-
params[:redirectImmediately] = 0
|
205
|
-
elsif @version == '0.7'
|
206
|
-
params[:userID] = user_id
|
207
|
-
params[:webVoiceConf] = web_voice_conf
|
208
|
-
end
|
173
|
+
params = { :meetingID => meeting_id, :password => password, :fullName => user_name,
|
174
|
+
:userID => user_id, :webVoiceConf => web_voice_conf }
|
209
175
|
send_api_request(:join, params)
|
210
176
|
end
|
211
177
|
|
@@ -242,30 +208,17 @@ module BigBlueButton
|
|
242
208
|
def get_meeting_info(meeting_id, password)
|
243
209
|
response = send_api_request(:getMeetingInfo, { :meetingID => meeting_id, :password => password } )
|
244
210
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
end
|
257
|
-
response[:attendees] = attendees
|
258
|
-
response[:attendees].each { |att| att[:role] = att[:role].downcase.to_sym }
|
259
|
-
|
260
|
-
response[:meetingID] = response[:meetingID].to_s
|
261
|
-
response[:moderatorPW] = response[:moderatorPW].to_s
|
262
|
-
response[:attendeePW] = response[:attendeePW].to_s
|
263
|
-
response[:hasBeenForciblyEnded] = response[:hasBeenForciblyEnded].downcase == "true"
|
264
|
-
response[:running] = response[:running].downcase == "true"
|
265
|
-
response[:startTime] = response[:startTime].downcase == "null" ?
|
266
|
-
nil : DateTime.parse(response[:startTime])
|
267
|
-
response[:endTime] = response[:endTime].downcase == "null" ?
|
268
|
-
nil : DateTime.parse(response[:endTime])
|
211
|
+
formatter = BigBlueButtonFormatter.new(response)
|
212
|
+
formatter.flatten_objects(:attendees, :attendee)
|
213
|
+
response[:attendees].each { |a| formatter.format_attendee(a) }
|
214
|
+
|
215
|
+
formatter.to_string(:meetingID)
|
216
|
+
formatter.to_string(:moderatorPW)
|
217
|
+
formatter.to_string(:attendeePW)
|
218
|
+
formatter.to_boolean(:hasBeenForciblyEnded)
|
219
|
+
formatter.to_boolean(:running)
|
220
|
+
formatter.to_datetime(:startTime)
|
221
|
+
formatter.to_datetime(:endTime)
|
269
222
|
|
270
223
|
response
|
271
224
|
end
|
@@ -292,52 +245,23 @@ module BigBlueButton
|
|
292
245
|
def get_meetings
|
293
246
|
response = send_api_request(:getMeetings, { :random => rand(9999999999) } )
|
294
247
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
else
|
299
|
-
node = response[:meetings][:meeting]
|
300
|
-
if node.kind_of?(Array)
|
301
|
-
meetings = node
|
302
|
-
else
|
303
|
-
meetings = []
|
304
|
-
meetings << node
|
305
|
-
end
|
306
|
-
end
|
307
|
-
response[:meetings] = meetings
|
308
|
-
|
309
|
-
response[:meetings].each do |meeting|
|
310
|
-
meeting[:meetingID] = meeting[:meetingID].to_s
|
311
|
-
meeting[:moderatorPW] = meeting[:moderatorPW].to_s
|
312
|
-
meeting[:attendeePW] = meeting[:attendeePW].to_s
|
313
|
-
meeting[:hasBeenForciblyEnded] = meeting[:hasBeenForciblyEnded].downcase == "true"
|
314
|
-
meeting[:running] = meeting[:running].downcase == "true"
|
315
|
-
end
|
316
|
-
|
248
|
+
formatter = BigBlueButtonFormatter.new(response)
|
249
|
+
formatter.flatten_objects(:meetings, :meeting)
|
250
|
+
response[:meetings].each { |m| formatter.format_meeting(m) }
|
317
251
|
response
|
318
252
|
end
|
319
253
|
|
320
254
|
# Returns the API version (as string) of the associated server. This actually returns
|
321
|
-
# the version
|
322
|
-
# the initialization.
|
323
|
-
#
|
324
|
-
# Works for BBB >= 0.7 only. For earlier versions, returns an empty string.
|
255
|
+
# the version returned by the BBB server, and not the version set by the user in
|
256
|
+
# the initialization of this object.
|
325
257
|
def get_api_version
|
326
258
|
response = send_api_request(:index)
|
327
|
-
|
328
|
-
response[:version].to_s
|
329
|
-
else
|
330
|
-
""
|
331
|
-
end
|
259
|
+
response[:returncode] ? response[:version].to_s : ""
|
332
260
|
end
|
333
261
|
|
334
262
|
# Make a simple request to the server to test the connection
|
335
263
|
def test_connection
|
336
|
-
|
337
|
-
response = send_api_request(:index)
|
338
|
-
else
|
339
|
-
response = get_meetings
|
340
|
-
end
|
264
|
+
response = send_api_request(:index)
|
341
265
|
response[:returncode]
|
342
266
|
end
|
343
267
|
|
@@ -350,56 +274,50 @@ module BigBlueButton
|
|
350
274
|
r
|
351
275
|
end
|
352
276
|
|
353
|
-
|
277
|
+
def last_http_response
|
278
|
+
@http_response
|
279
|
+
end
|
354
280
|
|
355
|
-
def get_url(method, data)
|
281
|
+
def get_url(method, data={})
|
356
282
|
if method == :index
|
357
283
|
return @url
|
358
284
|
end
|
359
285
|
|
360
286
|
url = "#{@url}/#{method}?"
|
361
287
|
|
288
|
+
# stringify and escape all params
|
362
289
|
data.delete_if { |k, v| v.nil? } unless data.nil?
|
363
290
|
params = ""
|
364
291
|
params = data.map{ |k,v| "#{k}=" + CGI::escape(v.to_s) unless k.nil? || v.nil? }.join("&")
|
365
292
|
|
293
|
+
# checksum calc
|
366
294
|
checksum_param = params + @salt
|
367
|
-
checksum_param = method.to_s + checksum_param
|
295
|
+
checksum_param = method.to_s + checksum_param
|
368
296
|
checksum = Digest::SHA1.hexdigest(checksum_param)
|
369
297
|
|
370
|
-
|
298
|
+
# final url
|
299
|
+
url += "#{params}&" unless params.empty?
|
300
|
+
url += "checksum=#{checksum}"
|
371
301
|
end
|
372
302
|
|
373
303
|
def send_api_request(method, data = {})
|
374
304
|
url = get_url(method, data)
|
375
|
-
begin
|
376
|
-
res = Net::HTTP.get_response(URI.parse(url))
|
377
|
-
puts "BigBlueButtonAPI: URL request = #{url}" if @debug
|
378
|
-
puts "BigBlueButtonAPI: URL response = #{res.body}" if @debug
|
379
|
-
rescue Exception => socketerror
|
380
|
-
raise BigBlueButtonException.new("Connection error. Your URL is probably incorrect: \"#{@url}\"")
|
381
|
-
end
|
382
305
|
|
383
|
-
|
384
|
-
|
385
|
-
end
|
306
|
+
@http_response = send_request(url)
|
307
|
+
return { } if @http_response.body.empty?
|
386
308
|
|
387
309
|
# 'Hashify' the XML
|
388
|
-
hash = Hash.from_xml
|
310
|
+
hash = Hash.from_xml(@http_response.body)
|
389
311
|
|
390
312
|
# simple validation of the xml body
|
391
313
|
unless hash.has_key?(:response) and hash[:response].has_key?(:returncode)
|
392
314
|
raise BigBlueButtonException.new("Invalid response body. Is the API URL correct? \"#{@url}\", version #{@version}")
|
393
315
|
end
|
394
316
|
|
395
|
-
#
|
396
|
-
hash =
|
397
|
-
|
398
|
-
# Adjust some values. There will always be a returncode, message and messageKey in the hash.
|
399
|
-
hash[:returncode] = hash[:returncode].downcase == "success" # true instead of "SUCCESS"
|
400
|
-
hash[:messageKey] = "" if !hash.has_key?(:messageKey) or hash[:messageKey].empty? # "" instead of {}
|
401
|
-
hash[:message] = "" if !hash.has_key?(:message) or hash[:message].empty? # "" instead of {}
|
317
|
+
# default cleanup in the response
|
318
|
+
hash = BigBlueButtonFormatter.new(hash).default_formatting
|
402
319
|
|
320
|
+
# all responses should have a returncode
|
403
321
|
unless hash[:returncode]
|
404
322
|
exception = BigBlueButtonException.new(hash[:message])
|
405
323
|
exception.key = hash.has_key?(:messageKey) ? hash[:messageKey] : ""
|
@@ -409,6 +327,25 @@ module BigBlueButton
|
|
409
327
|
hash
|
410
328
|
end
|
411
329
|
|
330
|
+
protected
|
331
|
+
|
332
|
+
def send_request(url)
|
333
|
+
begin
|
334
|
+
puts "BigBlueButtonAPI: URL request = #{url}" if @debug
|
335
|
+
url_parsed = URI.parse(url)
|
336
|
+
http = Net::HTTP.new(url_parsed.host, url_parsed.port)
|
337
|
+
http.open_timeout = @timeout
|
338
|
+
http.read_timeout = @timeout
|
339
|
+
response = http.get(url_parsed.request_uri)
|
340
|
+
puts "BigBlueButtonAPI: URL response = #{response.body}" if @debug
|
341
|
+
rescue TimeoutError => error
|
342
|
+
raise BigBlueButtonException.new("Timeout error. Your server is probably down: \"#{@url}\"")
|
343
|
+
rescue Exception => error
|
344
|
+
raise BigBlueButtonException.new("Connection error. Your URL is probably incorrect: \"#{@url}\"")
|
345
|
+
end
|
346
|
+
response
|
347
|
+
end
|
348
|
+
|
412
349
|
end
|
413
350
|
end
|
414
351
|
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module BigBlueButton
|
2
|
+
|
3
|
+
# Helper class to format the response hash received when the BigBlueButtonApi makes API calls
|
4
|
+
class BigBlueButtonFormatter
|
5
|
+
attr_accessor :hash
|
6
|
+
|
7
|
+
def initialize(hash)
|
8
|
+
@hash = hash
|
9
|
+
end
|
10
|
+
|
11
|
+
# converts a value in the @hash to boolean
|
12
|
+
def to_boolean(key)
|
13
|
+
@hash[key] = @hash[key].downcase == "true"
|
14
|
+
end
|
15
|
+
|
16
|
+
# converts a value in the @hash to string
|
17
|
+
def to_string(key)
|
18
|
+
@hash[key] = @hash[key].to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
# converts a value in the @hash to DateTime
|
22
|
+
def to_datetime(key)
|
23
|
+
@hash[key] = @hash[key].downcase == "null" ? nil : DateTime.parse(@hash[key])
|
24
|
+
end
|
25
|
+
|
26
|
+
# Default formatting for all responses given by a BBB server
|
27
|
+
def default_formatting
|
28
|
+
|
29
|
+
# remove the "response" node
|
30
|
+
response = Hash[@hash[:response]].inject({}){|h,(k,v)| h[k] = v; h}
|
31
|
+
|
32
|
+
# Adjust some values. There will always be a returncode, a message and a messageKey in the hash.
|
33
|
+
response[:returncode] = response[:returncode].downcase == "success" # true instead of "SUCCESS"
|
34
|
+
response[:messageKey] = "" if !response.has_key?(:messageKey) or response[:messageKey].empty? # "" instead of {}
|
35
|
+
response[:message] = "" if !response.has_key?(:message) or response[:message].empty? # "" instead of {}
|
36
|
+
|
37
|
+
@hash = response
|
38
|
+
end
|
39
|
+
|
40
|
+
# default formatting for a meeting hash
|
41
|
+
def format_meeting(meeting)
|
42
|
+
meeting[:meetingID] = meeting[:meetingID].to_s
|
43
|
+
meeting[:moderatorPW] = meeting[:moderatorPW].to_s
|
44
|
+
meeting[:attendeePW] = meeting[:attendeePW].to_s
|
45
|
+
meeting[:hasBeenForciblyEnded] = meeting[:hasBeenForciblyEnded].downcase == "true"
|
46
|
+
meeting[:running] = meeting[:running].downcase == "true"
|
47
|
+
meeting
|
48
|
+
end
|
49
|
+
|
50
|
+
# default formatting for an attendee hash
|
51
|
+
def format_attendee(attendee)
|
52
|
+
attendee[:userID] = attendee[:userID].to_s
|
53
|
+
attendee[:role] = attendee[:role].downcase.to_sym
|
54
|
+
attendee
|
55
|
+
end
|
56
|
+
|
57
|
+
# simplifies the hash making a node e.g. :attendee with an array with all attendees
|
58
|
+
# TODO: comments with the expected @hash at this point
|
59
|
+
def flatten_objects(first, second)
|
60
|
+
if @hash[first].empty?
|
61
|
+
collection = []
|
62
|
+
else
|
63
|
+
node = @hash[first][second]
|
64
|
+
if node.kind_of?(Array)
|
65
|
+
collection = node
|
66
|
+
else
|
67
|
+
collection = []
|
68
|
+
collection << node
|
69
|
+
end
|
70
|
+
end
|
71
|
+
@hash[first] = collection
|
72
|
+
@hash
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,386 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BigBlueButton::BigBlueButtonApi do
|
4
|
+
|
5
|
+
# default variables and API object for all tests
|
6
|
+
let(:url) { "http://server.com" }
|
7
|
+
let(:salt) { "1234567890abcdefghijkl" }
|
8
|
+
let(:version) { "0.7" }
|
9
|
+
let(:debug) { false }
|
10
|
+
let(:api) { BigBlueButton::BigBlueButtonApi.new(url, salt, version, debug) }
|
11
|
+
|
12
|
+
describe "#initialize" do
|
13
|
+
context "standard initialization" do
|
14
|
+
subject { BigBlueButton::BigBlueButtonApi.new(url, salt, version, debug) }
|
15
|
+
it { subject.url.should be(url) }
|
16
|
+
it { subject.salt.should be(salt) }
|
17
|
+
it { subject.version.should be(version) }
|
18
|
+
it { subject.debug.should be(debug) }
|
19
|
+
it { subject.timeout.should be(2) }
|
20
|
+
it { subject.supported_versions.should include("0.7") }
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when the version is not informed, get it from the BBB server" do
|
24
|
+
before { BigBlueButton::BigBlueButtonApi.any_instance.should_receive(:get_api_version).and_return("0.7") }
|
25
|
+
subject { BigBlueButton::BigBlueButtonApi.new(url, salt, nil) }
|
26
|
+
it { subject.version.should == "0.7" }
|
27
|
+
end
|
28
|
+
|
29
|
+
it "when the version is not supported raise an error" do
|
30
|
+
expect {
|
31
|
+
BigBlueButton::BigBlueButtonApi.new(url, salt, "0.not-supported", nil)
|
32
|
+
}.to raise_error(BigBlueButton::BigBlueButtonException)
|
33
|
+
end
|
34
|
+
|
35
|
+
context "current supported versions" do
|
36
|
+
subject { BigBlueButton::BigBlueButtonApi.new(url, salt) }
|
37
|
+
it { subject.supported_versions.should == ["0.7"] }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#join_meeting_url" do
|
42
|
+
let(:meeting_id) { "meeting-id" }
|
43
|
+
let(:password) { "password" }
|
44
|
+
let(:user_name) { "user-name" }
|
45
|
+
let(:user_id) { "user-id" }
|
46
|
+
let(:web_voice_conf) { "web-voice-conf" }
|
47
|
+
let(:params) {
|
48
|
+
{ :meetingID => meeting_id, :password => password, :fullName => user_name,
|
49
|
+
:userID => user_id, :webVoiceConf => web_voice_conf }
|
50
|
+
}
|
51
|
+
|
52
|
+
before { api.should_receive(:get_url).with(:join, params).and_return("test-url") }
|
53
|
+
it { api.join_meeting_url(meeting_id, user_name, password, user_id, web_voice_conf).should == "test-url" }
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#create_meeting" do
|
57
|
+
let(:meeting_name) { "name" }
|
58
|
+
let(:meeting_id) { "meeting-id" }
|
59
|
+
let(:moderator_password) { "moderator-password" }
|
60
|
+
let(:attendee_password) { "attendee-password" }
|
61
|
+
let(:welcome_message) { "welcome" }
|
62
|
+
let(:dial_number) { "dial-number" }
|
63
|
+
let(:logout_url) { "logout-url" }
|
64
|
+
let(:max_participants) { "max-participants" }
|
65
|
+
let(:voice_bridge) { "voice-bridge" }
|
66
|
+
let(:params) {
|
67
|
+
{ :name => meeting_name, :meetingID => meeting_id,
|
68
|
+
:moderatorPW => moderator_password, :attendeePW => attendee_password,
|
69
|
+
:welcome => welcome_message, :dialNumber => dial_number,
|
70
|
+
:logoutURL => logout_url, :maxParticpants => max_participants,
|
71
|
+
:voiceBridge => voice_bridge }
|
72
|
+
}
|
73
|
+
let(:response) { { :meetingID => 123, :moderatorPW => 111, :attendeePW => 222, :hasBeenForciblyEnded => "FALSE" } }
|
74
|
+
let(:expected_response) { { :meetingID => "123", :moderatorPW => "111", :attendeePW => "222", :hasBeenForciblyEnded => false } }
|
75
|
+
|
76
|
+
# ps: not mocking the formatter here because it's easier to just check the results (expected_response)
|
77
|
+
before { api.should_receive(:send_api_request).with(:create, params).and_return(response) }
|
78
|
+
subject { api.create_meeting(meeting_name, meeting_id, moderator_password,
|
79
|
+
attendee_password, welcome_message, dial_number,
|
80
|
+
logout_url, max_participants, voice_bridge) }
|
81
|
+
it { subject.should == expected_response }
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#end_meeting" do
|
85
|
+
let(:meeting_id) { "meeting-id" }
|
86
|
+
let(:moderator_password) { "password" }
|
87
|
+
let(:params) { { :meetingID => meeting_id, :password => moderator_password } }
|
88
|
+
let(:response) { "anything" }
|
89
|
+
|
90
|
+
before { api.should_receive(:send_api_request).with(:end, params).and_return(response) }
|
91
|
+
it { api.end_meeting(meeting_id, moderator_password).should == response }
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#is_meeting_running?" do
|
95
|
+
let(:meeting_id) { "meeting-id" }
|
96
|
+
let(:params) { { :meetingID => meeting_id } }
|
97
|
+
|
98
|
+
context "when the meeting is running" do
|
99
|
+
let(:response) { { :running => "TRUE" } }
|
100
|
+
before { api.should_receive(:send_api_request).with(:isMeetingRunning, params).and_return(response) }
|
101
|
+
it { api.is_meeting_running?(meeting_id).should == true }
|
102
|
+
end
|
103
|
+
|
104
|
+
context "when the meeting is not running" do
|
105
|
+
let(:response) { { :running => "FALSE" } }
|
106
|
+
before { api.should_receive(:send_api_request).with(:isMeetingRunning, params).and_return(response) }
|
107
|
+
it { api.is_meeting_running?(meeting_id).should == false }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "#join_meeting" do
|
112
|
+
let(:meeting_id) { "meeting-id" }
|
113
|
+
let(:password) { "password" }
|
114
|
+
let(:user_name) { "user-name" }
|
115
|
+
let(:user_id) { "user-id" }
|
116
|
+
let(:web_voice_conf) { "web-voice-conf" }
|
117
|
+
let(:params) {
|
118
|
+
{ :meetingID => meeting_id, :password => password, :fullName => user_name,
|
119
|
+
:userID => user_id, :webVoiceConf => web_voice_conf }
|
120
|
+
}
|
121
|
+
|
122
|
+
before { api.should_receive(:send_api_request).with(:join, params).and_return("join-return") }
|
123
|
+
it { api.join_meeting(meeting_id, user_name, password, user_id, web_voice_conf).should == "join-return" }
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "#get_meeting_info" do
|
127
|
+
let(:meeting_id) { "meeting-id" }
|
128
|
+
let(:password) { "password" }
|
129
|
+
let(:params) { { :meetingID => meeting_id, :password => password } }
|
130
|
+
|
131
|
+
let(:attendee1) { { :userID => 123, :fullName => "Dexter Morgan", :role => "MODERATOR" } }
|
132
|
+
let(:attendee2) { { :userID => "id2", :fullName => "Cameron", :role => "VIEWER" } }
|
133
|
+
let(:response) {
|
134
|
+
{ :meetingID => 123, :moderatorPW => 111, :attendeePW => 222, :hasBeenForciblyEnded => "FALSE",
|
135
|
+
:running => "TRUE", :startTime => "Thu Sep 01 17:51:42 UTC 2011", :endTime => "null",
|
136
|
+
:returncode => true, :attendees => { :attendee => [ attendee1, attendee2 ] }, :messageKey => "mkey", :message => "m" }
|
137
|
+
} # hash after the send_api_request call, before the specific formatting
|
138
|
+
|
139
|
+
let(:expected_attendee1) { { :userID => "123", :fullName => "Dexter Morgan", :role => :moderator } }
|
140
|
+
let(:expected_attendee2) { { :userID => "id2", :fullName => "Cameron", :role => :viewer } }
|
141
|
+
let(:expected_response) {
|
142
|
+
{ :meetingID => "123", :moderatorPW => "111", :attendeePW => "222", :hasBeenForciblyEnded => false,
|
143
|
+
:running => true, :startTime => DateTime.parse("Thu Sep 01 17:51:42 UTC 2011"), :endTime => nil,
|
144
|
+
:returncode => true, :attendees => [ expected_attendee1, expected_attendee2 ], :messageKey => "mkey", :message => "m" }
|
145
|
+
} # expected return hash after all the formatting
|
146
|
+
|
147
|
+
# ps: not mocking the formatter here because it's easier to just check the results (expected_response)
|
148
|
+
before { api.should_receive(:send_api_request).with(:getMeetingInfo, params).and_return(response) }
|
149
|
+
it { api.get_meeting_info(meeting_id, password).should == expected_response }
|
150
|
+
end
|
151
|
+
|
152
|
+
describe "#get_meetings" do
|
153
|
+
let(:meeting_hash1) { { :meetingID => "Demo Meeting", :attendeePW => "ap", :moderatorPW => "mp", :hasBeenForciblyEnded => false, :running => true } }
|
154
|
+
let(:meeting_hash2) { { :meetingID => "Ended Meeting", :attendeePW => "pass", :moderatorPW => "pass", :hasBeenForciblyEnded => true, :running => false } }
|
155
|
+
let(:flattened_response) {
|
156
|
+
{ :returncode => true, :meetings => [ meeting_hash1, meeting_hash2 ], :messageKey => "mkey", :message => "m" }
|
157
|
+
} # hash *after* the flatten_objects call
|
158
|
+
|
159
|
+
before {
|
160
|
+
# FIXME: how to expect a hash with a random value in the should_receive below?
|
161
|
+
api.should_receive(:send_api_request).with(:getMeetings, anything).and_return(flattened_response)
|
162
|
+
formatter_mock = mock(BigBlueButton::BigBlueButtonFormatter)
|
163
|
+
formatter_mock.should_receive(:flatten_objects).with(:meetings, :meeting)
|
164
|
+
formatter_mock.should_receive(:format_meeting).with(meeting_hash1)
|
165
|
+
formatter_mock.should_receive(:format_meeting).with(meeting_hash2)
|
166
|
+
BigBlueButton::BigBlueButtonFormatter.should_receive(:new).and_return(formatter_mock)
|
167
|
+
}
|
168
|
+
it { api.get_meetings }
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "#get_api_version" do
|
172
|
+
context "returns the version returned by the server" do
|
173
|
+
let(:hash) { { :returncode => true, :version => "0.7" } }
|
174
|
+
before { api.should_receive(:send_api_request).with(:index).and_return(hash) }
|
175
|
+
it { api.get_api_version.should == "0.7" }
|
176
|
+
end
|
177
|
+
|
178
|
+
context "returns an empty string when the server responds with an empty hash" do
|
179
|
+
before { api.should_receive(:send_api_request).with(:index).and_return({}) }
|
180
|
+
it { api.get_api_version.should == "" }
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "#test_connection" do
|
185
|
+
context "returns the returncode returned by the server" do
|
186
|
+
let(:hash) { { :returncode => "any-value" } }
|
187
|
+
before { api.should_receive(:send_api_request).with(:index).and_return(hash) }
|
188
|
+
it { api.test_connection.should == "any-value" }
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe "#==" do
|
193
|
+
let(:api2) { BigBlueButton::BigBlueButtonApi.new(url, salt, version, debug) }
|
194
|
+
|
195
|
+
context "compares attributes" do
|
196
|
+
it { api.should == api2 }
|
197
|
+
end
|
198
|
+
|
199
|
+
context "differs #debug" do
|
200
|
+
before { api2.debug = !api.debug }
|
201
|
+
it { api.should_not == api2 }
|
202
|
+
end
|
203
|
+
|
204
|
+
context "differs #salt" do
|
205
|
+
before { api2.salt = api.salt + "x" }
|
206
|
+
it { api.should_not == api2 }
|
207
|
+
end
|
208
|
+
|
209
|
+
context "differs #version" do
|
210
|
+
before { api2.version = api.version + "x" }
|
211
|
+
it { api.should_not == api2 }
|
212
|
+
end
|
213
|
+
|
214
|
+
context "differs #supported_versions" do
|
215
|
+
before { api2.supported_versions << "x" }
|
216
|
+
it { api.should_not == api2 }
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe "#last_http_response" do
|
221
|
+
# we test this through a #test_connection call
|
222
|
+
|
223
|
+
let(:request_mock) { mock }
|
224
|
+
before {
|
225
|
+
api.should_receive(:get_url)
|
226
|
+
# this return value will be stored in @http_response
|
227
|
+
api.should_receive(:send_request).and_return(request_mock)
|
228
|
+
# to return fast from #send_api_request
|
229
|
+
request_mock.should_receive(:body).and_return("")
|
230
|
+
api.test_connection
|
231
|
+
}
|
232
|
+
it { api.last_http_response.should == request_mock }
|
233
|
+
end
|
234
|
+
|
235
|
+
describe "#get_url" do
|
236
|
+
|
237
|
+
context "when method = :index" do
|
238
|
+
it { api.get_url(:index).should == api.url }
|
239
|
+
end
|
240
|
+
|
241
|
+
context "when method != :index" do
|
242
|
+
context "validates the entire url" do
|
243
|
+
context "with params" do
|
244
|
+
let(:params) { { :param1 => "value1", :param2 => "value2" } }
|
245
|
+
subject { api.get_url(:join, params) }
|
246
|
+
it { subject.should match(/#{url}\/join\?param1=value1¶m2=value2/) }
|
247
|
+
end
|
248
|
+
|
249
|
+
context "without params" do
|
250
|
+
subject { api.get_url(:join) }
|
251
|
+
it { subject.should match(/#{url}\/join\?[^&]/) }
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
context "discards params with nil value" do
|
256
|
+
let(:params) { { :param1 => "value1", :param2 => nil } }
|
257
|
+
subject { api.get_url(:join, params) }
|
258
|
+
it { subject.should_not match(/param2=/) }
|
259
|
+
end
|
260
|
+
|
261
|
+
context "escapes all params" do
|
262
|
+
let(:params) { { :param1 => "value with spaces", :param2 => "@$" } }
|
263
|
+
subject { api.get_url(:join, params) }
|
264
|
+
it { subject.should match(/param1=value\+with\+spaces/) }
|
265
|
+
it { subject.should match(/param2=%40%24/) }
|
266
|
+
end
|
267
|
+
|
268
|
+
context "includes the checksum" do
|
269
|
+
let(:params) { { :param1 => "value1", :param2 => "value2" } }
|
270
|
+
let(:checksum) { Digest::SHA1.hexdigest("joinparam1=value1¶m2=value2#{salt}") }
|
271
|
+
subject { api.get_url(:join, params) }
|
272
|
+
it { subject.should match(/checksum=#{checksum}$/) }
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
# FIXME: this complex test means that the method is too complex - try to refactor it
|
278
|
+
describe "#send_api_request" do
|
279
|
+
let(:method) { :join }
|
280
|
+
let(:params) { { :param1 => "value1" } }
|
281
|
+
let(:target_url) { "http://test-server:8080?param1=value1&checksum=12345" }
|
282
|
+
let(:make_request) { api.send_api_request(method, params) }
|
283
|
+
before { api.should_receive(:get_url).with(method, params).and_return(target_url) }
|
284
|
+
|
285
|
+
def setup_http_mock
|
286
|
+
@http_mock = mock(Net::HTTP)
|
287
|
+
Net::HTTP.should_receive(:new).with("test-server", 8080).and_return(@http_mock)
|
288
|
+
@http_mock.should_receive(:"open_timeout=").with(api.timeout)
|
289
|
+
@http_mock.should_receive(:"read_timeout=").with(api.timeout)
|
290
|
+
end
|
291
|
+
|
292
|
+
context "sets up the Net::HTTP object correctly" do
|
293
|
+
before do
|
294
|
+
setup_http_mock
|
295
|
+
response_mock = mock()
|
296
|
+
@http_mock.should_receive(:get).and_return(response_mock)
|
297
|
+
response_mock.should_receive(:body).and_return("") # so the method exits right after the setup
|
298
|
+
end
|
299
|
+
it { make_request }
|
300
|
+
end
|
301
|
+
|
302
|
+
context "handles a TimeoutError" do
|
303
|
+
before do
|
304
|
+
setup_http_mock
|
305
|
+
@http_mock.should_receive(:get) { raise TimeoutError }
|
306
|
+
end
|
307
|
+
it { expect { make_request }.to raise_error(BigBlueButton::BigBlueButtonException) }
|
308
|
+
end
|
309
|
+
|
310
|
+
context "handles general Exceptions" do
|
311
|
+
before do
|
312
|
+
setup_http_mock
|
313
|
+
@http_mock.should_receive(:get) { raise Exception }
|
314
|
+
end
|
315
|
+
it { expect { make_request }.to raise_error(BigBlueButton::BigBlueButtonException) }
|
316
|
+
end
|
317
|
+
|
318
|
+
context "returns an empty hash if the response body is empty" do
|
319
|
+
before do
|
320
|
+
setup_http_mock
|
321
|
+
response_mock = mock()
|
322
|
+
@http_mock.should_receive(:get).and_return(response_mock)
|
323
|
+
response_mock.should_receive(:body).and_return("")
|
324
|
+
end
|
325
|
+
it { make_request.should == { } }
|
326
|
+
end
|
327
|
+
|
328
|
+
context "hashfies and validates the response body" do
|
329
|
+
before do
|
330
|
+
setup_http_mock
|
331
|
+
response_mock = mock()
|
332
|
+
@http_mock.should_receive(:get).and_return(response_mock)
|
333
|
+
response_mock.should_receive(:body).twice.and_return("response-body")
|
334
|
+
end
|
335
|
+
|
336
|
+
context "checking if it has a :response key" do
|
337
|
+
before { Hash.should_receive(:from_xml).with("response-body").and_return({ }) }
|
338
|
+
it { expect { make_request }.to raise_error(BigBlueButton::BigBlueButtonException) }
|
339
|
+
end
|
340
|
+
|
341
|
+
context "checking if it the :response key has a :returncode key" do
|
342
|
+
before { Hash.should_receive(:from_xml).with("response-body").and_return({ :response => { } }) }
|
343
|
+
it { expect { make_request }.to raise_error(BigBlueButton::BigBlueButtonException) }
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
context "formats the response hash" do
|
348
|
+
let(:response) { { :response => { :returncode => true } } }
|
349
|
+
let(:formatted_response) { { :returncode => true } }
|
350
|
+
before do
|
351
|
+
setup_http_mock
|
352
|
+
|
353
|
+
response_mock = mock()
|
354
|
+
@http_mock.should_receive(:get).and_return(response_mock)
|
355
|
+
response_mock.should_receive(:body).twice.and_return("response-body")
|
356
|
+
Hash.should_receive(:from_xml).with("response-body").and_return(response)
|
357
|
+
|
358
|
+
# here starts the validation
|
359
|
+
formatter_mock = mock(BigBlueButton::BigBlueButtonFormatter)
|
360
|
+
BigBlueButton::BigBlueButtonFormatter.should_receive(:new).with(response).and_return(formatter_mock)
|
361
|
+
formatter_mock.should_receive(:default_formatting).and_return(formatted_response)
|
362
|
+
end
|
363
|
+
it { make_request }
|
364
|
+
end
|
365
|
+
|
366
|
+
context "raise an error if the formatted response has no :returncode" do
|
367
|
+
let(:response) { { :response => { :returncode => true } } }
|
368
|
+
let(:formatted_response) { { } }
|
369
|
+
before do
|
370
|
+
setup_http_mock
|
371
|
+
|
372
|
+
response_mock = mock()
|
373
|
+
@http_mock.should_receive(:get).and_return(response_mock)
|
374
|
+
response_mock.should_receive(:body).twice.and_return("response-body")
|
375
|
+
Hash.should_receive(:from_xml).with("response-body").and_return(response)
|
376
|
+
|
377
|
+
formatter_mock = mock(BigBlueButton::BigBlueButtonFormatter)
|
378
|
+
BigBlueButton::BigBlueButtonFormatter.should_receive(:new).with(response).and_return(formatter_mock)
|
379
|
+
formatter_mock.should_receive(:default_formatting).and_return(formatted_response)
|
380
|
+
end
|
381
|
+
it { expect { make_request }.to raise_error(BigBlueButton::BigBlueButtonException) }
|
382
|
+
end
|
383
|
+
|
384
|
+
end
|
385
|
+
|
386
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BigBlueButton::BigBlueButtonException do
|
4
|
+
|
5
|
+
describe "#key" do
|
6
|
+
subject { BigBlueButton::BigBlueButtonException.new }
|
7
|
+
it { should respond_to(:key) }
|
8
|
+
it { should respond_to("key=") }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#to_s" do
|
12
|
+
context "when key is set" do
|
13
|
+
let(:api) { BigBlueButton::BigBlueButtonException.new("super-msg") }
|
14
|
+
before { api.key = "key-msg" }
|
15
|
+
it { api.to_s.should == "super-msg, messageKey: key-msg" }
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when key is not set" do
|
19
|
+
let(:api) { BigBlueButton::BigBlueButtonException.new("super-msg") }
|
20
|
+
before { api.key = nil }
|
21
|
+
it { api.to_s.should == "super-msg" }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BigBlueButton::BigBlueButtonFormatter do
|
4
|
+
|
5
|
+
describe "#hash" do
|
6
|
+
subject { BigBlueButton::BigBlueButtonFormatter.new({}) }
|
7
|
+
it { subject.should respond_to(:hash) }
|
8
|
+
it { subject.should respond_to(:"hash=") }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#to_stringtring" do
|
12
|
+
let(:hash) { { :param1 => "123", :param2 => 123, :param3 => true } }
|
13
|
+
subject { BigBlueButton::BigBlueButtonFormatter.new(hash) }
|
14
|
+
it { subject.to_string(:param1).should == "123" }
|
15
|
+
it { subject.to_string(:param2).should == "123" }
|
16
|
+
it { subject.to_string(:param3).should == "true" }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#to_booleanoolean" do
|
20
|
+
let(:hash) { { :true1 => "TRUE", :true2 => "true", :false1 => "FALSE", :false2 => "false" } }
|
21
|
+
subject { BigBlueButton::BigBlueButtonFormatter.new(hash) }
|
22
|
+
it { subject.to_boolean(:true1).should be_true }
|
23
|
+
it { subject.to_boolean(:true2).should be_true }
|
24
|
+
it { subject.to_boolean(:false1).should be_false }
|
25
|
+
it { subject.to_boolean(:false2).should be_false }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#to_datetime" do
|
29
|
+
let(:hash) { { :param1 => "Thu Sep 01 17:51:42 UTC 2011", :param2 => "Thu Sep 08", :param3 => "NULL" } }
|
30
|
+
subject { BigBlueButton::BigBlueButtonFormatter.new(hash) }
|
31
|
+
it { subject.to_datetime(:param1).should == DateTime.parse("Thu Sep 01 17:51:42 UTC 2011") }
|
32
|
+
it { subject.to_datetime(:param2).should == DateTime.parse("Thu Sep 08") }
|
33
|
+
it { subject.to_datetime(:param3).should == nil }
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#default_formatting" do
|
37
|
+
let(:input) { { :response => { :returncode => "SUCCESS", :messageKey => "mkey", :message => "m" } } }
|
38
|
+
let(:formatter) { BigBlueButton::BigBlueButtonFormatter.new(input) }
|
39
|
+
|
40
|
+
context "standard case" do
|
41
|
+
let(:expected_output) { { :returncode => true, :messageKey => "mkey", :message => "m" } }
|
42
|
+
subject { formatter.default_formatting }
|
43
|
+
it { subject.should == expected_output }
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when :returncode should be false" do
|
47
|
+
before { input[:response][:returncode] = "ERROR" }
|
48
|
+
subject { formatter.default_formatting }
|
49
|
+
it { subject[:returncode].should be_false }
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when :messageKey is empty" do
|
53
|
+
before { input[:response][:messageKey] = {} }
|
54
|
+
subject { formatter.default_formatting }
|
55
|
+
it { subject[:messageKey].should == "" }
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when :messageKey is nil" do
|
59
|
+
before { input[:response].delete(:messageKey) }
|
60
|
+
subject { formatter.default_formatting }
|
61
|
+
it { subject[:messageKey].should == "" }
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when :message is empty" do
|
65
|
+
before { input[:response][:message] = {} }
|
66
|
+
subject { formatter.default_formatting }
|
67
|
+
it { subject[:message].should == "" }
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when there's no :message key" do
|
71
|
+
before { input[:response].delete(:message) }
|
72
|
+
subject { formatter.default_formatting }
|
73
|
+
it { subject[:message].should == "" }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#format_meeting" do
|
78
|
+
let(:formatter) { BigBlueButton::BigBlueButtonFormatter.new({}) }
|
79
|
+
let(:hash) {
|
80
|
+
{ :meetingID => 123, :moderatorPW => 111, :attendeePW => 222,
|
81
|
+
:hasBeenForciblyEnded => "FALSE", :running => "TRUE" }
|
82
|
+
}
|
83
|
+
|
84
|
+
subject { formatter.format_meeting(hash) }
|
85
|
+
it { subject[:meetingID].should == "123" }
|
86
|
+
it { subject[:moderatorPW].should == "111" }
|
87
|
+
it { subject[:attendeePW].should == "222" }
|
88
|
+
it { subject[:hasBeenForciblyEnded].should == false }
|
89
|
+
it { subject[:running].should == true }
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#format_attendee" do
|
93
|
+
let(:formatter) { BigBlueButton::BigBlueButtonFormatter.new({}) }
|
94
|
+
let(:hash) { { :userID => 123, :fullName => "Cameron", :role => "VIEWER" } }
|
95
|
+
|
96
|
+
subject { formatter.format_attendee(hash) }
|
97
|
+
it { subject[:userID].should == "123" }
|
98
|
+
it { subject[:fullName].should == "Cameron" }
|
99
|
+
it { subject[:role].should == :viewer }
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#flatten_objects" do
|
103
|
+
let(:formatter) { BigBlueButton::BigBlueButtonFormatter.new({ }) }
|
104
|
+
|
105
|
+
context "standard case" do
|
106
|
+
context "when the target key is empty" do
|
107
|
+
let(:hash) { { :objects => {} } }
|
108
|
+
before { formatter.hash = hash }
|
109
|
+
subject { formatter.flatten_objects(:objects, :object) }
|
110
|
+
it { subject.should == { :objects => [] } }
|
111
|
+
end
|
112
|
+
|
113
|
+
context "when there's only one object in the list" do
|
114
|
+
let(:object_hash) { { :id => 1 } }
|
115
|
+
let(:hash) { { :objects => { :object => object_hash } } }
|
116
|
+
before { formatter.hash = hash }
|
117
|
+
subject { formatter.flatten_objects(:objects, :object) }
|
118
|
+
it { subject.should == { :objects => [ object_hash ] } }
|
119
|
+
end
|
120
|
+
|
121
|
+
context "when there are several objects in the list" do
|
122
|
+
let(:object_hash1) { { :id => 1 } }
|
123
|
+
let(:object_hash2) { { :id => 2 } }
|
124
|
+
let(:hash) { { :objects => { :object => [ object_hash1, object_hash2 ] } } }
|
125
|
+
before { formatter.hash = hash }
|
126
|
+
subject { formatter.flatten_objects(:objects, :object) }
|
127
|
+
it { subject.should == { :objects => [ object_hash1, object_hash2 ] } }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "using different keys" do
|
132
|
+
let(:hash1) { { :any => 1 } }
|
133
|
+
let(:hash2) { { :any => 2 } }
|
134
|
+
let(:collection_hash) { { :foos => { :bar => [ hash1, hash2 ] } } }
|
135
|
+
before { formatter.hash = collection_hash }
|
136
|
+
subject { formatter.flatten_objects(:foos, :bar) }
|
137
|
+
it { subject.should == { :foos => [ hash1, hash2 ] } }
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Load support files
|
2
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
3
|
+
|
4
|
+
# Load Factories
|
5
|
+
#require 'factory_girl'
|
6
|
+
#require 'forgery'
|
7
|
+
#Dir["#{ File.dirname(__FILE__)}/factories/*.rb"].each { |f| require f }
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.mock_with :rspec
|
11
|
+
end
|
12
|
+
|
13
|
+
require "bigbluebutton_api"
|
data/test/test.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
+
$:.unshift File.expand_path(File.dirname(__FILE__))
|
2
|
+
$:.unshift File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
|
3
|
+
|
1
4
|
require 'bigbluebutton-api'
|
2
5
|
require 'thread'
|
3
6
|
require 'yaml'
|
4
7
|
|
5
8
|
def prepare
|
6
9
|
|
7
|
-
config_file = '
|
10
|
+
config_file = File.join(File.dirname(__FILE__), 'config.yml')
|
8
11
|
unless File.exist? config_file
|
9
12
|
puts config_file + " does not exists. Copy the example and configure your server."
|
10
13
|
puts "cp test/config.yml.example test/config.yml"
|
@@ -135,8 +138,17 @@ def join_test
|
|
135
138
|
|
136
139
|
end
|
137
140
|
|
141
|
+
def get_version_test
|
142
|
+
@api = BigBlueButton::BigBlueButtonApi.new(@config['bbb_url'], @config['bbb_salt'], nil, true)
|
143
|
+
|
144
|
+
puts
|
145
|
+
puts "---------------------------------------------------"
|
146
|
+
puts "The version of your BBB server is: #{@api.version}"
|
147
|
+
end
|
148
|
+
|
138
149
|
begin
|
139
150
|
prepare
|
140
151
|
general_test
|
141
152
|
#join_test
|
153
|
+
#get_version_test
|
142
154
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bigbluebutton-api-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-09-02 00:00:00.000000000Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: nokogiri
|
17
|
-
requirement: &
|
17
|
+
requirement: &20159120 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
@@ -22,7 +22,7 @@ dependencies:
|
|
22
22
|
version: 1.4.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *20159120
|
26
26
|
description: Provides an interface to the BigBlueButton web meeting API (https://github.com/mconf/bigbluebutton-api-ruby)
|
27
27
|
email:
|
28
28
|
- leonardodaronco@gmail.com
|
@@ -35,13 +35,23 @@ extra_rdoc_files:
|
|
35
35
|
- CHANGELOG.rdoc
|
36
36
|
files:
|
37
37
|
- .gitignore
|
38
|
+
- .rspec
|
39
|
+
- .rvmrc
|
38
40
|
- CHANGELOG.rdoc
|
41
|
+
- Gemfile
|
42
|
+
- Gemfile.lock
|
39
43
|
- LICENSE
|
40
44
|
- README.rdoc
|
41
45
|
- Rakefile
|
42
46
|
- bigbluebutton-api-ruby.gemspec
|
43
|
-
- lib/
|
47
|
+
- lib/bigbluebutton_api.rb
|
48
|
+
- lib/bigbluebutton_exception.rb
|
49
|
+
- lib/bigbluebutton_formatter.rb
|
44
50
|
- lib/hash_to_xml.rb
|
51
|
+
- spec/bigbluebutton_api_spec.rb
|
52
|
+
- spec/bigbluebutton_exception_spec.rb
|
53
|
+
- spec/bigbluebutton_formatter_spec.rb
|
54
|
+
- spec/spec_helper.rb
|
45
55
|
- test/config.yml.example
|
46
56
|
- test/test.rb
|
47
57
|
homepage: https://github.com/mconf/bigbluebutton-api-ruby/
|
@@ -64,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
74
|
version: '0'
|
65
75
|
requirements: []
|
66
76
|
rubyforge_project:
|
67
|
-
rubygems_version: 1.
|
77
|
+
rubygems_version: 1.8.10
|
68
78
|
signing_key:
|
69
79
|
specification_version: 3
|
70
80
|
summary: Provides an interface to the BigBlueButton web meeting API (https://github.com/mconf/bigbluebutton-api-ruby)
|