bigbluebutton-api-ruby 0.0.10 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|