noah 0.0.9 → 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +1 -6
- data/TODO.md +15 -9
- data/bin/noah-watcher.rb +18 -10
- data/lib/noah/app.rb +1 -1
- data/lib/noah/application_routes.rb +1 -1
- data/lib/noah/configuration_routes.rb +1 -1
- data/lib/noah/ephemeral_routes.rb +35 -6
- data/lib/noah/helpers.rb +25 -0
- data/lib/noah/host_routes.rb +1 -1
- data/lib/noah/models/ephemerals.rb +21 -2
- data/lib/noah/models/watchers.rb +9 -1
- data/lib/noah/service_routes.rb +1 -1
- data/lib/noah/version.rb +1 -1
- data/lib/noah/watcher_routes.rb +34 -1
- data/noah.gemspec +1 -0
- data/spec/configuration_spec.rb +7 -10
- data/spec/ephemeral_spec.rb +20 -13
- data/spec/noahapp_configuration_spec.rb +2 -2
- data/spec/noahapp_ephemeral_spec.rb +115 -0
- data/spec/noahapp_host_spec.rb +1 -1
- data/spec/noahapp_service_spec.rb +1 -1
- data/spec/noahapp_watcher_spec.rb +89 -0
- data/spec/watcher_spec.rb +5 -5
- metadata +4 -4
- data/lib/vendor/em-hiredis/em-hiredis-0.0.1.gem +0 -0
data/Rakefile
CHANGED
@@ -13,28 +13,24 @@ end
|
|
13
13
|
|
14
14
|
|
15
15
|
task :default => :run
|
16
|
-
task :test =>
|
16
|
+
task :test => :run
|
17
17
|
|
18
18
|
desc "Run tests and manage server start/stop"
|
19
19
|
task :run => [:start, :spec, :stop]
|
20
20
|
|
21
|
-
desc "Start the Redis server"
|
22
21
|
task :start do
|
23
22
|
puts "Starting redis-server"
|
24
23
|
system "redis-server #{REDIS_CNF}"
|
25
24
|
end
|
26
25
|
|
27
|
-
desc "Stop the Redis server"
|
28
26
|
task :stop do
|
29
27
|
puts "Killing redis"
|
30
28
|
system "killall -TERM redis-server"
|
31
29
|
end
|
32
30
|
|
33
31
|
namespace :coverage do
|
34
|
-
desc "Delete aggregate coverage data."
|
35
32
|
task(:clean) { rm_f "coverage.data" }
|
36
33
|
end
|
37
|
-
desc "Run Rcov code coverage analysis"
|
38
34
|
RSpec::Core::RakeTask.new(:coverage) do |t|
|
39
35
|
t.rcov = true
|
40
36
|
t.verbose = true
|
@@ -128,7 +124,6 @@ rescue LoadError
|
|
128
124
|
"You need YARD installed to generate docs"
|
129
125
|
end
|
130
126
|
|
131
|
-
desc "Demo environment"
|
132
127
|
task :start_demo do
|
133
128
|
puts "Soon, young padawan"
|
134
129
|
end
|
data/TODO.md
CHANGED
@@ -1,4 +1,12 @@
|
|
1
1
|
# Brain dump of stuff
|
2
|
+
* Fix JRuby
|
3
|
+
|
4
|
+
This is an ongoing issue for me. I can't rely on stuff that's MRI only.
|
5
|
+
|
6
|
+
* Break agent into separate gem
|
7
|
+
|
8
|
+
Again so that the server gem can be as lean as possible
|
9
|
+
|
2
10
|
* Documentation
|
3
11
|
|
4
12
|
Need to finish documenting everything for YARD to pick up.
|
@@ -13,15 +21,18 @@
|
|
13
21
|
|
14
22
|
* Watchers
|
15
23
|
|
16
|
-
|
24
|
+
**IN PROGRESS**
|
25
|
+
Need to resolve some issues around pathing for Configuration and Service nodes however watch registration and listing are up.
|
26
|
+
Need to address alternative watcher URIs. Webhook is the only one supported right now.
|
17
27
|
|
18
28
|
* Ephemeral nodes
|
19
29
|
|
20
|
-
|
30
|
+
**IN PROGRESS**
|
31
|
+
implement lifetime support
|
21
32
|
|
22
33
|
* Examples
|
23
34
|
|
24
|
-
I
|
35
|
+
Pretty happy with the examples I have but I need more. Want some in other languages - Python, Java, whatever!
|
25
36
|
|
26
37
|
* Clean up deps
|
27
38
|
|
@@ -35,9 +46,6 @@
|
|
35
46
|
* Github pages
|
36
47
|
- see [[http://lusis.github.com/Noah/]]
|
37
48
|
|
38
|
-
* Bundle a war
|
39
|
-
- see [[https://github.com/downloads/lusis/Noah/noah.war]]
|
40
|
-
|
41
49
|
* Examples
|
42
50
|
- Sort of done. Demo app is up! [[http://noah-demo.heroku.com/]]. Also see `examples` directory.
|
43
51
|
|
@@ -48,12 +56,10 @@
|
|
48
56
|
- Done.
|
49
57
|
|
50
58
|
* Watchers
|
51
|
-
-
|
59
|
+
- Done. GET PUT DELETE are all available at the '/w/' endpoint now!
|
52
60
|
|
53
61
|
|
54
62
|
## Watcher specific stuff
|
55
|
-
* Implement a watcher endpoint
|
56
|
-
* Implement webhooks
|
57
63
|
* Implement AMQP
|
58
64
|
* Implement REST
|
59
65
|
* Implement JMX on JRuby
|
data/bin/noah-watcher.rb
CHANGED
@@ -1,15 +1,22 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
require '
|
9
|
-
require '
|
10
|
-
require '
|
11
|
-
require '
|
12
|
-
require '
|
3
|
+
HELP = <<-EOH
|
4
|
+
Unfortunately, the agent script has some difficult requirements right now.
|
5
|
+
Please see https://github.com/lusis/Noah/Watcher-Agent for details.
|
6
|
+
EOH
|
7
|
+
begin
|
8
|
+
require 'rubygems'
|
9
|
+
require 'logger'
|
10
|
+
require 'optparse'
|
11
|
+
require 'em-hiredis'
|
12
|
+
require 'eventmachine'
|
13
|
+
require 'em-http-request'
|
14
|
+
require 'noah'
|
15
|
+
require 'json'
|
16
|
+
rescue LoadError
|
17
|
+
puts HELP
|
18
|
+
exit
|
19
|
+
end
|
13
20
|
|
14
21
|
LOGGER = Logger.new(STDOUT)
|
15
22
|
|
@@ -73,6 +80,7 @@ end
|
|
73
80
|
|
74
81
|
EventMachine.run do
|
75
82
|
logger = LOGGER
|
83
|
+
trap("INT") { logger.debug("Shutting down. Watches will not be fired");EM.stop }
|
76
84
|
noah = EventMachine::NoahAgent.new
|
77
85
|
# Passing messages...like a boss
|
78
86
|
master_channel = EventMachine::Channel.new
|
data/lib/noah/app.rb
CHANGED
@@ -63,7 +63,7 @@ module Noah
|
|
63
63
|
load File.join(File.dirname(__FILE__), 'application_routes.rb')
|
64
64
|
load File.join(File.dirname(__FILE__), 'configuration_routes.rb')
|
65
65
|
load File.join(File.dirname(__FILE__), 'watcher_routes.rb')
|
66
|
-
|
66
|
+
load File.join(File.dirname(__FILE__), 'ephemeral_routes.rb')
|
67
67
|
|
68
68
|
end
|
69
69
|
end
|
@@ -59,7 +59,7 @@ class Noah::App
|
|
59
59
|
r = {"result" => "success","id" => "#{config.id}", "action" => action, "dependencies" => dependency_action, "application" => app.name, "item" => config.name}
|
60
60
|
r.to_json
|
61
61
|
else
|
62
|
-
raise "#{config
|
62
|
+
raise "#{format_errors(config)}"
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -1,19 +1,48 @@
|
|
1
1
|
class Noah::App
|
2
|
-
|
2
|
+
get '/e/?' do
|
3
|
+
halt 404
|
4
|
+
end
|
5
|
+
|
3
6
|
get '/e/*' do
|
4
|
-
|
5
|
-
|
7
|
+
params["splat"].size == 0 ? (halt 404) : (e=Noah::Ephemeral.find(:path => "/#{params["splat"][0]}").first)
|
8
|
+
(halt 404) if e.nil?
|
9
|
+
content_type "application/octet-stream"
|
10
|
+
e.data.nil? ? "" : "#{e.data}"
|
6
11
|
end
|
7
12
|
|
8
13
|
put '/e/*/watch' do
|
9
|
-
|
14
|
+
required_params = ["endpoint"]
|
15
|
+
data = JSON.parse(request.body.read)
|
16
|
+
(data.keys.sort == required_params.sort) ? (e = Noah::Watcher.find(:path => params[:splat][0]).first) : (raise "Missing Parameters")
|
17
|
+
e.nil? ? (halt 404) : (w = e.watch!(:endpoint => data["endpoint"]))
|
18
|
+
w.to_json
|
10
19
|
end
|
11
20
|
|
12
21
|
put '/e/*' do
|
13
|
-
|
22
|
+
raise("Data too large") if request.body.size > 512
|
23
|
+
d = request.body.read || nil
|
24
|
+
e = Noah::Ephemeral.find_or_create(:path => "/#{params[:splat][0]}")
|
25
|
+
e.data = d
|
26
|
+
if e.valid?
|
27
|
+
e.save
|
28
|
+
action = e.is_new? ? "create" : "update"
|
29
|
+
r = {"action" => action, "result" => "success", "id" => e.id, "path" => e.path, "data" => e.data}
|
30
|
+
r.to_json
|
31
|
+
else
|
32
|
+
raise "#{format_errors(e)}"
|
33
|
+
end
|
14
34
|
end
|
15
35
|
|
16
36
|
delete '/e/*' do
|
17
|
-
|
37
|
+
p = params[:splat][0]
|
38
|
+
e = Noah::Ephemeral.find(:path => "/"+p).first
|
39
|
+
if e
|
40
|
+
e.delete
|
41
|
+
r = {"result" => "success", "id" => "#{e.id}", "action" => "delete", "path" => e.name}
|
42
|
+
r.to_json
|
43
|
+
else
|
44
|
+
halt 404
|
45
|
+
end
|
18
46
|
end
|
47
|
+
|
19
48
|
end
|
data/lib/noah/helpers.rb
CHANGED
@@ -1,5 +1,30 @@
|
|
1
1
|
module Noah
|
2
2
|
module SinatraHelpers
|
3
|
+
|
4
|
+
def format_errors(model)
|
5
|
+
error_messages = model.errors.present do |e|
|
6
|
+
# Missing attributes
|
7
|
+
e.on [:name, :not_present], "Name attribute missing"
|
8
|
+
e.on [:status, :not_present], "Status attribute missing"
|
9
|
+
e.on [:format, :not_present], "Format attribute missing"
|
10
|
+
e.on [:body, :not_present], "Body attribute missing"
|
11
|
+
e.on [:application_id, :not_present], "Application attribute missing"
|
12
|
+
e.on [:path, :not_present], "Path attribute missing"
|
13
|
+
e.on [:pattern, :not_present], "Pattern attribute missing"
|
14
|
+
e.on [:endpoint, :not_present], "Endpoint attribute missing"
|
15
|
+
# Invalid option
|
16
|
+
e.on [:status, :not_member], "Status must be up, down or pending"
|
17
|
+
# Duplicate keys
|
18
|
+
e.on [[:name, :application_id], :not_unique], "Record already exists"
|
19
|
+
e.on [[:name, :host_id], :not_unique], "Record already exists"
|
20
|
+
e.on [[:endpoint, :pattern], :not_unique], "Record already exists"
|
21
|
+
e.on [:path, :not_unique], "Record already exists"
|
22
|
+
# Custom exceptions
|
23
|
+
e.on [:pattern, :already_provided], "Pattern is already provided"
|
24
|
+
e.on [:pattern, :replaces_existing], "Pattern would overwrite existing"
|
25
|
+
end
|
26
|
+
error_messages.first
|
27
|
+
end
|
3
28
|
|
4
29
|
def host(opts = {})
|
5
30
|
Noah::Host.find(opts).first
|
data/lib/noah/host_routes.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require 'digest/sha1'
|
2
1
|
module Noah
|
3
2
|
class Ephemeral < Model #NYI
|
4
3
|
|
5
4
|
attribute :path
|
6
5
|
attribute :data
|
6
|
+
attribute :lifetime
|
7
7
|
|
8
8
|
index :path
|
9
9
|
|
@@ -17,6 +17,25 @@ module Noah
|
|
17
17
|
@name = path
|
18
18
|
end
|
19
19
|
|
20
|
+
def to_hash
|
21
|
+
h = {:path => path, :data => data, :created_at => created_at, :updated_at => :updated_at}
|
22
|
+
super.merge(h)
|
23
|
+
end
|
24
|
+
|
25
|
+
class << self
|
26
|
+
def find_or_create(opts = {})
|
27
|
+
begin
|
28
|
+
find(opts).first.nil? ? (eph = create(opts)) : (eph = find(opts).first)
|
29
|
+
if eph.valid?
|
30
|
+
eph.save
|
31
|
+
end
|
32
|
+
eph
|
33
|
+
rescue Exception => e
|
34
|
+
e.message
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
20
39
|
protected
|
21
40
|
def save_hook
|
22
41
|
# called after any create,update,delete
|
@@ -27,7 +46,7 @@ module Noah
|
|
27
46
|
def path_protected?(path_part)
|
28
47
|
# Check for protected paths in ephemeral nodes
|
29
48
|
end
|
30
|
-
|
49
|
+
|
31
50
|
end
|
32
51
|
|
33
52
|
end
|
data/lib/noah/models/watchers.rb
CHANGED
@@ -7,6 +7,7 @@ module Noah
|
|
7
7
|
|
8
8
|
attribute :pattern
|
9
9
|
attribute :endpoint
|
10
|
+
attribute :name
|
10
11
|
|
11
12
|
index :pattern
|
12
13
|
index :endpoint
|
@@ -29,12 +30,19 @@ module Noah
|
|
29
30
|
super.merge(h)
|
30
31
|
end
|
31
32
|
|
32
|
-
|
33
|
+
class << self
|
34
|
+
def find_by_name(name)
|
35
|
+
pattern, endpoint = Base64.decode64(name).split('|')
|
36
|
+
find(:pattern => pattern, :endpoint => endpoint).first
|
37
|
+
end
|
38
|
+
|
39
|
+
def watch_list
|
33
40
|
arr = []
|
34
41
|
watches = self.all.sort_by(:pattern)
|
35
42
|
watches.each {|w| arr << w.name}
|
36
43
|
arr
|
37
44
|
end
|
45
|
+
end
|
38
46
|
|
39
47
|
private
|
40
48
|
# Not sure about these next two.
|
data/lib/noah/service_routes.rb
CHANGED
@@ -50,7 +50,7 @@ class Noah::App
|
|
50
50
|
r = {"action" => action, "result" => "success", "id" => service.id, "host" => h.name, "name" => service.name}
|
51
51
|
r.to_json
|
52
52
|
else
|
53
|
-
raise "#{service
|
53
|
+
raise "#{format_errors(service)}"
|
54
54
|
end
|
55
55
|
else
|
56
56
|
raise "Missing Parameters"
|
data/lib/noah/version.rb
CHANGED
data/lib/noah/watcher_routes.rb
CHANGED
@@ -1,12 +1,45 @@
|
|
1
1
|
class Noah::App
|
2
2
|
|
3
|
+
get '/w/:name' do |name|
|
4
|
+
w = Noah::Watcher.find_by_name(name)
|
5
|
+
w.nil? ? (halt 404) : w.to_json
|
6
|
+
end
|
7
|
+
|
3
8
|
get '/w/?' do
|
4
9
|
w = Noah::Watcher.all.sort_by(:pattern)
|
5
10
|
if w.size == 0
|
6
11
|
halt 404
|
7
12
|
else
|
8
13
|
w.to_json
|
9
|
-
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
put '/w/?' do
|
18
|
+
required_params = %w[endpoint pattern]
|
19
|
+
data = JSON.parse(request.body.read)
|
20
|
+
(data.keys.sort == required_params.sort) ? (pattern, endpoint = data['pattern'],data['endpoint']) : (raise "Missing Parameters")
|
21
|
+
w = Noah::Watcher.create(:pattern => pattern, :endpoint => endpoint)
|
22
|
+
if w.valid?
|
23
|
+
w.save
|
24
|
+
r = {"action" => "create", "result" => "success"}.merge(w.to_hash)
|
25
|
+
r.to_json
|
26
|
+
else
|
27
|
+
raise "#{format_errors(w)}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
delete '/w/?' do
|
32
|
+
required_params = %w[endpoint pattern]
|
33
|
+
data = JSON.parse(request.body.read)
|
34
|
+
(data.keys.sort == required_params.sort) ? (pattern, endpoint = data['pattern'],data['endpoint']) : (raise "Missing Parameters")
|
35
|
+
w = Noah::Watcher.find(:pattern => pattern, :endpoint => endpoint).first
|
36
|
+
if w.nil?
|
37
|
+
halt 404
|
38
|
+
else
|
39
|
+
w.delete
|
40
|
+
r = {"result" => "success", "action" => "delete"}.merge(w.to_hash)
|
41
|
+
r.to_json
|
42
|
+
end
|
10
43
|
end
|
11
44
|
|
12
45
|
end
|
data/noah.gemspec
CHANGED
data/spec/configuration_spec.rb
CHANGED
@@ -1,18 +1,15 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
3
|
describe "Using the Configuration Model", :reset_redis => true do
|
4
|
-
before(:all) do
|
5
|
-
app = Noah::Application.create(:name => "my_application")
|
6
|
-
app.save
|
7
|
-
@appconf_string = {:name => "mystringconf", :format => "string", :body => "some_var", :application_id => app.id}
|
8
|
-
@appconf_json = {:name => "myjsonconf", :format => "json", :body => @appconf_string.to_json, :application_id => app.id}
|
9
|
-
@appconf_missing_name = @appconf_string.reject {|x| x == :name}
|
10
|
-
@appconf_missing_format = @appconf_string.reject {|x| x == :format}
|
11
|
-
@appconf_missing_body = @appconf_string.reject {|x| x == :body}
|
12
|
-
@appconf_missing_application = @appconf_string.reject {|x| x == :application_id}
|
13
|
-
end
|
14
4
|
before(:each) do
|
15
5
|
Ohm.redis.flushdb
|
6
|
+
app = Noah::Application.create :name => "my_application"
|
7
|
+
@appconf_string = {:name => "mystringconf", :format => "string", :body => "some_var", :application_id => app.id}
|
8
|
+
@appconf_json = {:name => "myjsonconf", :format => "json", :body => @appconf_string.to_json, :application_id => app.id}
|
9
|
+
@appconf_missing_name = @appconf_string.reject {|k, v| k == :name}
|
10
|
+
@appconf_missing_format = @appconf_string.reject {|k, v| k == :format}
|
11
|
+
@appconf_missing_body = @appconf_string.reject {|k, v| k == :body}
|
12
|
+
@appconf_missing_application = @appconf_string.reject {|k, v| k == :application_id}
|
16
13
|
end
|
17
14
|
after(:each) do
|
18
15
|
Ohm.redis.flushdb
|
data/spec/ephemeral_spec.rb
CHANGED
@@ -3,8 +3,8 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
3
3
|
describe "Using the Ephemeral Model", :reset_redis => true do
|
4
4
|
before(:all) do
|
5
5
|
@edata = {:path => "/foo/bar/baz", :data => "some_value"}
|
6
|
-
@emissing_path = @edata.reject {|
|
7
|
-
@emissing_data = @edata.reject {|
|
6
|
+
@emissing_path = @edata.reject {|k, v| k == :path}
|
7
|
+
@emissing_data = @edata.reject {|k, v| k == :data}
|
8
8
|
@good_ephemeral = Noah::Ephemeral.new(@edata)
|
9
9
|
@missing_path = Noah::Ephemeral.new(@emissing_path)
|
10
10
|
@missing_data = Noah::Ephemeral.new(@emissing_data)
|
@@ -28,15 +28,15 @@ describe "Using the Ephemeral Model", :reset_redis => true do
|
|
28
28
|
b = Noah::Ephemeral[@missing_data.id]
|
29
29
|
b.should == @missing_data
|
30
30
|
end
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
it "update an existing Noah::Ephemeral" do
|
32
|
+
e = Noah::Ephemeral.create :path => "/is/new/test"
|
33
|
+
Noah::Ephemeral.all.size.should == 1
|
34
|
+
sleep(2)
|
35
|
+
c = Noah::Ephemeral[e.id]
|
36
|
+
c.data = "updated_data"
|
37
|
+
c.save
|
38
|
+
c.is_new?.should == false
|
39
|
+
end
|
40
40
|
it "delete an existing Noah::Ephemeral" do
|
41
41
|
@good_ephemeral.save
|
42
42
|
@good_ephemeral.delete
|
@@ -45,8 +45,15 @@ describe "Using the Ephemeral Model", :reset_redis => true do
|
|
45
45
|
end
|
46
46
|
describe "should not" do
|
47
47
|
it "create a new Noah::Ephemeral with missing path" do
|
48
|
-
|
49
|
-
|
48
|
+
e = Noah::Ephemeral.create
|
49
|
+
e.valid?.should == false
|
50
|
+
e.errors.should == [[:path, :not_present]]
|
51
|
+
end
|
52
|
+
it "create a duplicate Noah::Ephemeral" do
|
53
|
+
e = Noah::Ephemeral.create :path => "/random/path"
|
54
|
+
f = Noah::Ephemeral.create :path => "/random/path"
|
55
|
+
f.valid?.should == false
|
56
|
+
f.errors.should == [[:path, :not_unique]]
|
50
57
|
end
|
51
58
|
end
|
52
59
|
end
|
@@ -34,8 +34,8 @@ describe "Using the Configuration API", :reset_redis => false, :populate_sample_
|
|
34
34
|
response = YAML.load(last_response.body)
|
35
35
|
response.is_a?(Hash).should == true
|
36
36
|
response.keys.should == ["development"]
|
37
|
-
response["development"].keys.should == ["
|
38
|
-
response["development"].values.should == ["
|
37
|
+
response["development"].keys.sort.should == ["adapter", "database", "password", "username"]
|
38
|
+
response["development"].values.sort.should == ["dev_password", "dev_user", "development_database", "mysql"]
|
39
39
|
end
|
40
40
|
it "invalid application should not work" do
|
41
41
|
get '/c/badapp'
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Using the Ephemeral API", :reset_redis => true do
|
4
|
+
before(:each) do
|
5
|
+
Ohm.redis.flushdb
|
6
|
+
Noah::Ephemeral.create(:path => "/foo/bar/baz", :data => "value1")
|
7
|
+
Noah::Ephemeral.create(:path => "/baz/bar")
|
8
|
+
end
|
9
|
+
after(:each) do
|
10
|
+
Ohm.redis.flushdb
|
11
|
+
end
|
12
|
+
describe "calling" do
|
13
|
+
|
14
|
+
describe "GET" do
|
15
|
+
it "all ephemerals should return 404" do
|
16
|
+
get '/e'
|
17
|
+
last_response.should_not be_ok
|
18
|
+
last_response.status.should == 404
|
19
|
+
response = last_response.should return_json
|
20
|
+
response['error_message'].should == 'Resource not found'
|
21
|
+
response['result'].should == 'failure'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "named path with data should work" do
|
25
|
+
get '/e/foo/bar/baz'
|
26
|
+
last_response.should be_ok
|
27
|
+
last_response.body.should == 'value1'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "named path without data should work" do
|
31
|
+
get '/e/baz/bar'
|
32
|
+
last_response.status.should == 200
|
33
|
+
last_response.body.should == ""
|
34
|
+
end
|
35
|
+
|
36
|
+
it "invalid path should not work" do
|
37
|
+
get '/e/ssss/dddd'
|
38
|
+
last_response.should_not be_ok
|
39
|
+
last_response.status.should == 404
|
40
|
+
response = last_response.should return_json
|
41
|
+
response['error_message'].should == 'Resource not found'
|
42
|
+
response['result'].should == 'failure'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "PUT" do
|
47
|
+
it "new ephemeral with data should work" do
|
48
|
+
put '/e/whiz/bang/', 'value3'
|
49
|
+
last_response.should be_ok
|
50
|
+
response = last_response.should return_json
|
51
|
+
response['result'].should == 'success'
|
52
|
+
response['id'].nil?.should == false
|
53
|
+
response['path'].should == '/whiz/bang/'
|
54
|
+
response['data'].should == 'value3'
|
55
|
+
end
|
56
|
+
|
57
|
+
it "new ephemeral without data should work" do
|
58
|
+
put '/e/bang/whiz'
|
59
|
+
last_response.should be_ok
|
60
|
+
response = last_response.should return_json
|
61
|
+
response['result'].should == 'success'
|
62
|
+
response['action'].should == 'create'
|
63
|
+
response['id'].nil?.should == false
|
64
|
+
response['path'].should == '/bang/whiz'
|
65
|
+
response['data'].should == nil
|
66
|
+
end
|
67
|
+
|
68
|
+
it "existing ephemeral with data should work" do
|
69
|
+
Noah::Ephemeral.create(:path => '/new/ephemeral', :data => 'old_value')
|
70
|
+
get '/e/new/ephemeral'
|
71
|
+
last_response.should be_ok
|
72
|
+
last_response.body.should == 'old_value'
|
73
|
+
put '/e/new/ephemeral', 'new_value'
|
74
|
+
last_response.should be_ok
|
75
|
+
get '/e/new/ephemeral'
|
76
|
+
last_response.should be_ok
|
77
|
+
last_response.body.should == 'new_value'
|
78
|
+
end
|
79
|
+
it "existing ephemeral without data should work" do
|
80
|
+
Noah::Ephemeral.create(:path => '/a/random/key')
|
81
|
+
get '/e/a/random/key'
|
82
|
+
last_response.should be_ok
|
83
|
+
last_response.body.should == ""
|
84
|
+
put '/e/a/random/key', 'a new value'
|
85
|
+
last_response.should be_ok
|
86
|
+
get '/e/a/random/key'
|
87
|
+
last_response.should be_ok
|
88
|
+
last_response.body.should == 'a new value'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "DELETE" do
|
93
|
+
it "existing path should work" do
|
94
|
+
e = Noah::Ephemeral.new(:path => '/slart/i/bart/fast', :data => 'someddata')
|
95
|
+
e.save
|
96
|
+
delete "/e/slart/i/bart/fast"
|
97
|
+
last_response.should be_ok
|
98
|
+
response = last_response.should return_json
|
99
|
+
response['result'].should == 'success'
|
100
|
+
response['action'].should == 'delete'
|
101
|
+
response['id'].should == e.id
|
102
|
+
response['path'].should == e.name
|
103
|
+
end
|
104
|
+
|
105
|
+
it "invalid path should not work" do
|
106
|
+
delete '/e/fork/spoon/knife'
|
107
|
+
last_response.should_not be_ok
|
108
|
+
last_response.status.should == 404
|
109
|
+
response = last_response.should return_json
|
110
|
+
response['error_message'].should == 'Resource not found'
|
111
|
+
response['result'].should == 'failure'
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/spec/noahapp_host_spec.rb
CHANGED
@@ -82,7 +82,7 @@ describe "Using the Host API", :reset_redis => false, :populate_sample_data => t
|
|
82
82
|
response = last_response.should return_json
|
83
83
|
|
84
84
|
response["result"].should == "failure"
|
85
|
-
response["error_message"].should == "
|
85
|
+
response["error_message"].should == "Status must be up, down or pending"
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
@@ -68,7 +68,7 @@ describe "Using the Service API", :reset_redis => false, :populate_sample_data =
|
|
68
68
|
put "/s/foobar", {:name => "foobar", :status => "fsck", :host => @h.name}.to_json, "CONTENT_TYPE" => "application/json"
|
69
69
|
last_response.should_not be_ok
|
70
70
|
response = last_response.should return_json
|
71
|
-
response["error_message"].should == "
|
71
|
+
response["error_message"].should == "Status must be up, down or pending"
|
72
72
|
end
|
73
73
|
it "new service with missing name should not work" do
|
74
74
|
put "/s/foobar", {:status => "fsck", :host => @h.name}.to_json, "CONTENT_TYPE" => "application/json"
|
@@ -28,7 +28,96 @@ describe "Using the Watcher API", :reset_redis => true do
|
|
28
28
|
response.is_a?(Array).should == true
|
29
29
|
response.size.should == 4
|
30
30
|
end
|
31
|
+
|
32
|
+
it "named watch should work" do
|
33
|
+
w = Noah::Watcher.create(:pattern => '//noah/application/myapp', :endpoint => 'http://localhost/webhook')
|
34
|
+
get "/w/#{w.name}"
|
35
|
+
last_response.should be_ok
|
36
|
+
response = last_response.should return_json
|
37
|
+
response['pattern'].should == w.pattern
|
38
|
+
response['endpoint'].should == w.endpoint
|
39
|
+
end
|
40
|
+
|
41
|
+
it "invalid watch should not work" do
|
42
|
+
get '/w/asdfasdfasdfasdfasdfsdf'
|
43
|
+
last_response.should be_missing
|
44
|
+
end
|
31
45
|
end
|
32
46
|
|
47
|
+
describe "PUT" do
|
48
|
+
it "new watch should work" do
|
49
|
+
data = {:pattern => "//noah/application", :endpoint => "http://myendpoint/webhook"}
|
50
|
+
put '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
51
|
+
last_response.should be_ok
|
52
|
+
response = last_response.should return_json
|
53
|
+
response['pattern'].should == data[:pattern]
|
54
|
+
response['endpoint'].should == data[:endpoint]
|
55
|
+
w = Noah::Watcher.find(data).first
|
56
|
+
w.pattern.should == data[:pattern]
|
57
|
+
w.endpoint.should == data[:endpoint]
|
58
|
+
end
|
59
|
+
|
60
|
+
it "new watch without pattern should not work" do
|
61
|
+
data = {:endpoint => "http://myendpoint/webhook"}
|
62
|
+
put '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
63
|
+
last_response.should be_invalid
|
64
|
+
end
|
65
|
+
|
66
|
+
it "new watch without endpoint should not work" do
|
67
|
+
data = {:pattern => "//noah/application"}
|
68
|
+
put '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
69
|
+
last_response.should be_invalid
|
70
|
+
end
|
71
|
+
|
72
|
+
it "new watch that supercedes existing should not work" do
|
73
|
+
Noah::Watcher.create(:endpoint => 'http://myendpoint/webhook', :pattern => '//noah/application/foo')
|
74
|
+
data = {:endpoint => "http://myendpoint/webhook", :pattern => '//noah/application'}
|
75
|
+
put '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
76
|
+
last_response.should_not be_ok
|
77
|
+
response = last_response.should return_json
|
78
|
+
response['error_message'].should == 'Pattern would overwrite existing'
|
79
|
+
end
|
80
|
+
|
81
|
+
it "new watch that subsets an existing should not work" do
|
82
|
+
Noah::Watcher.create(:endpoint => 'http://myendpoint/webhook', :pattern => '//noah/application')
|
83
|
+
data = {:endpoint => "http://myendpoint/webhook", :pattern => '//noah/application/foo'}
|
84
|
+
put '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
85
|
+
last_response.should_not be_ok
|
86
|
+
response = last_response.should return_json
|
87
|
+
response['error_message'].should == 'Pattern is already provided'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "DELETE" do
|
92
|
+
it "delete an existing watch should work" do
|
93
|
+
data = {:endpoint => "http://myendpoint/webhookd", :pattern => '//noah/application/d'}
|
94
|
+
w = Noah::Watcher.create(data)
|
95
|
+
delete '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
96
|
+
last_response.should be_ok
|
97
|
+
response = last_response.should return_json
|
98
|
+
response['pattern'].should == data[:pattern]
|
99
|
+
response['endpoint'].should == data[:endpoint]
|
100
|
+
response['name'].should_not == "null"
|
101
|
+
Noah::Watcher.find(data).size.should == 0
|
102
|
+
end
|
103
|
+
|
104
|
+
it "delete an invalid watch should not work" do
|
105
|
+
data = {:endpoint => 'missing', :pattern => '//noah/application/dag'}
|
106
|
+
delete '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
107
|
+
last_response.should be_missing
|
108
|
+
end
|
109
|
+
|
110
|
+
it "delete without pattern should not work" do
|
111
|
+
data = {:endpoint => "invalid"}
|
112
|
+
delete '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
113
|
+
last_response.should be_invalid
|
114
|
+
end
|
115
|
+
|
116
|
+
it "delete without endpoint should not work" do
|
117
|
+
data = {:pattern => "//noah/invalid"}
|
118
|
+
delete '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
119
|
+
last_response.should be_invalid
|
120
|
+
end
|
121
|
+
end
|
33
122
|
end
|
34
123
|
end
|
data/spec/watcher_spec.rb
CHANGED
@@ -32,30 +32,30 @@ describe "Using the Watcher Model", :reset_redis => true do
|
|
32
32
|
it "create a new Noah::Watcher with missing endpoint" do
|
33
33
|
a = Noah::Watcher.create(:pattern => "/foo/bar")
|
34
34
|
a.valid?.should == false
|
35
|
-
a.errors.
|
35
|
+
a.errors.should == [[:endpoint, :not_present]]
|
36
36
|
end
|
37
37
|
it "create a new Noah::Watcher with missing pattern" do
|
38
38
|
a = Noah::Watcher.create(:endpoint => "http://localhost/webhook")
|
39
39
|
a.valid?.should == false
|
40
|
-
a.errors.
|
40
|
+
a.errors.should == [[:pattern, :not_present]]
|
41
41
|
end
|
42
42
|
it "create a new Noah::Watcher with subset pattern" do
|
43
43
|
a = Noah::Watcher.create(:endpoint => "http://localhost.domain.com/webhook", :pattern => "//noah/")
|
44
44
|
b = Noah::Watcher.create(:endpoint => "http://localhost.domain.com/webhook", :pattern => "//noah/foobar")
|
45
45
|
b.valid?.should == false
|
46
|
-
b.errors.
|
46
|
+
b.errors.should == [[:pattern, :already_provided]]
|
47
47
|
end
|
48
48
|
it "create a new Noah::Watcher with superset pattern" do
|
49
49
|
a = Noah::Watcher.create(:endpoint => "http://localhost.domain.com/webhook", :pattern => "//noah/foobar")
|
50
50
|
b = Noah::Watcher.create(:endpoint => "http://localhost.domain.com/webhook", :pattern => "//noah")
|
51
51
|
b.valid?.should == false
|
52
|
-
b.errors.
|
52
|
+
b.errors.should == [[:pattern, :replaces_existing]]
|
53
53
|
end
|
54
54
|
it "create a duplicate Noah::Watcher" do
|
55
55
|
a = Noah::Watcher.create(:endpoint => "http://localhost.domain.com/webhook", :pattern => "//noah/foobar")
|
56
56
|
b = Noah::Watcher.create(:endpoint => "http://localhost.domain.com/webhook", :pattern => "//noah/foobar")
|
57
57
|
b.valid?.should == false
|
58
|
-
b.errors.
|
58
|
+
b.errors.should == [[[:endpoint, :pattern], :not_unique]]
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: noah
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: "0.1"
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- John E. Vincent
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-03-
|
13
|
+
date: 2011-03-11 00:00:00 -05:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -265,7 +265,6 @@ files:
|
|
265
265
|
- lib/vendor/em-hiredis/Gemfile
|
266
266
|
- lib/vendor/em-hiredis/README.md
|
267
267
|
- lib/vendor/em-hiredis/Rakefile
|
268
|
-
- lib/vendor/em-hiredis/em-hiredis-0.0.1.gem
|
269
268
|
- lib/vendor/em-hiredis/em-hiredis.gemspec
|
270
269
|
- lib/vendor/em-hiredis/lib/em-hiredis.rb
|
271
270
|
- lib/vendor/em-hiredis/lib/em-hiredis/client.rb
|
@@ -279,6 +278,7 @@ files:
|
|
279
278
|
- spec/host_spec.rb
|
280
279
|
- spec/noahapp_application_spec.rb
|
281
280
|
- spec/noahapp_configuration_spec.rb
|
281
|
+
- spec/noahapp_ephemeral_spec.rb
|
282
282
|
- spec/noahapp_host_spec.rb
|
283
283
|
- spec/noahapp_service_spec.rb
|
284
284
|
- spec/noahapp_spec.rb
|
@@ -316,7 +316,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
316
316
|
requirements: []
|
317
317
|
|
318
318
|
rubyforge_project: noah
|
319
|
-
rubygems_version: 1.5.
|
319
|
+
rubygems_version: 1.5.2
|
320
320
|
signing_key:
|
321
321
|
specification_version: 3
|
322
322
|
summary: Application registry based on Apache Zookeeper
|
Binary file
|