spectate 0.0.0

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.
@@ -0,0 +1,23 @@
1
+ require 'cgi'
2
+
3
+ module Spectate
4
+ # A convenience module to provide URI-safe versions of spectator names. It essentially
5
+ # just uses URI::Escape on the strings, but with the additional conversion of spaces to
6
+ # underscores (and underscores to double underscores) because having lots of '%20' blobs
7
+ # in a URL is painful on the eyes.
8
+ module Encode
9
+ # Makes a name URI-safe, with the minor cosmetic tweak of underscoring spaces.
10
+ def encode(name)
11
+ name.gsub!(/_/,'__')
12
+ name.tr!(' ','_')
13
+ CGI::escape(name)
14
+ end
15
+
16
+ # Turns a URI-safe name generated by 'encode' back into a reasonable string.
17
+ def decode(name)
18
+ name.gsub!(/_(?!_)/,' ')
19
+ name.gsub!(/_ /,'_')
20
+ CGI::unescape(name)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ module Spectate
2
+ module Ping
3
+ def ping
4
+ c = Spectate::Client.new
5
+ c.get
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+ require 'sinatra/base'
3
+ require 'rufus-tokyo'
4
+ require 'json'
5
+
6
+ module Spectate
7
+ class Server < Sinatra::Base
8
+
9
+ def initialize
10
+ Spectate::Config.load_configuration
11
+ Rufus::Tokyo::Cabinet.open(File.join(Spectate::Config.basedir, 'spectate.tcb'), :opts => 'b') do |db|
12
+ nil
13
+ end
14
+ super
15
+ end
16
+
17
+ get '/' do
18
+ {:summary => "Spectate v#{VERSION}"}.to_json
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,43 @@
1
+ module Spectate
2
+ class Status
3
+ include Encode
4
+ attr_reader :server, :source
5
+ def initialize(server, source, properties = {})
6
+ @server, @source = server, source
7
+ @status = properties.inject({}) do |status, (key, value)| # Shamelessly lifted from ActiveSupport
8
+ status[(key.to_sym rescue key) || key] = value
9
+ status
10
+ end
11
+ end
12
+
13
+ # An array of all the properties contained in this Status object.
14
+ def properties
15
+ @status.keys
16
+ end
17
+
18
+ # Returns the path of the spectator that owns this source. In practical
19
+ # terms, this simply truncates to the next-to-last element on the path; so
20
+ # if the source is '/examples/foo/re_bar' the parent would be
21
+ # '/examples/foo'.
22
+ def parent
23
+ @source.slice %r{^/.*(?=/)}
24
+ end
25
+
26
+ # The English representation of the name of the spectator belonging to this source.
27
+ def name
28
+ decode @source.slice(%r{/[^/]+$}).delete('/') # Ruby 1.8 doesn't support lookbehind
29
+ end
30
+
31
+ def [](key)
32
+ @status[key]
33
+ end
34
+
35
+ def method_missing(method, *args, &block)
36
+ if @status.has_key?(method)
37
+ @status[method]
38
+ else
39
+ super
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,150 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'spectate/client'
3
+
4
+ describe Spectate::Client do
5
+ include Spectate::Spec::ServerHelpers
6
+
7
+ before(:all) do
8
+ start_server
9
+ end
10
+ describe "configuration" do
11
+ it "loads configuration if it has to" do
12
+ Spectate::Config.clear!
13
+ Spectate::Config.expects(:load_configuration).returns(true)
14
+ @this = Spectate::Client.new
15
+ end
16
+
17
+ it "doesn't reload the configuration if it doesn't have to" do
18
+ Spectate::Config.expects(:load_configuration).never
19
+ Spectate::Config.expects(:loaded?).returns(true)
20
+ @this = Spectate::Client.new
21
+ end
22
+
23
+ it "knows its host" do
24
+ @this = Spectate::Client.new
25
+ @this.host.should == 'localhost'
26
+ end
27
+
28
+ it "can override its host on creation" do
29
+ @this = Spectate::Client.new(:host => 'example.com')
30
+ @this.host.should == 'example.com'
31
+ end
32
+
33
+ it "can override its host at any time" do
34
+ @this = Spectate::Client.new
35
+ @this.host = 'example.org'
36
+ @this.host.should == 'example.org'
37
+ end
38
+
39
+ it "knows its port" do
40
+ @this = Spectate::Client.new
41
+ @this.port.should == 47502
42
+ end
43
+
44
+ it "can override its port on creation" do
45
+ @this = Spectate::Client.new(:port => 8888)
46
+ @this.port.should == 8888
47
+ end
48
+
49
+ it "can override its port at any time" do
50
+ @this = Spectate::Client.new
51
+ @this.port = 9999
52
+ @this.port.should == 9999
53
+ end
54
+
55
+ it "knows its protocol" do
56
+ @this = Spectate::Client.new
57
+ @this.protocol.should == 'http'
58
+ end
59
+
60
+ it "can override its protocol on creation" do
61
+ @this = Spectate::Client.new(:protocol => 'https')
62
+ @this.protocol.should == 'https'
63
+ end
64
+
65
+ it "can override its protocol at any time" do
66
+ @this = Spectate::Client.new
67
+ @this.protocol = 'ftp'
68
+ @this.protocol.should == 'ftp'
69
+ end
70
+
71
+ it "defaults to accepting JSON" do
72
+ @this = Spectate::Client.new
73
+ @this.accept.should == 'application/json'
74
+ end
75
+
76
+ it "can override its accept on creation" do
77
+ @this = Spectate::Client.new(:accept => 'text/html')
78
+ @this.accept.should == 'text/html'
79
+ end
80
+
81
+ it "can override its accept at any time" do
82
+ @this = Spectate::Client.new
83
+ @this.accept = 'application/xml'
84
+ @this.accept.should == 'application/xml'
85
+ end
86
+
87
+ it "knows its root with a port" do
88
+ @this = Spectate::Client.new(:protocol => 'https', :host => 'example.org', :port => 777)
89
+ @this.root.should == 'https://example.org:777'
90
+ end
91
+
92
+ it "knows its root without a port or protocol" do
93
+ @this = Spectate::Client.new(:host => '10.0.1.5', :port => 0)
94
+ @this.root.should == 'http://10.0.1.5'
95
+ end
96
+
97
+ end
98
+
99
+ shared_examples_for "a Rest-Client proxy method" do
100
+ STATUS_JSON = '{"uptime":"23h 14m 11s","summary":"Spectate v0.0.0.0"}'
101
+ before(:each) do
102
+ method = @method
103
+ @dummy = stub('Rest Client') do
104
+ stubs(method).returns(STATUS_JSON)
105
+ stubs(:[]).returns(@dummy)
106
+ end
107
+ @this.instance_variable_set(:@driver, @dummy)
108
+ end
109
+ it "calls the method in the RestClient resource" do
110
+ @dummy.expects(@method).returns(STATUS_JSON)
111
+ @this.send(@method).should_not be_nil
112
+ end
113
+ it "parses the result when accepting JSON" do
114
+ @this.send(@method).should be_a_kind_of(Spectate::Status)
115
+ end
116
+ it "includes the appropriate fields" do
117
+ s = @this.send(@method)
118
+ s[:summary].should =~ /Spectate/
119
+ end
120
+ it "returns nil on a Resource Not Found error" do
121
+ @dummy.expects(@method).raises(RestClient::ResourceNotFound)
122
+ @this.send(@method).should be_nil
123
+ end
124
+ it "returns nil on a Connection Refused error" do
125
+ @dummy.expects(@method).raises(Errno::ECONNREFUSED)
126
+ @this.send(@method).should be_nil
127
+ end
128
+ it "raises any other exception" do
129
+ @dummy.expects(@method).raises(RestClient::RequestFailed)
130
+ lambda{@this.send(@method)}.should raise_error(RestClient::RequestFailed)
131
+ end
132
+ end
133
+
134
+ describe 'calling method' do
135
+ before(:each) do
136
+ @this = Spectate::Client.new
137
+ end
138
+
139
+ describe "get" do
140
+ before(:each) do
141
+ @method = :get
142
+ end
143
+ it_should_behave_like "a Rest-Client proxy method"
144
+ end
145
+ end
146
+
147
+ after(:all) do
148
+ stop_server
149
+ end
150
+ end
@@ -0,0 +1,86 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Command 'spectate'" do
4
+ include Spectate::Spec::ConfigHelpers
5
+
6
+ before(:all) do
7
+ create_config
8
+ end
9
+
10
+ it "gets its base directory from the SPECTATE_DIR environment variable if specified" do
11
+ unmade_dir = File.expand_path("~/blahhhhh")
12
+ ENV['SPECTATE_DIR'] = unmade_dir
13
+ `spectate`.should =~ /Directory #{Regexp.escape(unmade_dir)} not found!/
14
+ ENV['SPECTATE_DIR'] = @tempdir
15
+ end
16
+
17
+ it "executes" do
18
+ `spectate --help`.should =~ /Spectate/i
19
+ end
20
+
21
+ # We have several options for displaying help
22
+ %w{-h -? --help --usage}.each do |option|
23
+ it "displays its usage when called with #{option}" do
24
+ `spectate #{option}`.should =~ /Usage:/
25
+ end
26
+
27
+ it "does not attempt to start the server if called with #{option}" do
28
+ `spectate #{option}`.should_not =~ /Starting Spectate/
29
+ end
30
+
31
+ end
32
+
33
+ it "displays its usage when given parameters it doesn't understand" do
34
+ `spectate --blah1234`.should =~ /invalid option: --blah1234.*Usage:/m
35
+ end
36
+
37
+
38
+ %w{-d --directory}.each do |option|
39
+ it "requires a directory parameter" do
40
+ `spectate #{option}`.should =~ /missing argument: #{option}.*Usage:/m
41
+ end
42
+
43
+ it "sets a different base directory when called with #{option} dirname" do
44
+ tmpdir = Dir.mktmpdir
45
+ `spectate #{option} #{tmpdir}`.should =~ /Directory set to #{Regexp.escape(tmpdir)}/
46
+ # Ensure cleanup
47
+ FileUtils.rm_r tmpdir, :force => true, :secure => true
48
+ end
49
+ end
50
+
51
+ describe "starting" do
52
+ it "attempts to start Spectate if not already running" do
53
+ `spectate`.should =~ /Starting Spectate/
54
+ end
55
+ it "complains if Spectate is already running" do
56
+ `spectate`
57
+ `spectate`.should =~ /already running/
58
+ end
59
+
60
+ it "creates a PID file in the base directory" do
61
+ `spectate`
62
+ File.exists?(File.join(@tempdir,'spectate.pid')).should be_true
63
+ end
64
+ after(:each) do
65
+ `spectate --stop`
66
+ end
67
+ end
68
+
69
+ describe "--stop" do
70
+ before(:each) do
71
+ `spectate`
72
+ end
73
+ it "stops the server" do
74
+ `spectate --stop`.should =~ /stopped./
75
+ end
76
+ it "complains if the server wasn't running" do
77
+ `spectate --stop`
78
+ `spectate --stop`.should =~ /wasn't running!/
79
+ end
80
+ end
81
+
82
+
83
+ after(:all) do
84
+ remove_config
85
+ end
86
+ end
@@ -0,0 +1,247 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Configuration" do
4
+ describe "version" do
5
+ it "is a proper major.minor.build number" do
6
+ Spectate::VERSION.should =~ /\d+\.\d+\.\d+/
7
+ end
8
+ end
9
+
10
+ describe "variables" do
11
+ it "can be set" do
12
+ Spectate::Config['foo'] = 'bar'
13
+ Spectate::Config['foo'].should == 'bar'
14
+ Spectate::Config.delete('foo')
15
+ end
16
+
17
+ it "can be displayed as a hash" do
18
+ Spectate::Config['bar'] = 'foo'
19
+ hash = Spectate::Config.to_hash
20
+ hash['bar'].should == 'foo'
21
+ Spectate::Config.delete('bar')
22
+ end
23
+
24
+ it "can be deleted" do
25
+ Spectate::Config['foo'] = 'bar'
26
+ Spectate::Config.delete('foo')
27
+ Spectate::Config.to_hash.should_not have_key('foo')
28
+ end
29
+
30
+ it "can be cleared" do
31
+ Spectate::Config['something'] = 'something else'
32
+ Spectate::Config.clear!
33
+ Spectate::Config.to_hash.size.should == 0
34
+ end
35
+ end
36
+
37
+ describe "defaults" do
38
+ before(:each) do
39
+ @defhash = {'aloha' => 'hello'}
40
+ end
41
+
42
+ it "will merge in if they don't exist" do
43
+ Spectate::Config.default(@defhash)
44
+ Spectate::Config['aloha'].should == 'hello'
45
+ end
46
+
47
+ it "will not merge in if they do exist" do
48
+ Spectate::Config['aloha'] = "goodbye"
49
+ Spectate::Config.default(@defhash)
50
+ Spectate::Config['aloha'].should == 'goodbye'
51
+ end
52
+
53
+ after(:each) do
54
+ Spectate::Config.delete('aloha')
55
+ end
56
+ end
57
+
58
+ describe "file setup" do
59
+ include Spectate::Spec::ConfigHelpers
60
+
61
+ # We don't want to mess up anyone's actual configuration
62
+ before(:all) do
63
+ set_tempdir # Sets @tempparent, @tempdir, @configfile
64
+ end
65
+
66
+ describe "without a .spectate directory" do
67
+ before(:each) do
68
+ FileUtils.rm_r @tempdir, :force => true, :secure => true
69
+ end
70
+
71
+ it "tells the user to run spectate --setup" do
72
+ `spectate -d #{@tempdir}`.should =~ /Directory #{Regexp.escape(@tempdir)} not found!\nRun spectate --setup to initialize things\./m
73
+ end
74
+ end
75
+
76
+ describe "without a config.yml file" do
77
+ before(:each) do
78
+ FileUtils.mkdir @tempdir
79
+ File.delete(@configfile) if File.exists?(@configfile)
80
+ end
81
+
82
+ it "tells the user to run spectate --setup" do
83
+ `spectate -d #{@tempdir}`.should =~ /File #{Regexp.escape(@tempdir)}\/config\.yml not found!\nRun spectate --setup to initialize things\./m
84
+ end
85
+ end
86
+
87
+
88
+ shared_examples_for "a valid setup option" do
89
+ it "complains if config.yml already exists" do
90
+ FileUtils.mkdir @tempdir
91
+ FileUtils.touch @configfile
92
+ `spectate -d #{@tempdir} --setup #{@option}`.should =~ /You already have a config\.yml file! We don't want to mess with a good thing\.\nIf you really want to start over, delete #{Regexp.escape(@tempdir)}\/config\.yml and run spectate --setup again\./m
93
+
94
+ end
95
+
96
+ it "tells the user a config.yml file is being made" do
97
+ `spectate -d #{@tempdir} --setup #{@option}`.should =~ /Creating config.yml file/
98
+ end
99
+
100
+ it "creates the file" do
101
+ `spectate -d #{@tempdir} --setup #{@option}`
102
+ File.exists?(@configfile).should be_true
103
+ end
104
+
105
+ it "writes the server value to the file" do
106
+ `spectate -d #{@tempdir} --setup #{@option}`
107
+ File.read(@configfile).should =~ /server: #{@option}/
108
+ end
109
+
110
+ it "writes the host if given" do
111
+ `spectate -d #{@tempdir} -h foo.bar.local --setup #{@option}`
112
+ File.read(@configfile).should =~ /host: foo\.bar\.local/
113
+ end
114
+
115
+ it "writes the port if given" do
116
+ `spectate -d #{@tempdir} -p 55555 --setup #{@option}`
117
+ File.read(@configfile).should =~ /port: 55555/
118
+ end
119
+
120
+ it "creates a rackup file" do
121
+ `spectate -d #{@tempdir} --setup #{@option}`
122
+ File.read(File.join(@tempdir,'config.ru')).should =~ /run Spectate::Server/
123
+ end
124
+ end
125
+
126
+ describe "with spectate --setup" do
127
+
128
+ describe "(no parameters)" do
129
+ it "tells the user to specify a parameter" do
130
+ `spectate -d #{@tempdir} --setup`.should =~ /missing argument/
131
+ end
132
+ end
133
+
134
+ describe "passenger" do
135
+ before(:each) do
136
+ @option = "passenger"
137
+ end
138
+ it_should_behave_like "a valid setup option"
139
+
140
+ it "sets rackup to false" do
141
+ `spectate -d #{@tempdir} --setup #{@option}`
142
+ File.read(@configfile).should =~ /rackup: false/
143
+ end
144
+
145
+ it "doesn't set a port" do
146
+ `spectate -d #{@tempdir} --setup #{@option}`
147
+ File.read(@configfile).should_not =~ /port/
148
+ end
149
+
150
+ it "defaults the host to spectate.local" do
151
+ `spectate -d #{@tempdir} --setup #{@option}`
152
+ File.read(@configfile).should =~ /host: spectate\.local/
153
+ end
154
+ end
155
+
156
+ %w[thin webrick mongrel].each do |server|
157
+ describe "#{server}" do
158
+ before(:each) do
159
+ @option = "#{server}"
160
+ end
161
+
162
+ it_should_behave_like "a valid setup option"
163
+
164
+ it "sets rackup to true" do
165
+ `spectate -d #{@tempdir} --setup #{@option}`
166
+ File.read(@configfile).should =~ /rackup: true/
167
+ end
168
+
169
+ it "sets the port to the default of 20574" do
170
+ `spectate -d #{@tempdir} --setup #{@option}`
171
+ File.read(@configfile).should =~ /port: 20574/
172
+ end
173
+
174
+ it "defaults the host to localhost" do
175
+ `spectate -d #{@tempdir} --setup #{@option}`
176
+ File.read(@configfile).should =~ /host: localhost/
177
+ end
178
+ end
179
+ end
180
+ after(:each) do
181
+ FileUtils.rm_r @tempdir, :force => true, :secure => true
182
+ end
183
+ end
184
+
185
+
186
+ after(:all) do
187
+ FileUtils.rm_r @tempparent, :force => true, :secure => true
188
+ end
189
+ end
190
+
191
+ describe "loading" do
192
+ include Spectate::Spec::ConfigHelpers
193
+ before(:each) do
194
+ Spectate::Config.clear!
195
+ create_config
196
+ ENV["SPECTATE_DIR"] = nil
197
+ end
198
+
199
+ it "gets its values from the environment variable if set" do
200
+ ENV["SPECTATE_DIR"] = @tempdir
201
+ Spectate::Config.load_configuration
202
+ Spectate::Config['port'].should == 47502
203
+ end
204
+
205
+ it "gets its values from the method parameter if given" do
206
+ Spectate::Config.load_configuration(@tempdir)
207
+ Spectate::Config['port'].should == 47502
208
+ end
209
+
210
+ it "gets its values from Spectate::Config['basedir'] if given" do
211
+ Spectate::Config['basedir'] = @tempdir
212
+ Spectate::Config.load_configuration
213
+ Spectate::Config['port'].should == 47502
214
+ end
215
+
216
+ it "gets its values from ROOT_DIR as a last resort" do
217
+ Spectate.send(:remove_const, :ROOT_DIR) # To suppress warnings
218
+ Spectate.const_set(:ROOT_DIR,@tempdir)
219
+ Spectate::Config.load_configuration
220
+ Spectate::Config['port'].should == 47502
221
+ Spectate.send(:remove_const, :ROOT_DIR) # To suppress warnings
222
+ Spectate.const_set(:ROOT_DIR,nil)
223
+ end
224
+
225
+ it "complains if no base directory can be found" do
226
+ lambda{Spectate::Config.load_configuration}.should raise_error(RuntimeError, /could not find/i)
227
+ end
228
+
229
+ it "knows when it hasn't been loaded yet" do
230
+ Spectate::Config.loaded?.should be_false
231
+ end
232
+
233
+ it "knows when it has been loaded" do
234
+ Spectate::Config.load_configuration(@tempdir)
235
+ Spectate::Config.loaded?.should be_true
236
+ end
237
+
238
+ it "knows its basedir" do
239
+ Spectate::Config.load_configuration(@tempdir)
240
+ Spectate::Config.basedir.should == @tempdir
241
+ end
242
+
243
+ after(:each) do
244
+ remove_config
245
+ end
246
+ end
247
+ end