noah 0.0.9 → 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -13,28 +13,24 @@ end
13
13
 
14
14
 
15
15
  task :default => :run
16
- task :test => [:start, :spec, :stop]
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
- This is going to be a fun task. I'm serious.
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
- Not sure how I want to implement that. Not too keen on storing them as in-memory hashes. Maybe a LRU in Redis?
30
+ **IN PROGRESS**
31
+ implement lifetime support
21
32
 
22
33
  * Examples
23
34
 
24
- I need to make some example apps to really demonstrate what I'm trying to accomplish.
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
- - Partially done. Framework is in place to create a custom Watcher by hooking directly into Redis. Need to expand that to "official" watchers
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
- require 'rubygems'
4
- require 'rbtrace'
5
- require 'logger'
6
- require 'optparse'
7
- require 'em-hiredis'
8
- require 'eventmachine'
9
- require 'em-http-request'
10
- require 'thin'
11
- require 'noah'
12
- require 'json'
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
- #load File.joint(File.dirname(__FILE__), 'ephemeral_routes.rb')
66
+ load File.join(File.dirname(__FILE__), 'ephemeral_routes.rb')
67
67
 
68
68
  end
69
69
  end
@@ -41,7 +41,7 @@ class Noah::App
41
41
  r = {"result" => "success","id" => app.id, "action" => action, "name" => app.name }
42
42
  r.to_json
43
43
  else
44
- raise "#{app.errors}"
44
+ raise "#{format_errors(app)}"
45
45
  end
46
46
  end
47
47
 
@@ -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.errors}"
62
+ raise "#{format_errors(config)}"
63
63
  end
64
64
  end
65
65
 
@@ -1,19 +1,48 @@
1
1
  class Noah::App
2
- # Stubbing Ephemeral endpoints
2
+ get '/e/?' do
3
+ halt 404
4
+ end
5
+
3
6
  get '/e/*' do
4
- # Some logic to handle splats for ephemerals
5
- # Eventually I'll move to root path
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
- # Logic for adding watches to ephemerals
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
- # Some logic for creating ephemerals
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
- # See previous two entries
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
@@ -49,7 +49,7 @@ class Noah::App
49
49
  r = {"result" => "success","id" => "#{host.id}","status" => "#{host.status}", "name" => "#{host.name}", "new_record" => host.is_new?}
50
50
  r.to_json
51
51
  else
52
- raise "#{host.errors}"
52
+ raise "#{format_errors(host)}"
53
53
  end
54
54
  end
55
55
 
@@ -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
@@ -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
- def self.watch_list
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.
@@ -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.errors}"
53
+ raise "#{format_errors(service)}"
54
54
  end
55
55
  else
56
56
  raise "Missing Parameters"
data/lib/noah/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Noah
2
- VERSION = "0.0.9"
2
+ VERSION = "0.1"
3
3
  end
@@ -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
@@ -37,6 +37,7 @@ Gem::Specification.new do |s|
37
37
  s.add_development_dependency("warbler", ["= 1.2.1"])
38
38
  else
39
39
  s.add_dependency("yajl-ruby")
40
+ s.add_dependency("SystemTimer") if RUBY_VERSION =~ /1.8/
40
41
  s.add_dependency("thin")
41
42
  end
42
43
 
@@ -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
@@ -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 {|x| x == :path}
7
- @emissing_data = @edata.reject {|x| x == :data}
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
- # it "update an existing Noah::Ephemeral" do
32
- # @good_ephemeral.save
33
- # Noah::Ephemeral.all.size.should == 1
34
- # c = Noah::Ephemeral[@good_ephemeral.id]
35
- # c.data = "updated_data"
36
- # c.save
37
- # sleep(2)
38
- # c.is_new?.should == false
39
- # end
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
- @missing_path.valid?.should == false
49
- @missing_path.errors.should == [[:path, :not_present]]
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 == ["database", "adapter", "username", "password"]
38
- response["development"].values.should == ["development_database", "mysql", "dev_user", "dev_password"]
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
@@ -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 == "[[:status, :not_member]]"
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 == "[[:status, :not_member]]"
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.to_s.should == "[[:endpoint, :not_present]]"
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.to_s.should == "[[:pattern, :not_present]]"
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.to_s.should == "[[:pattern, :already_provided]]"
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.to_s.should == "[[:pattern, :replaces_existing]]"
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.to_s.should == "[[[:endpoint, :pattern], :not_unique]]"
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.0.9
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-08 00:00:00 -05:00
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.3
319
+ rubygems_version: 1.5.2
320
320
  signing_key:
321
321
  specification_version: 3
322
322
  summary: Application registry based on Apache Zookeeper