network_executive 0.0.1.alpha.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +15 -1
  3. data/README.md +9 -41
  4. data/Rakefile +38 -1
  5. data/app/assets/javascripts/application.js +13 -0
  6. data/app/assets/javascripts/network_executive/osd.js +46 -0
  7. data/app/assets/javascripts/network_executive/set_top_box.js +44 -0
  8. data/app/assets/stylesheets/network_executive/application.css +16 -0
  9. data/app/assets/stylesheets/network_executive/gui_components.css +17 -0
  10. data/app/assets/stylesheets/network_executive/normalize.css +500 -0
  11. data/app/assets/stylesheets/network_executive/osd.css +33 -0
  12. data/app/assets/stylesheets/network_executive/smpte.css +164 -0
  13. data/app/controllers/network_executive/application_controller.rb +4 -0
  14. data/app/controllers/network_executive/network_controller.rb +9 -0
  15. data/app/helpers/network_executive/network_helper.rb +7 -0
  16. data/app/models/network_executive/channel.rb +46 -0
  17. data/app/models/network_executive/channel_schedule.rb +13 -0
  18. data/app/models/network_executive/lineup.rb +66 -0
  19. data/app/models/network_executive/lineup_range.rb +34 -0
  20. data/app/models/network_executive/network.rb +10 -0
  21. data/app/models/network_executive/program.rb +39 -0
  22. data/app/models/network_executive/program_schedule.rb +148 -0
  23. data/app/models/network_executive/viewer.rb +76 -0
  24. data/app/views/network_executive/network/index.html.erb +39 -0
  25. data/config/routes.rb +7 -0
  26. data/lib/generators/network_executive/install_generator.rb +96 -0
  27. data/lib/generators/network_executive/templates/initializer.erb +5 -0
  28. data/lib/generators/network_executive/uninstall_generator.rb +20 -0
  29. data/lib/network_executive/configuration.rb +26 -0
  30. data/lib/network_executive/engine.rb +28 -0
  31. data/lib/network_executive/producer.rb +36 -0
  32. data/lib/network_executive/scheduling.rb +44 -0
  33. data/lib/network_executive/station/local_affiliate.rb +21 -0
  34. data/lib/network_executive/station.rb +11 -0
  35. data/lib/network_executive/version.rb +1 -1
  36. data/lib/network_executive.rb +18 -3
  37. data/network_executive.gemspec +9 -8
  38. data/spec/dummy/README.rdoc +261 -0
  39. data/spec/dummy/Rakefile +7 -0
  40. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  41. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  42. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  43. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  44. data/{lib/network_executive/templates/config/lineup.rb → spec/dummy/app/mailers/.gitkeep} +0 -0
  45. data/spec/dummy/app/models/.gitkeep +0 -0
  46. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  47. data/spec/dummy/config/application.rb +47 -0
  48. data/spec/dummy/config/boot.rb +10 -0
  49. data/spec/dummy/config/database.yml +25 -0
  50. data/spec/dummy/config/environment.rb +5 -0
  51. data/spec/dummy/config/environments/development.rb +37 -0
  52. data/spec/dummy/config/environments/production.rb +67 -0
  53. data/spec/dummy/config/environments/test.rb +37 -0
  54. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  55. data/spec/dummy/config/initializers/inflections.rb +15 -0
  56. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  57. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  58. data/spec/dummy/config/initializers/session_store.rb +8 -0
  59. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  60. data/spec/dummy/config/locales/en.yml +5 -0
  61. data/spec/dummy/config/routes.rb +3 -0
  62. data/spec/dummy/config.ru +4 -0
  63. data/spec/dummy/lib/assets/.gitkeep +0 -0
  64. data/spec/dummy/log/.gitkeep +0 -0
  65. data/spec/dummy/public/404.html +26 -0
  66. data/spec/dummy/public/422.html +26 -0
  67. data/spec/dummy/public/500.html +25 -0
  68. data/spec/dummy/public/favicon.ico +0 -0
  69. data/spec/dummy/script/rails +6 -0
  70. data/spec/generators/install_generator_spec.rb +129 -0
  71. data/spec/generators/uninstall_generator_spec.rb +39 -0
  72. data/spec/helpers/network_helper_spec.rb +7 -0
  73. data/spec/models/channel_schedule_spec.rb +29 -0
  74. data/spec/models/channel_spec.rb +55 -0
  75. data/spec/models/lineup_range_spec.rb +65 -0
  76. data/spec/models/lineup_spec.rb +95 -0
  77. data/spec/models/network_spec.rb +11 -0
  78. data/spec/models/program_schedule_spec.rb +399 -0
  79. data/spec/models/program_spec.rb +37 -0
  80. data/spec/models/viewer_spec.rb +210 -0
  81. data/spec/network_executive_spec.rb +15 -0
  82. data/spec/spec_helper.rb +27 -1
  83. data/spec/unit/configuration_spec.rb +3 -0
  84. data/spec/unit/producer_spec.rb +60 -0
  85. data/spec/unit/scheduling_spec.rb +106 -0
  86. data/spec/unit/station/local_affiliate_spec.rb +41 -0
  87. data/tasks/network_executive_tasks.rake +4 -0
  88. metadata +177 -40
  89. data/lib/network_executive/behaviors/file_system.rb +0 -73
  90. data/lib/network_executive/behaviors/terminal_output.rb +0 -84
  91. data/lib/network_executive/cli.rb +0 -29
  92. data/lib/network_executive/commands/application.rb +0 -64
  93. data/lib/network_executive/commands/server.rb +0 -48
  94. data/lib/network_executive/network.rb +0 -5
  95. data/lib/network_executive/templates/app/channels/.gitkeep +0 -1
  96. data/lib/network_executive/templates/config/my_network.rb +0 -5
  97. data/lib/network_executive/templates/my_network.ru +0 -4
  98. data/lib/network_executive/templates/public/.gitkeep +0 -1
  99. data/spec/commands/application_spec.rb +0 -58
  100. data/spec/commands/server_spec.rb +0 -15
@@ -0,0 +1,210 @@
1
+ describe NetworkExecutive::Viewer do
2
+ let(:env) { {} }
3
+
4
+ let(:viewer) { described_class.new( env ) }
5
+
6
+ subject { viewer }
7
+
8
+ describe '#ip' do
9
+ subject { viewer.ip }
10
+
11
+ context 'with a valid HTTP_X_FORWARDED_FOR header' do
12
+ before do
13
+ env['HTTP_X_FORWARDED_FOR'] = '255.255.255.255'
14
+ end
15
+
16
+ it { should == '255.255.255.255' }
17
+ end
18
+
19
+ context 'with an invalid HTTP_X_FORWARDED_FOR header' do
20
+ before do
21
+ env['HTTP_X_FORWARDED_FOR'] = ''
22
+ env['REMOTE_ADDR'] = '10.0.0.1'
23
+ end
24
+
25
+ it { should == '10.0.0.1' }
26
+ end
27
+
28
+ context 'with a REMOTE_ADDR header' do
29
+ before do
30
+ env['REMOTE_ADDR'] = '255.255.255.255'
31
+ end
32
+
33
+ it { should == '255.255.255.255' }
34
+ end
35
+ end
36
+
37
+ describe '#channel' do
38
+ subject { viewer.channel }
39
+
40
+ before do
41
+ described_class.any_instance.stub( :channel_name ).and_return 'test'
42
+ end
43
+
44
+ context 'with a known channel' do
45
+ it 'should find the channel' do
46
+ NetworkExecutive::Channel.should_receive( :find_by_name ).with( 'test' ).and_return true
47
+
48
+ subject
49
+ end
50
+ end
51
+
52
+ context 'with an unknown channel' do
53
+ it 'should raise an exception' do
54
+ NetworkExecutive::Channel.stub(:find_by_name).and_return nil
55
+
56
+ expect{ viewer.channel }.to raise_error NetworkExecutive::ChannelNotFoundError
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '#stream' do
62
+ subject { viewer.stream }
63
+
64
+ it 'should be an EventSource' do
65
+ Faye::EventSource.should_receive( :new )
66
+
67
+ subject
68
+ end
69
+ end
70
+
71
+ describe '#tune_in' do
72
+ let(:channel) { double('channel').as_null_object }
73
+ let(:stream) { double('stream').as_null_object }
74
+
75
+ before do
76
+ described_class.any_instance.stub( :ip )
77
+ described_class.any_instance.stub( :stream ).and_return stream
78
+ described_class.any_instance.stub( :channel ).and_return channel
79
+ end
80
+
81
+ subject { viewer.tune_in }
82
+
83
+ it 'should subscribe to the channel' do
84
+ channel.should_receive( :subscribe )
85
+
86
+ subject
87
+ end
88
+
89
+ it 'should register an onclose handler' do
90
+ subject
91
+
92
+ stream.onclose.should_not be_nil
93
+ end
94
+ end
95
+
96
+ describe '#tune_out' do
97
+ let(:channel) { double('channel').as_null_object }
98
+ let(:beat) { double('heartbeat').as_null_object }
99
+ let(:id) { 1 }
100
+
101
+ before do
102
+ described_class.any_instance.stub( :id ).and_return id
103
+ described_class.any_instance.stub( :channel ).and_return channel
104
+ described_class.any_instance.stub( :heartbeat ).and_return beat
105
+ end
106
+
107
+ subject { viewer.tune_out( nil ) }
108
+
109
+ it 'should unsubscribe from the channel' do
110
+ channel.should_receive( :unsubscribe ).with id
111
+
112
+ subject
113
+ end
114
+
115
+ it 'should cancel the heartbeat' do
116
+ beat.should_receive :cancel
117
+
118
+ subject
119
+ end
120
+
121
+ it 'should nullify the stream' do
122
+ subject
123
+
124
+ viewer.instance_variable_get('@stream').should be_nil
125
+ end
126
+ end
127
+
128
+ describe '#response' do
129
+ let(:stream) { double('stream') }
130
+
131
+ subject { viewer.response }
132
+
133
+ before do
134
+ described_class.any_instance.stub(:stream).and_return stream
135
+ end
136
+
137
+ it 'should return a response for Rack' do
138
+ stream.should_receive :rack_response
139
+
140
+ subject
141
+ end
142
+ end
143
+
144
+ describe '#channel_name' do
145
+ before do
146
+ env['PATH_INFO'] = '/foo/bar/baz'
147
+ end
148
+
149
+ subject { viewer.channel_name }
150
+
151
+ it { should == 'baz' }
152
+ end
153
+
154
+ describe '#keep_alive!' do
155
+ let(:stream) { double('stream') }
156
+
157
+ subject { viewer.keep_alive! }
158
+
159
+ before do
160
+ described_class.any_instance.stub :ip
161
+ described_class.any_instance.stub :channel
162
+ described_class.any_instance.stub( :stream ).and_return stream
163
+
164
+ EM.stub( :add_periodic_timer ).and_yield
165
+ end
166
+
167
+ it 'should send a ping' do
168
+ stream.should_receive :ping
169
+
170
+ subject
171
+ end
172
+ end
173
+
174
+ describe '.change_channel' do
175
+ subject { described_class.change_channel env }
176
+
177
+ before do
178
+ described_class.any_instance.stub :tune_in
179
+ described_class.any_instance.stub :keep_alive!
180
+ described_class.any_instance.stub :response
181
+ end
182
+
183
+ it 'should tune in to the channel' do
184
+ viewer = double('viewer').as_null_object
185
+
186
+ described_class.should_receive( :new ).with( env ).and_return viewer
187
+
188
+ subject
189
+ end
190
+
191
+ it 'should tune in to the channel' do
192
+ described_class.any_instance.should_receive :tune_in
193
+
194
+ subject
195
+ end
196
+
197
+ it 'should keep the connection alive' do
198
+ described_class.any_instance.should_receive :keep_alive!
199
+
200
+ subject
201
+ end
202
+
203
+ it 'should return a Rack response' do
204
+ described_class.any_instance.should_receive :response
205
+
206
+ subject
207
+ end
208
+ end
209
+
210
+ end
@@ -0,0 +1,15 @@
1
+ describe NetworkExecutive do
2
+ it { should be_a Module }
3
+
4
+ its(:config) { should be_a NetworkExecutive::Configuration }
5
+
6
+ describe '.configure' do
7
+ it 'should yield the config Hash' do
8
+ config = nil
9
+
10
+ described_class.configure { |c| config = c }
11
+
12
+ config.should eq described_class.config
13
+ end
14
+ end
15
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,11 +1,37 @@
1
- ENV['RACK_ENV'] ||= 'test'
1
+ ENV['RACK_ENV'] ||= 'test'
2
+ ENV['RAILS_ENV'] ||= 'test'
2
3
 
3
4
  require 'rubygems'
4
5
  require 'bundler/setup'
6
+
5
7
  require 'awesome_print'
6
8
 
9
+ require File.expand_path( '../dummy/config/environment.rb', __FILE__ )
10
+
11
+ require 'rails/test_help'
12
+ require 'rspec/rails'
13
+ require 'fakefs/spec_helpers'
14
+ require 'timecop'
15
+
16
+ Rails.backtrace_cleaner.remove_silencers!
17
+
7
18
  RSpec.configure do |config|
8
19
  config.treat_symbols_as_metadata_keys_with_true_values = true
9
20
  config.filter_run focus: true
10
21
  config.run_all_when_everything_filtered = true
22
+
23
+ # Because of the use of Rack::Static, we need to initialize the
24
+ # fake filesystem before NetworkExecutive is loaded.
25
+ config.before do
26
+ FakeFS.activate!
27
+ end
28
+
29
+ config.after do
30
+ FakeFS.deactivate!
31
+
32
+ Timecop.return
33
+
34
+ NetworkExecutive::Network.channels.clear
35
+ NetworkExecutive::Network.programming.clear
36
+ end
11
37
  end
@@ -0,0 +1,3 @@
1
+ describe NetworkExecutive::Configuration do
2
+ it { should respond_to :name }
3
+ end
@@ -0,0 +1,60 @@
1
+ describe NetworkExecutive::Producer do
2
+
3
+ describe '.run!' do
4
+ subject { described_class.run! }
5
+
6
+ before do
7
+ EM.stub :add_timer
8
+ end
9
+
10
+ it 'should immediately run any scheduled programming' do
11
+ described_class.should_receive :run_scheduled_programming
12
+
13
+ subject
14
+ end
15
+
16
+ it 'should wait for the next 1-minute interval' do
17
+ Timecop.freeze Time.now.change( sec:59 )
18
+
19
+ EM.should_receive( :add_timer ).with 1
20
+
21
+ subject
22
+ end
23
+
24
+ it 'should run scheduled programming every minute' do
25
+ EM.stub( :add_timer ).and_yield
26
+
27
+ EM.should_receive( :add_periodic_timer ).with 60
28
+
29
+ subject
30
+ end
31
+
32
+ it 'should run any scheduled programming at intervals' do
33
+ described_class.should_receive( :run_scheduled_programming ).exactly(3).times
34
+
35
+ EM.stub( :add_timer ).and_yield
36
+ EM.stub( :add_periodic_timer ).and_yield
37
+
38
+ subject
39
+ end
40
+ end
41
+
42
+ describe '.run_scheduled_programming' do
43
+ let(:scheduled) { double('channel', whats_on?: true) }
44
+ let(:unscheduled) { double('channel', whats_on?: nil) }
45
+
46
+ before do
47
+ NetworkExecutive::Network.stub(:channels).and_return [ scheduled, unscheduled ]
48
+ end
49
+
50
+ subject { described_class.run_scheduled_programming }
51
+
52
+ it 'should show all scheduled programming' do
53
+ scheduled.should_receive :show
54
+ unscheduled.should_receive( :show ).never
55
+
56
+ subject
57
+ end
58
+ end
59
+
60
+ end
@@ -0,0 +1,106 @@
1
+ describe NetworkExecutive::Scheduling do
2
+
3
+ describe '.every' do
4
+ it 'should schedule the program' do
5
+ channel = Class.new( NetworkExecutive::Channel ) do
6
+ include NetworkExecutive::Scheduling
7
+
8
+ every :day, play:'my_show'
9
+ end
10
+
11
+ channel.schedule.first.should be_a NetworkExecutive::ProgramSchedule
12
+ end
13
+ end
14
+
15
+ describe 'schedule' do
16
+ it 'should be a ChannelSchedule' do
17
+ channel = Class.new( NetworkExecutive::Channel ) do
18
+ include NetworkExecutive::Scheduling
19
+ end
20
+
21
+ channel.schedule.should be_a NetworkExecutive::ChannelSchedule
22
+ end
23
+ end
24
+
25
+ describe '#whats_on?' do
26
+ let(:channel) do
27
+ Class.new( NetworkExecutive::Channel ) do
28
+ include NetworkExecutive::Scheduling
29
+ end
30
+ end
31
+
32
+ context 'with nothing scheduled' do
33
+ it 'should return nil' do
34
+ channel.new.whats_on?.should be_nil
35
+ end
36
+ end
37
+
38
+ it 'should return the most appropriate program for a given time' do
39
+ program_c = double('program c', include?: true)
40
+
41
+ channel.schedule.add double('program a', include?: false)
42
+ channel.schedule.add double('program b', include?: true)
43
+ channel.schedule.add program_c
44
+ channel.schedule.add double('program d', include?: false)
45
+
46
+ channel.new.whats_on?.should == program_c
47
+ end
48
+
49
+ it 'should return all programs scheduled for a range of times' do
50
+ program_b = double 'program b'
51
+ program_b.stub(:include?).and_return true, false
52
+
53
+ program_c = double 'program c'
54
+ program_c.stub(:include?).and_return false, true
55
+
56
+ channel.schedule.add double('program a', include?: false)
57
+ channel.schedule.add program_b
58
+ channel.schedule.add program_c
59
+ channel.schedule.add double('program d', include?: false)
60
+
61
+ shows = channel.new.whats_on?( 1.hour.ago, 1.hour.from_now )
62
+
63
+ shows.first[:program].should be program_b
64
+ shows.last[:program].should be program_c
65
+ end
66
+
67
+ it 'should yield a block when provided a stop_time' do
68
+ program_a = double('program a', include?: true)
69
+ channel.schedule.add program_a
70
+
71
+ channel.new.whats_on?( 1.hour.ago, 1.hour.from_now) do |program|
72
+ program.should be program_a
73
+ end
74
+ end
75
+ end
76
+
77
+ describe '#with_showtimes_between' do
78
+ let(:klass) do
79
+ Class.new( NetworkExecutive::Channel ) do
80
+ include NetworkExecutive::Scheduling
81
+
82
+ every :day, play:'my_show'
83
+ end
84
+ end
85
+
86
+ let(:channel) { klass.new }
87
+
88
+ subject do
89
+ program_a = double 'program_a', include?: true
90
+
91
+ channel.schedule.add program_a
92
+
93
+ range = [ 1.hour.ago, 1.hour.from_now ]
94
+
95
+ channel.with_showtimes_between( *range ) do |showtime, program|
96
+ 'block retval'
97
+ end
98
+ end
99
+
100
+ it 'should contain the blocks return value' do
101
+ subject.all?{ |x| x == 'block retval' }.should be_true
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -0,0 +1,41 @@
1
+ describe NetworkExecutive::Station::LocalAffiliate do
2
+ describe '#initialize' do
3
+ it 'should run the Producer on the next tick' do
4
+ EM.stub( :next_tick ).and_yield
5
+
6
+ NetworkExecutive::Producer.should_receive( :run! )
7
+
8
+ described_class.new
9
+ end
10
+ end
11
+
12
+ describe '#call' do
13
+ before { EM.stub( :next_tick ) }
14
+
15
+ let(:env) { double('env').as_null_object }
16
+
17
+ subject { described_class.new.call( env ) }
18
+
19
+ context 'with a request that accepts event streams' do
20
+ before do
21
+ Faye::EventSource.stub( :eventsource? ).and_return true
22
+ end
23
+
24
+ it 'should change the channel for the Viewer' do
25
+ NetworkExecutive::Viewer.should_receive( :change_channel ).with env
26
+
27
+ subject
28
+ end
29
+ end
30
+
31
+ context 'with a request that does not accept event streams' do
32
+ before do
33
+ Faye::EventSource.stub( :eventsource? ).and_return false
34
+ end
35
+
36
+ it 'should return a 403' do
37
+ subject.first.should == 403
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :network_executive do
3
+ # # Task goes here
4
+ # end