bigbluebutton_rails 1.3.0 → 1.4.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. data/.gitignore +2 -0
  2. data/.rspec +2 -2
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.rdoc +31 -6
  5. data/Gemfile +13 -3
  6. data/Gemfile.lock +88 -42
  7. data/README.rdoc +84 -15
  8. data/Rakefile +22 -25
  9. data/{TODO_08 → TODO.rdoc} +6 -2
  10. data/app/assets/images/badges/apple_store_en.png +0 -0
  11. data/app/assets/images/badges/apple_store_pt-br.png +0 -0
  12. data/app/assets/images/badges/google_play_en.png +0 -0
  13. data/app/assets/images/badges/google_play_pt-br.png +0 -0
  14. data/app/controllers/bigbluebutton/recordings_controller.rb +25 -10
  15. data/app/controllers/bigbluebutton/rooms_controller.rb +158 -141
  16. data/app/controllers/bigbluebutton/servers_controller.rb +25 -12
  17. data/app/helpers/bigbluebutton_rails_helper.rb +20 -0
  18. data/app/models/bigbluebutton_meeting.rb +28 -0
  19. data/app/models/bigbluebutton_metadata.rb +2 -2
  20. data/app/models/bigbluebutton_playback_format.rb +2 -2
  21. data/app/models/bigbluebutton_recording.rb +29 -4
  22. data/app/models/bigbluebutton_room.rb +153 -22
  23. data/app/models/bigbluebutton_room_options.rb +46 -0
  24. data/app/models/bigbluebutton_server.rb +4 -2
  25. data/app/views/bigbluebutton/recordings/_form.html.erb +4 -0
  26. data/app/views/bigbluebutton/recordings/_recordings.html.erb +1 -0
  27. data/app/views/bigbluebutton/recordings/show.html.erb +5 -0
  28. data/app/views/bigbluebutton/rooms/join_mobile.html.erb +29 -5
  29. data/app/workers/bigbluebutton_meeting_updater.rb +31 -0
  30. data/bigbluebutton_rails.gemspec +5 -1
  31. data/config/locales/en.yml +6 -5
  32. data/config/schedule.rb +4 -0
  33. data/lib/bigbluebutton_rails/controller_methods.rb +29 -10
  34. data/lib/bigbluebutton_rails/internal_controller_methods.rb +56 -0
  35. data/lib/bigbluebutton_rails/rails/routes.rb +1 -5
  36. data/lib/bigbluebutton_rails/version.rb +1 -1
  37. data/lib/bigbluebutton_rails.rb +11 -0
  38. data/lib/generators/bigbluebutton_rails/templates/migration.rb +28 -0
  39. data/lib/generators/bigbluebutton_rails/templates/migration_1_4_0.rb +37 -0
  40. data/lib/tasks/bigbluebutton_rails/meetings.rake +22 -0
  41. data/lib/tasks/bigbluebutton_rails/recordings.rake +2 -1
  42. data/spec/classes/bigbluebutton_attendee_spec.rb +1 -1
  43. data/spec/controllers/bigbluebutton/recordings_controller_json_responses_spec.rb +10 -9
  44. data/spec/controllers/bigbluebutton/recordings_controller_spec.rb +103 -16
  45. data/spec/controllers/bigbluebutton/rooms_controller_exception_handling_spec.rb +15 -5
  46. data/spec/controllers/bigbluebutton/rooms_controller_json_responses_spec.rb +17 -12
  47. data/spec/controllers/bigbluebutton/rooms_controller_spec.rb +485 -432
  48. data/spec/controllers/bigbluebutton/servers_controller_json_responses_spec.rb +20 -13
  49. data/spec/controllers/bigbluebutton/servers_controller_spec.rb +174 -16
  50. data/spec/factories/bigbluebutton_meeting.rb +13 -0
  51. data/spec/factories/bigbluebutton_recording.rb +4 -2
  52. data/spec/factories/bigbluebutton_room.rb +5 -1
  53. data/spec/factories/bigbluebutton_room_options.rb +6 -0
  54. data/spec/generators/install_generator_spec.rb +1 -1
  55. data/spec/generators/views_generator_spec.rb +0 -1
  56. data/spec/lib/tasks/meetings_rake_spec.rb +5 -0
  57. data/spec/lib/tasks/recordings_rake_spec.rb +5 -0
  58. data/spec/models/bigbluebutton_meeting_db_spec.rb +24 -0
  59. data/spec/models/bigbluebutton_meeting_spec.rb +52 -0
  60. data/spec/models/bigbluebutton_metadata_db_spec.rb +2 -0
  61. data/spec/models/bigbluebutton_metadata_spec.rb +18 -22
  62. data/spec/models/bigbluebutton_playback_format_db_spec.rb +2 -0
  63. data/spec/models/bigbluebutton_playback_format_spec.rb +0 -4
  64. data/spec/models/bigbluebutton_recording_db_spec.rb +3 -0
  65. data/spec/models/bigbluebutton_recording_spec.rb +69 -16
  66. data/spec/models/bigbluebutton_room_db_spec.rb +2 -0
  67. data/spec/models/bigbluebutton_room_options_db_spec.rb +16 -0
  68. data/spec/models/bigbluebutton_room_options_spec.rb +206 -0
  69. data/spec/models/bigbluebutton_room_spec.rb +420 -80
  70. data/spec/models/bigbluebutton_server_db_spec.rb +2 -0
  71. data/spec/models/bigbluebutton_server_spec.rb +22 -24
  72. data/spec/rails_app/config/application.rb +3 -0
  73. data/spec/rails_app/config/database.yml.example +28 -0
  74. data/spec/rails_app/config/environments/test.rb +1 -1
  75. data/spec/rails_app/db/seeds.rb +1 -0
  76. data/spec/rails_app/features/step_definitions/activity_monitor_servers_step.rb +0 -2
  77. data/spec/rails_app/features/step_definitions/common_steps.rb +6 -0
  78. data/spec/rails_app/features/step_definitions/join_rooms_steps.rb +0 -6
  79. data/spec/rails_app/features/support/locales.rb +4 -2
  80. data/spec/rails_app/features/support/paths.rb +0 -2
  81. data/spec/rails_app/features/support/templates.rb +2 -17
  82. data/spec/rails_app/lib/tasks/db/populate.rake +2 -0
  83. data/spec/rails_app/lib/tasks/resque.rake +3 -0
  84. data/spec/routing/bigbluebutton/custom_controllers_routing_spec.rb +1 -10
  85. data/spec/routing/bigbluebutton/rooms_only_routing_spec.rb +1 -9
  86. data/spec/routing/bigbluebutton/rooms_routing_spec.rb +3 -31
  87. data/spec/spec_helper.rb +40 -24
  88. data/spec/support/matchers/array_with_key.rb +7 -0
  89. data/spec/support/matchers/array_without_key.rb +7 -0
  90. data/spec/support/matchers/delegate_matcher.rb +62 -0
  91. data/spec/support/matchers/respond_with_content_type.rb +8 -0
  92. data/spec/support/matchers/shoulda/assign_to_matcher.rb +131 -0
  93. data/spec/support/mocked_server.rb +2 -2
  94. data/spec/support/models/user.rb +11 -0
  95. data/spec/workers/bigbluebutton_meeting_updater_spec.rb +9 -0
  96. metadata +86 -16
  97. data/app/views/bigbluebutton/rooms/external.html.erb +0 -25
  98. data/spec/rails_app/config/database.yml +0 -25
  99. data/spec/rails_app/features/join_external_rooms.feature +0 -61
@@ -11,6 +11,8 @@ describe BigbluebuttonRecording do
11
11
 
12
12
  it { should belong_to(:room) }
13
13
 
14
+ it { should belong_to(:meeting) }
15
+
14
16
  it { should validate_presence_of(:recordid) }
15
17
  it { should validate_uniqueness_of(:recordid) }
16
18
 
@@ -44,7 +46,7 @@ describe BigbluebuttonRecording do
44
46
  }
45
47
  end
46
48
 
47
- describe "#sync" do
49
+ describe ".sync" do
48
50
  let(:data) {
49
51
  [
50
52
  {
@@ -192,7 +194,7 @@ describe BigbluebuttonRecording do
192
194
  end
193
195
  end
194
196
 
195
- describe "#update_recording" do
197
+ describe ".update_recording" do
196
198
  let(:old_attrs) { FactoryGirl.attributes_for(:bigbluebutton_recording) }
197
199
  let(:attrs) { FactoryGirl.attributes_for(:bigbluebutton_recording) }
198
200
  let(:recording) { FactoryGirl.create(:bigbluebutton_recording, old_attrs) }
@@ -226,11 +228,13 @@ describe BigbluebuttonRecording do
226
228
  it { recording.room.should == @room }
227
229
  end
228
230
 
229
- describe "#create_recording" do
231
+ describe ".create_recording" do
232
+ let(:meeting_start_time) { DateTime.now }
233
+ let(:recordid) { "#{SecureRandom.uuid}-#{meeting_start_time.to_i}" }
230
234
  let(:attrs) { FactoryGirl.attributes_for(:bigbluebutton_recording) }
231
235
  let(:data) {
232
236
  {
233
- :recordid => attrs[:recordid],
237
+ :recordid => recordid,
234
238
  :meetingid => attrs[:meetingid],
235
239
  :name => attrs[:name],
236
240
  :published => attrs[:published],
@@ -244,22 +248,29 @@ describe BigbluebuttonRecording do
244
248
 
245
249
  before {
246
250
  @room = FactoryGirl.create(:bigbluebutton_room, :meetingid => attrs[:meetingid])
251
+ @meeting = FactoryGirl.create(:bigbluebutton_meeting, :room => @room, :start_time => meeting_start_time.utc)
252
+
247
253
  BigbluebuttonRecording.should_receive(:sync_additional_data)
248
254
  .with(anything, data)
249
255
  BigbluebuttonRecording.send(:create_recording, new_server, data)
250
256
  @recording = BigbluebuttonRecording.last
251
257
  }
252
- it { @recording.recordid.should == attrs[:recordid] }
253
- it { @recording.meetingid.should == attrs[:meetingid] }
254
- it { @recording.name.should == attrs[:name] }
255
- it { @recording.published.should == attrs[:published] }
256
- it { @recording.end_time.utc.to_i.should == attrs[:end_time].utc.to_i }
257
- it { @recording.start_time.utc.to_i.should == attrs[:start_time].utc.to_i }
258
- it { @recording.server.should == new_server }
259
- it { @recording.room.should == @room }
258
+ it("sets recordid") { @recording.recordid.should == recordid }
259
+ it("sets meetingid") { @recording.meetingid.should == attrs[:meetingid] }
260
+ it("sets name") { @recording.name.should == attrs[:name] }
261
+ it("sets published") { @recording.published.should == attrs[:published] }
262
+ it("sets end_time") { @recording.end_time.utc.to_i.should == attrs[:end_time].utc.to_i }
263
+ it("sets start_time") { @recording.start_time.utc.to_i.should == attrs[:start_time].utc.to_i }
264
+ it("sets server") { @recording.server.should == new_server }
265
+ it("sets room") { @recording.room.should == @room }
266
+ it("sets meeting") { @recording.meeting.should == @meeting }
267
+ it("sets description") {
268
+ time = data[:start_time].utc.to_formatted_s(:long)
269
+ @recording.description.should == I18n.t('bigbluebutton_rails.recordings.default.description', :time => time)
270
+ }
260
271
  end
261
272
 
262
- describe "#adapt_recording_hash" do
273
+ describe ".adapt_recording_hash" do
263
274
  let(:before) {
264
275
  { :recordID => "anything",
265
276
  :meetingID => "anything",
@@ -282,7 +293,7 @@ describe BigbluebuttonRecording do
282
293
  it { should eq(after) }
283
294
  end
284
295
 
285
- describe "#sync_additional_data" do
296
+ describe ".sync_additional_data" do
286
297
  let(:attrs) { FactoryGirl.attributes_for(:bigbluebutton_recording) }
287
298
  let(:recording) { FactoryGirl.create(:bigbluebutton_recording) }
288
299
  let(:data) {
@@ -327,7 +338,7 @@ describe BigbluebuttonRecording do
327
338
  end
328
339
  end
329
340
 
330
- describe "#sync_metadata" do
341
+ describe ".sync_metadata" do
331
342
  let(:recording) { FactoryGirl.create(:bigbluebutton_recording) }
332
343
 
333
344
  context "updates metadata that are already in the db" do
@@ -386,7 +397,7 @@ describe BigbluebuttonRecording do
386
397
 
387
398
  end
388
399
 
389
- describe "#sync_playback_formats" do
400
+ describe ".sync_playback_formats" do
390
401
  let(:recording) { FactoryGirl.create(:bigbluebutton_recording) }
391
402
 
392
403
  context "with several formats" do
@@ -447,4 +458,46 @@ describe BigbluebuttonRecording do
447
458
 
448
459
  end
449
460
 
461
+ describe ".find_matching_meeting" do
462
+
463
+ context "if no recording is informed" do
464
+ let(:recording) { FactoryGirl.create(:bigbluebutton_recording, :room => nil) }
465
+ subject { BigbluebuttonRecording.send(:find_matching_meeting, nil) }
466
+ it { subject.should be_nil }
467
+ end
468
+
469
+ context "if the recording has no room associated to it" do
470
+ let(:recording) { FactoryGirl.create(:bigbluebutton_recording, :room => nil) }
471
+ subject { BigbluebuttonRecording.send(:find_matching_meeting, recording) }
472
+ it { subject.should be_nil }
473
+ end
474
+
475
+ context "if can't find the start time in recordid" do
476
+ let(:recording) { FactoryGirl.create(:bigbluebutton_recording, :recordid => "without-timestamp") }
477
+ subject { BigbluebuttonRecording.send(:find_matching_meeting, recording) }
478
+ it { subject.should be_nil }
479
+ end
480
+
481
+ context "if found a start time in recordid" do
482
+ let(:meeting_start_time) { DateTime.now }
483
+ let(:recording) {
484
+ FactoryGirl.create(:bigbluebutton_recording, :recordid => "#{SecureRandom.uuid}-#{meeting_start_time.to_i}")
485
+ }
486
+
487
+ context "when there's no associated meeting" do
488
+ subject { BigbluebuttonRecording.send(:find_matching_meeting, recording) }
489
+ it { subject.should be_nil }
490
+ end
491
+
492
+ context "when there's one associated meeting" do
493
+ before {
494
+ @meeting = FactoryGirl.create(:bigbluebutton_meeting, :room => recording.room, :start_time => meeting_start_time)
495
+ }
496
+ subject { BigbluebuttonRecording.send(:find_matching_meeting, recording) }
497
+ it { subject.should eq(@meeting) }
498
+ end
499
+ end
500
+
501
+ end
502
+
450
503
  end
@@ -21,6 +21,8 @@ describe BigbluebuttonRoom do
21
21
  it { should have_db_column(:param).of_type(:string) }
22
22
  it { should have_db_column(:record).of_type(:boolean) }
23
23
  it { should have_db_column(:duration).of_type(:integer) }
24
+ it { should have_db_column(:created_at).of_type(:datetime) }
25
+ it { should have_db_column(:updated_at).of_type(:datetime) }
24
26
  it { should have_db_index(:server_id) }
25
27
  it { should have_db_index(:meetingid).unique(true) }
26
28
  it { should have_db_index(:voice_bridge).unique(true) }
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe BigbluebuttonRoomOptions do
4
+
5
+ # to ensure that the migration is correct
6
+ context "db" do
7
+ it { should have_db_column(:room_id).of_type(:integer) }
8
+ it { should have_db_column(:default_layout).of_type(:string) }
9
+ it { should have_db_column(:created_at).of_type(:datetime) }
10
+ it { should have_db_column(:updated_at).of_type(:datetime) }
11
+ it { should have_db_column(:presenter_share_only).of_type(:boolean)}
12
+ it { should have_db_column(:auto_start_video).of_type(:boolean) }
13
+ it { should have_db_column(:auto_start_audio).of_type(:boolean) }
14
+ end
15
+
16
+ end
@@ -0,0 +1,206 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe BigbluebuttonRoomOptions do
5
+ it "loaded correctly" do
6
+ BigbluebuttonRoomOptions.new.should be_a_kind_of(ActiveRecord::Base)
7
+ end
8
+
9
+ let(:room_options) { FactoryGirl.create(:bigbluebutton_room).room_options }
10
+
11
+ it { should belong_to(:room) }
12
+ it {
13
+ room = FactoryGirl.create(:bigbluebutton_room)
14
+ BigbluebuttonRoomOptions.new(:room => room)
15
+ .room.should be_a_kind_of(BigbluebuttonRoom) }
16
+ it { should validate_presence_of(:room_id) }
17
+
18
+ describe "#get_available_layouts" do
19
+ it "returns the layouts available" do
20
+ expected = ["Default", "Video Chat", "Meeting", "Webinar", "Lecture assistant", "Lecture"]
21
+ room_options.get_available_layouts.should eql(expected)
22
+ end
23
+ end
24
+
25
+ describe "#set_on_config_xml" do
26
+ let(:config_xml) { '<config></config>' }
27
+
28
+ context "if the xml changed" do
29
+ before {
30
+ # set a few values to true and a few to false to test both cases
31
+ room_options.update_attributes(:default_layout => "AnyLayout",
32
+ :presenter_share_only => true,
33
+ :auto_start_video => false,
34
+ :auto_start_audio => false)
35
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
36
+ .should_receive(:set_attribute)
37
+ .with('layout', 'defaultLayout', "AnyLayout", false)
38
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
39
+ .should_receive(:set_attribute)
40
+ .with('VideoconfModule', 'presenterShareOnly', true, true)
41
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
42
+ .should_receive(:set_attribute)
43
+ .with('PhoneModule', 'presenterShareOnly', true, true)
44
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
45
+ .should_receive(:set_attribute)
46
+ .with('VideoconfModule', 'autoStart', false, true)
47
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
48
+ .should_receive(:set_attribute)
49
+ .with('PhoneModule', 'autoJoin', false, true)
50
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
51
+ .should_receive(:is_modified?).and_return(true)
52
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
53
+ .should_receive(:as_string).and_return('new xml as string')
54
+ }
55
+ subject { room_options.set_on_config_xml(config_xml) }
56
+ it("returns the new xml") { should eql('new xml as string') }
57
+ end
58
+
59
+ context "if the xml did not change" do
60
+ before {
61
+ room_options.update_attributes(:default_layout => "AnyLayout",
62
+ :presenter_share_only => false,
63
+ :auto_start_video => false,
64
+ :auto_start_audio => false)
65
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
66
+ .should_receive(:set_attribute)
67
+ .with('layout', 'defaultLayout', "AnyLayout", false)
68
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
69
+ .should_receive(:set_attribute)
70
+ .with('VideoconfModule', 'presenterShareOnly', false, true)
71
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
72
+ .should_receive(:set_attribute)
73
+ .with('PhoneModule', 'presenterShareOnly', false, true)
74
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
75
+ .should_receive(:set_attribute)
76
+ .with('VideoconfModule', 'autoStart', false, true)
77
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
78
+ .should_receive(:set_attribute)
79
+ .with('PhoneModule', 'autoJoin', false, true)
80
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
81
+ .should_receive(:is_modified?).and_return(false)
82
+ }
83
+ subject { room_options.set_on_config_xml(config_xml) }
84
+ it("returns false") { should be_false }
85
+ end
86
+
87
+ context "if #default_layout is" do
88
+ context "nil" do
89
+ before {
90
+ room_options.update_attributes(:default_layout => nil)
91
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
92
+ .should_not_receive(:set_attribute)
93
+ .with('layout', 'defaultLayout', anything, anything)
94
+ }
95
+ it("doesn't set the property in the xml") { room_options.set_on_config_xml(config_xml) }
96
+ end
97
+
98
+ context "empty string" do
99
+ before {
100
+ room_options.update_attributes(:default_layout => "")
101
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
102
+ .should_not_receive(:set_attribute)
103
+ .with('layout', 'defaultLayout', anything, anything)
104
+ }
105
+ it("doesn't set the property in the xml") { room_options.set_on_config_xml(config_xml) }
106
+ end
107
+ end
108
+
109
+ context "if #presenter_share_only is" do
110
+ context "nil" do
111
+ before {
112
+ room_options.update_attributes(:presenter_share_only => nil)
113
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
114
+ .should_not_receive(:set_attribute)
115
+ .with('VideoconfModule', 'presenterShareOnly', anything, anything)
116
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
117
+ .should_not_receive(:set_attribute)
118
+ .with('PhoneModule', 'presenterShareOnly', anything, anything)
119
+ }
120
+ it("doesn't set the property in the xml") { room_options.set_on_config_xml(config_xml) }
121
+ end
122
+ end
123
+
124
+ context "if #auto_start_video is" do
125
+ context "nil" do
126
+ before {
127
+ room_options.update_attributes(:auto_start_video => nil)
128
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
129
+ .should_not_receive(:set_attribute)
130
+ .with('VideoconfModule', 'autoStart', anything, anything)
131
+ }
132
+ it("doesn't set the property in the xml") { room_options.set_on_config_xml(config_xml) }
133
+ end
134
+ end
135
+
136
+ context "if #auto_start_audio is" do
137
+ context "nil" do
138
+ before {
139
+ room_options.update_attributes(:auto_start_audio => nil)
140
+ BigBlueButton::BigBlueButtonConfigXml.any_instance
141
+ .should_not_receive(:set_attribute)
142
+ .with('PhoneModule', 'autoJoin', anything, anything)
143
+ }
144
+ it("doesn't set the property in the xml") {room_options.set_on_config_xml(config_xml) }
145
+ end
146
+ end
147
+
148
+ end
149
+
150
+ describe "#is_modified?" do
151
+ context "if default_layout is set" do
152
+ before { room_options.update_attributes(:default_layout => 'Any') }
153
+ subject { room_options.is_modified? }
154
+ it("returns true") { should be_true }
155
+ end
156
+
157
+ context "if default_layout is not set" do
158
+ before { room_options.update_attributes(:default_layout => nil) }
159
+ subject { room_options.is_modified? }
160
+ it("returns false") { should be_false }
161
+ end
162
+
163
+ context "if default_layout is empty" do
164
+ before { room_options.update_attributes(:default_layout => "") }
165
+ subject { room_options.is_modified? }
166
+ it("returns true") { should be_true }
167
+ end
168
+
169
+ context "if presenter_share_only is set" do
170
+ before { room_options.update_attributes(:presenter_share_only => true) }
171
+ subject { room_options.is_modified? }
172
+ it("returns true") { should be_true}
173
+ end
174
+
175
+ context "if presenter_share_only is not set" do
176
+ before { room_options.update_attributes(:presenter_share_only => nil) }
177
+ subject { room_options.is_modified? }
178
+ it("returns false") { should be_false }
179
+ end
180
+
181
+ context "if auto_start_video is set" do
182
+ before { room_options.update_attributes(:auto_start_video => true) }
183
+ subject { room_options.is_modified? }
184
+ it("returns true") { should be_true}
185
+ end
186
+
187
+ context "if auto_start_video is not set" do
188
+ before { room_options.update_attributes(:auto_start_video => nil) }
189
+ subject { room_options.is_modified? }
190
+ it("returns false" ) { should be_false }
191
+ end
192
+
193
+ context "if auto_start_audio is set" do
194
+ before { room_options.update_attributes(:auto_start_audio => true) }
195
+ subject { room_options.is_modified? }
196
+ it("returns true") { should be_true}
197
+ end
198
+
199
+ context "if auto_start_audio is not set" do
200
+ before { room_options.update_attributes(:auto_start_audio => nil) }
201
+ subject { room_options.is_modified? }
202
+ it("returns false" ) { should be_false }
203
+ end
204
+ end
205
+
206
+ end