nimble_nodes 0.1.9 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -5,12 +5,15 @@ begin
5
5
  require 'jeweler'
6
6
  Jeweler::Tasks.new do |gem|
7
7
  gem.name = "nimble_nodes"
8
- gem.summary = "gem for connecting apps to the NimbleNodes server"
9
- gem.description = "automatically scales dynos and workers at Heroku"
8
+ gem.summary = "coming soon"
9
+ gem.description = "coming soon"
10
10
  gem.email = "jordan@digitalignition.com"
11
11
  gem.homepage = "http://github.com/glasner/nimble_nodes"
12
12
  gem.authors = ["Jordan Glasner"]
13
13
  gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ gem.add_development_dependency "mocha"
15
+ gem.add_development_dependency "fakeweb"
16
+ gem.add_dependency "json"
14
17
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
18
  end
16
19
  Jeweler::GemcutterTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.9
1
+ 0.2.0
@@ -0,0 +1,51 @@
1
+ module NimbleNodes
2
+
3
+ module App
4
+
5
+ #= Rails
6
+
7
+ def self.rails?
8
+ defined?(RAILS_GEM_VERSION) ? true : false
9
+ end
10
+
11
+ def self.rails_version
12
+ RAILS_GEM_VERSION.slice(0..2).to_f
13
+ end
14
+
15
+ #== Check Rails version
16
+ # returns true if gem is loaded in a pre 2.3 version of rails
17
+ def self.use_rails_filter?
18
+ NimbleNodes::App.rails? and NimbleNodes::App.rails_version < 2.3
19
+ end
20
+
21
+ # set through Heroku API when app is created
22
+ def self.name
23
+ ENV['NIMBLE_NODES_APP_NAME']
24
+ end
25
+
26
+ # set through Heroku API when app is created at server
27
+ def self.token
28
+ ENV['NIMBLE_NODES_APP_TOKEN']
29
+ end
30
+
31
+ # returns true if app has been setup at server correctly
32
+ def self.token?
33
+ not NimbleNodes::App.token.nil?
34
+ end
35
+
36
+ # path at server for calling app resource and subresources
37
+ def self.path(subpath='/')
38
+ name = NimbleNodes::App.name
39
+ return nil if name.nil?
40
+ '/' + name + subpath
41
+ end
42
+
43
+ # returns path to platform specific report implementation
44
+ def self.reporter
45
+ path = NimbleNodes::App.use_rails_filter? ? '/rails/filter' : '/middleware'
46
+ NimbleNodes.lib_path(path)
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -2,16 +2,65 @@ module NimbleNodes
2
2
 
3
3
  module Dynos
4
4
 
5
+ #= Settings
6
+
7
+ # shortcut for accessing NimbleNodes.settings[:dynos_pool][key]
8
+ def self.[](key)
9
+ NimbleNodes::Dynos.settings[key]
10
+ end
11
+
12
+ def self.settings
13
+ hash = NimbleNodes::Settings['dynos_pool']
14
+ hash.nil? ? {} : hash
15
+ end
16
+
5
17
  def self.size
6
- ENV['NN_DYNOS_POOL_SIZE']
18
+ NimbleNodes::Dynos['size']
19
+ end
20
+
21
+ def self.min
22
+ NimbleNodes::Dynos['min']
7
23
  end
8
24
 
9
25
  def self.max
10
- ENV['NN_DYNOS_POOL_MAX']
26
+ NimbleNodes::Dynos['max']
27
+ end
28
+
29
+ def self.request_queue
30
+ hash = NimbleNodes::Dynos.settings['request_queue']
31
+ hash.nil? ? {} : hash
32
+ end
33
+
34
+ def self.min_request_queue
35
+ NimbleNodes::Dynos.request_queue['min']
11
36
  end
12
37
 
13
38
  def self.max_request_queue
14
- ENV['NN_DYNOS_REQUEST_QUEUE_MAX']
39
+ NimbleNodes::Dynos.request_queue['max']
40
+ end
41
+
42
+ #= Status Inspector
43
+
44
+ def self.paused?
45
+ not NimbleNodes::Dynos['paused_at'].nil?
46
+ end
47
+
48
+ #= Monitoring
49
+
50
+ def self.monitor?
51
+ NimbleNodes.active? and !NimbleNodes::Dynos.paused?
52
+ end
53
+
54
+
55
+ # pass over the hash containing Rack env variables
56
+ # a Report will be created and posted if neccessary
57
+ def self.monitor(env)
58
+ begin
59
+ report = NimbleNodes::Report.new(env)
60
+ report.post if report.post?
61
+ rescue
62
+ # rescues any possible errors to ensure app performace isn't affected
63
+ end
15
64
  end
16
65
 
17
66
  end
@@ -6,7 +6,7 @@ module NimbleNodes
6
6
 
7
7
 
8
8
  def call(env)
9
- NimbleNodes.monitor(env)
9
+ NimbleNodes::Dynos.monitor(env) if NimbleNodes::Dynos.monitor?
10
10
  # now, execute the request using our Rails app
11
11
  response = @app.call(env)
12
12
  end
@@ -0,0 +1,17 @@
1
+ module NimbleNodes
2
+ module Rails
3
+ module Filter
4
+
5
+ # Use as a before_filter
6
+ def monitor_heroku_app
7
+ NimbleNodes::Dynos.monitor(request.env) if NimbleNodes::Dynos.monitor?
8
+ end
9
+
10
+
11
+ end
12
+ end
13
+
14
+
15
+ end
16
+
17
+ ActionController::Base.send(:include, NimbleNodes::Rails::Filter)
@@ -2,11 +2,6 @@ module NimbleNodes
2
2
 
3
3
  class Report
4
4
 
5
-
6
- def self.path
7
- "/#{ENV['NN_APP_NAME']}/dynos/reports.json"
8
- end
9
-
10
5
  def initialize(env)
11
6
  @dynos_in_use = env['HTTP_X_HEROKU_DYNOS_IN_USE'].to_i
12
7
  @request_queue_depth = env['HTTP_X_HEROKU_QUEUE_DEPTH'].to_i
@@ -16,29 +11,36 @@ module NimbleNodes
16
11
  params = {
17
12
  :dynos_in_use => @dynos_in_use,
18
13
  :request_queue_size => @request_queue_depth }
19
- NimbleNodes::Server.post(self.class.path, params)
14
+ NimbleNodes::Server.post('/dynos/reports.json', params)
20
15
  end
21
16
 
17
+ # returns true if report needs to be posted to server
22
18
  def post?
23
- return false unless NimbleNodes.installed?
24
19
  return true
25
- return false if NimbleNodes.paused?
26
- dynos_maxed_out? or queue_depth_too_long? or unused_dynos?
20
+ dynos_maxed_out? or queue_depth_too_long? or queue_depth_too_short? or idle_dynos?
27
21
  end
28
22
 
23
+ # returns true if app is using all available dynos
29
24
  def dynos_maxed_out?
30
25
  return false if @dynos_in_use.nil?
31
- @dynos_in_use >= Dynos.max
26
+ @dynos_in_use >= NimbleNodes::Dynos.max
32
27
  end
33
-
28
+
29
+ # returns true if queue depth is over max
34
30
  def queue_depth_too_long?
35
31
  return false if @request_queue_depth.nil?
36
- @request_queue_depth > Dynos.max_request_queue
32
+ @request_queue_depth > NimbleNodes::Dynos.max_request_queue
33
+ end
34
+
35
+ def queue_depth_too_short?
36
+ return false if @request_queue_depth.nil?
37
+ @request_queue_depth < NimbleNodes::Dynos.min_request_queue
37
38
  end
38
39
 
39
- def unused_dynos?
40
+ # returns true if app isn't using all of it's dynos
41
+ def idle_dynos?
40
42
  return false if @dynos_in_use.nil?
41
- @dynos_in_use < Dynos.size
43
+ @dynos_in_use < NimbleNodes::Dynos.size
42
44
  end
43
45
 
44
46
  end
@@ -4,18 +4,63 @@ module NimbleNodes
4
4
 
5
5
  class Server
6
6
 
7
- def self.post(path,args)
8
- url = URI.parse(url_to(path))
9
- request = Net::HTTP::Post.new(url.path)
10
- request.set_form_data({:token => ENV['NN_APP_TOKEN'], :json => args.to_json, :created_at => Time.now })
11
- response = Net::HTTP.start(url.host, url.port) {|http| http.request(request)}
7
+ #= HTTP Requests
8
+ # GETs and POSTs both add App.token to request automatically
9
+
10
+ def self.get(path)
11
+ begin
12
+ path = NimbleNodes::App.path(path)
13
+ uri = uri_with_token(path)
14
+ path = uri.route_from(NimbleNodes::Server.url[0..-2]).to_s
15
+ request = Net::HTTP::Get.new(path)
16
+ return Net::HTTP.start(uri.host, uri.port) {|http| http.request(request)}.body
17
+ rescue
18
+ return nil
19
+ end
20
+ end
21
+
22
+
23
+ def self.post(path,params)
24
+ begin
25
+ path = NimbleNodes::App.path(path)
26
+ uri = uri(path)
27
+ request = Net::HTTP::Post.new(uri.path)
28
+ request.set_form_data({:token => NimbleNodes::App.token, :json => params.to_json, :created_at => Time.now })
29
+ return Net::HTTP.start(uri.host, uri.port) {|http| http.request(request)}
30
+ rescue
31
+ return nil
32
+ end
33
+ end
34
+
35
+
36
+ #= Domain & URLs
37
+
38
+ # set ENV variable in development to override production domain
39
+ def self.domain
40
+ ENV['NIMBLE_NODES_DOMAIN'].nil? ? 'nimblenodes.com' : ENV['NIMBLE_NODES_DOMAIN']
12
41
  end
13
42
 
14
- def self.url_to(path)
15
- 'http://' + ENV['NN_SERVER_DOMAIN'] + path
16
- # 'http://nimblenodes.com' + path
43
+ # returns string for url to given path at server
44
+ def self.url(path='/')
45
+ 'http://' + domain + path
17
46
  end
18
47
 
48
+ # returns parsed URI for given path at server
49
+ def self.uri(path)
50
+ URI.parse(url(path))
51
+ end
52
+
53
+ # returns parsed URI with App.token in query
54
+ def self.uri_with_token(path)
55
+ uri = uri(path)
56
+ query = (uri.query || '').split('&')
57
+ query.push("token=#{NimbleNodes::App.token}")
58
+ uri.query = query.join('&')
59
+ uri
60
+ end
61
+
62
+
63
+
19
64
  end
20
65
 
21
66
  end
@@ -0,0 +1,51 @@
1
+ module NimbleNodes
2
+
3
+ class Settings
4
+
5
+ #= Setting accessor
6
+ #= allows NimbleNodes::Settings to be treated as a hash
7
+ # shortcut for accessing NimbleNodes.settings cache
8
+ def self.[](key)
9
+ cache[key]
10
+ end
11
+
12
+ private
13
+
14
+ #= Cache
15
+ # settings are fetched once from server and cached in global constant
16
+
17
+ # returns hash of settings from cache or fetched from nimblenodes.com
18
+ def self.cache
19
+ return CACHE if cache? and fresh_cache?
20
+ const_set('CACHE',NimbleNodes::Settings.fetch_from_server)
21
+ end
22
+
23
+ #== Fetch from server
24
+
25
+ # returns hash from parsed server response
26
+ def self.fetch_from_server
27
+ response = NimbleNodes::Server.get("/settings.json")
28
+ return {} if response.nil?
29
+ JSON[response].merge('fetched_at' => Time.now)
30
+ end
31
+
32
+ #== Cache Inspectors
33
+
34
+ # returns true if local settings have been set
35
+ def self.cache?
36
+ defined?(NimbleNodes::Settings::CACHE) and !NimbleNodes::Settings::CACHE.nil? and !NimbleNodes::Settings::CACHE.empty?
37
+ end
38
+
39
+ def self.fresh_cache?
40
+ fetched_at = CACHE['fetched_at']
41
+ return false if fetched_at.nil?
42
+ age = Time.now.to_i - fetched_at.to_i
43
+ five_minutes = 300
44
+ age > five_minutes
45
+ end
46
+
47
+
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,35 @@
1
+ module NimbleNodes
2
+
3
+ module Workers
4
+
5
+ def self.active?
6
+ ENV.has_key?('NN_WORKERS_POOL_ACTIVE')
7
+ end
8
+
9
+ def self.size
10
+ ENV['NN_WORKERS_POOL_SIZE']
11
+ end
12
+
13
+ def self.min
14
+ ENV['NN_WORKERS_POOL_MIN']
15
+ end
16
+
17
+ def self.max
18
+ ENV['NN_WORKERS_POOL_MAX']
19
+ end
20
+
21
+ def self.min
22
+ ENV['NN_WORKERS_POOL_MIN']
23
+ end
24
+
25
+ def self.min_job_queue
26
+ ENV['NN_WORKERS_JOB_QUEUE_MIN']
27
+ end
28
+
29
+ def self.max_job_queue
30
+ ENV['NN_WORKERS_JOB_QUEUE_MAX']
31
+ end
32
+
33
+ end
34
+
35
+ end
data/lib/nimble_nodes.rb CHANGED
@@ -1,36 +1,34 @@
1
+ require 'json'
2
+
1
3
  module NimbleNodes
2
4
 
3
- # returns array of files
4
- def self.files
5
- files = %w(dynos report server)
6
- files.push NimbleNodes.legacy? ? 'filter' : 'middleware'
7
- files
8
- end
9
-
5
+ #= Check Rails version
10
6
  # returns true if gem is loaded in a pre 2.3 version of rails
11
7
  def self.legacy?
12
8
  defined?(RAILS_GEM_VERSION) and RAILS_GEM_VERSION.slice(0..2).to_f < 2.3
13
- end
9
+ end
14
10
 
15
- #= Monitoring
16
- # pass over the hash containing Rack env variables
17
- # a Report will be created and posted if neccessary
18
- def self.monitor(env)
19
- report = NimbleNodes::Report.new(env)
20
- report.post if report.post?
11
+ #= App status inspectors
12
+ def self.active?
13
+ NimbleNodes::App.token? and !NimbleNodes.paused?
21
14
  end
22
15
 
23
- def self.installed?
24
- not ENV['NN_SERVER_DOMAIN'].nil?
16
+ def self.paused?
17
+ not NimbleNodes::Settings[:paused_at].nil?
25
18
  end
26
19
 
27
- def self.paused?
28
- not ENV['NN_APP_PAUSED_AT'].nil?
20
+
21
+
22
+ def self.lib_path(path='')
23
+ File.dirname(__FILE__) + '/nimble_nodes' + path
29
24
  end
30
25
 
31
26
  end
32
27
 
33
- NimbleNodes.files.each { |file| require File.dirname(__FILE__) + "/nimble_nodes/#{file}" }
28
+ files = %w(app settings dynos workers report server)
29
+ files.each { |file| require NimbleNodes.lib_path('/' + file) }
30
+
31
+ require NimbleNodes::App.reporter
34
32
 
35
33
 
36
34
 
data/nimble_nodes.gemspec CHANGED
@@ -5,12 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{nimble_nodes}
8
- s.version = "0.1.9"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jordan Glasner"]
12
- s.date = %q{2010-03-23}
13
- s.description = %q{automatically scales dynos and workers at Heroku}
12
+ s.date = %q{2010-04-04}
13
+ s.description = %q{coming soon}
14
14
  s.email = %q{jordan@digitalignition.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
@@ -24,23 +24,32 @@ Gem::Specification.new do |s|
24
24
  "Rakefile",
25
25
  "VERSION",
26
26
  "lib/nimble_nodes.rb",
27
+ "lib/nimble_nodes/app.rb",
27
28
  "lib/nimble_nodes/dynos.rb",
28
- "lib/nimble_nodes/filter.rb",
29
29
  "lib/nimble_nodes/middleware.rb",
30
+ "lib/nimble_nodes/rails/filter.rb",
30
31
  "lib/nimble_nodes/report.rb",
31
32
  "lib/nimble_nodes/server.rb",
33
+ "lib/nimble_nodes/settings.rb",
34
+ "lib/nimble_nodes/workers.rb",
32
35
  "nimble_nodes.gemspec",
33
36
  "test/helper.rb",
34
- "test/test_nimble_nodes.rb"
37
+ "test/unit/test_app.rb",
38
+ "test/unit/test_dynos.rb",
39
+ "test/unit/test_nimble_nodes.rb",
40
+ "test/unit/test_settings.rb"
35
41
  ]
36
42
  s.homepage = %q{http://github.com/glasner/nimble_nodes}
37
43
  s.rdoc_options = ["--charset=UTF-8"]
38
44
  s.require_paths = ["lib"]
39
45
  s.rubygems_version = %q{1.3.5}
40
- s.summary = %q{gem for connecting apps to the NimbleNodes server}
46
+ s.summary = %q{coming soon}
41
47
  s.test_files = [
42
48
  "test/helper.rb",
43
- "test/test_nimble_nodes.rb"
49
+ "test/unit/test_app.rb",
50
+ "test/unit/test_dynos.rb",
51
+ "test/unit/test_nimble_nodes.rb",
52
+ "test/unit/test_settings.rb"
44
53
  ]
45
54
 
46
55
  if s.respond_to? :specification_version then
@@ -49,11 +58,20 @@ Gem::Specification.new do |s|
49
58
 
50
59
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
60
  s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
61
+ s.add_development_dependency(%q<mocha>, [">= 0"])
62
+ s.add_development_dependency(%q<fakeweb>, [">= 0"])
63
+ s.add_runtime_dependency(%q<json>, [">= 0"])
52
64
  else
53
65
  s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
66
+ s.add_dependency(%q<mocha>, [">= 0"])
67
+ s.add_dependency(%q<fakeweb>, [">= 0"])
68
+ s.add_dependency(%q<json>, [">= 0"])
54
69
  end
55
70
  else
56
71
  s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
72
+ s.add_dependency(%q<mocha>, [">= 0"])
73
+ s.add_dependency(%q<fakeweb>, [">= 0"])
74
+ s.add_dependency(%q<json>, [">= 0"])
57
75
  end
58
76
  end
59
77
 
data/test/helper.rb CHANGED
@@ -1,10 +1,11 @@
1
1
  require 'rubygems'
2
2
  require 'test/unit'
3
+
3
4
  require 'shoulda'
5
+ require 'mocha'
6
+ require 'fakeweb'
4
7
 
5
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
- $LOAD_PATH.unshift(File.dirname(__FILE__))
7
- require 'nimble_nodes'
8
+ require File.expand_path(File.dirname(__FILE__)) + '/../lib/nimble_nodes'
8
9
 
9
10
  class Test::Unit::TestCase
10
11
  end
@@ -0,0 +1,102 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + '/../helper'
2
+
3
+ class TestApp < Test::Unit::TestCase
4
+
5
+ context "An App" do
6
+
7
+ setup { @module = NimbleNodes::App }
8
+
9
+ context "on Rails" do
10
+
11
+ setup { @module.stubs(:rails?).returns(true) }
12
+
13
+ context "2.3 or later" do
14
+ setup { @module.stubs(:rails_version).returns(2.3) }
15
+
16
+ should "not use rails before_filter" do
17
+ assert(!@module.use_rails_filter?)
18
+ end
19
+
20
+ should "return NimbleNodes::Middleware as reporter" do
21
+ assert_equal 'middleware', @module.reporter.split('/').last
22
+ end
23
+
24
+ end
25
+
26
+ context "prior to 2.3" do
27
+ setup { NimbleNodes::App.stubs(:rails_version).returns(2.2) }
28
+
29
+ should "use rails before_filter" do
30
+ assert(@module.use_rails_filter?)
31
+ end
32
+
33
+ should "return NimbleNodes::Filter as reporter" do
34
+ assert_equal 'filter', @module.reporter.split('/').last
35
+ end
36
+
37
+ end
38
+
39
+
40
+ end
41
+
42
+ context "off Rails" do
43
+
44
+ should "return false for rails?" do
45
+ # we're not in Rails so this works
46
+ assert_equal false, @module.rails?
47
+ end
48
+
49
+ should "return NimbleNodes::Middleware as reporter" do
50
+ assert_equal 'middleware', @module.reporter.split('/').last
51
+ end
52
+
53
+ end
54
+
55
+
56
+ context "installed at NimbleNodes" do
57
+
58
+ setup {
59
+ ENV['NIMBLE_NODES_APP_NAME'] = 'nimble-nodes-test'
60
+ ENV['NIMBLE_NODES_APP_TOKEN'] = 'test'
61
+ }
62
+
63
+ should "return name from ENV" do
64
+ assert_equal ENV['NIMBLE_NODES_APP_NAME'], @module.name
65
+ end
66
+
67
+ should "return token from ENV" do
68
+ assert_equal ENV['NIMBLE_NODES_APP_TOKEN'], @module.token
69
+ end
70
+
71
+ should "return true for token?" do
72
+ assert @module.token?
73
+ end
74
+
75
+ should "return relative path at NN server" do
76
+ assert_equal '/nimble-nodes-test/', @module.path
77
+ end
78
+
79
+ should "return relative path to app resource for given path" do
80
+ assert_equal '/nimble-nodes-test/dynos', @module.path('/dynos')
81
+ end
82
+
83
+
84
+ end
85
+
86
+ context "not installed at NimbleNodes" do
87
+
88
+ setup {
89
+ ENV['NIMBLE_NODES_APP_NAME'] = nil
90
+ ENV['NIMBLE_NODES_APP_TOKEN'] = nil
91
+ }
92
+
93
+ should "return false for token?" do
94
+ assert_equal false, @module.token?
95
+ end
96
+
97
+ end
98
+
99
+
100
+ end
101
+
102
+ end
@@ -0,0 +1,97 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + '/../helper'
2
+
3
+ class Test::Unit::TestCase
4
+
5
+ def self.should_not_raise_anything_when_monitored
6
+ should "not raise any exceptions when sent :monitored?" do
7
+ assert_nothing_raised { @module.monitor? }
8
+ NimbleNodes::Server.stubs(:post).returns(nil)
9
+ assert_nothing_raised { @module.monitor({}) }
10
+ end
11
+ end
12
+
13
+ def self.should_not_be_monitored
14
+ should "not be monitored" do
15
+ assert_equal false, @module.monitor?
16
+ end
17
+ end
18
+
19
+
20
+ end
21
+
22
+
23
+ class TestDynos < Test::Unit::TestCase
24
+
25
+ context "Dynos" do
26
+
27
+ setup {
28
+ @module = NimbleNodes::Dynos
29
+ }
30
+
31
+ context "App setup at NimbleNodes" do
32
+
33
+ setup {
34
+ NimbleNodes::App.stubs({
35
+ :name => 'nimble-nodes-test',
36
+ :token => 'token'
37
+ })
38
+ @module.stubs(:settings).returns({
39
+ 'paused_at' => nil,
40
+ 'min' => 1,
41
+ 'max' => 2
42
+ })
43
+ }
44
+
45
+ context "and App not paused" do
46
+ setup { NimbleNodes.stubs(:paused?).returns(false) }
47
+
48
+ should "be monitored" do
49
+ assert @module.monitor?
50
+ end
51
+
52
+ should_not_raise_anything_when_monitored
53
+
54
+ context "and Dynos paused" do
55
+ setup {
56
+ @module.stubs(:settings).returns({
57
+ 'paused_at' => Time.now,
58
+ 'min' => 1,
59
+ 'max' => 2
60
+ })
61
+ }
62
+
63
+ should "be paused" do
64
+ assert @module.paused?
65
+ end
66
+
67
+ should_not_be_monitored
68
+ should_not_raise_anything_when_monitored
69
+
70
+ end
71
+
72
+
73
+ end
74
+
75
+ context "and App paused" do
76
+ setup { NimbleNodes.stubs(:paused?).returns(true) }
77
+ should_not_be_monitored
78
+ should_not_raise_anything_when_monitored
79
+
80
+ end
81
+
82
+
83
+ end
84
+
85
+ context "App *not* setup at NimbleNodes.com" do
86
+
87
+ should_not_be_monitored
88
+
89
+ should_not_raise_anything_when_monitored
90
+
91
+
92
+ end
93
+
94
+
95
+ end
96
+
97
+ end
@@ -0,0 +1,80 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + '/../helper'
2
+
3
+ class TestNimbleNodes < Test::Unit::TestCase
4
+
5
+
6
+ context "NimbleNodes module" do
7
+ setup { @module = NimbleNodes }
8
+
9
+ context "in a Rails app" do
10
+
11
+ setup { NimbleNodes::App.stubs(:rails?).returns(true) }
12
+
13
+ context "pre 2.3" do
14
+ setup { NimbleNodes::App.stubs(:rails_version).returns(2.2) }
15
+
16
+ should "use NimbleNodes::Filter as reporter" do
17
+ assert_equal 'filter', @module.reporter.split('/').last
18
+ end
19
+
20
+ end
21
+
22
+ context "2.3 or later" do
23
+ setup { NimbleNodes::App.stubs(:rails_version).returns(2.3) }
24
+
25
+ should "use NimbleNodes::Middleware as reporter" do
26
+ assert_equal 'middleware', @module.reporter.split('/').last
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
33
+ context "in a non-Rails app" do
34
+ setup { NimbleNodes::App.stubs(:rails?).returns(false) }
35
+
36
+ should "use NimbleNodes::Middleware" do
37
+ assert_equal 'middleware8', @module.reporter.split('/').last
38
+ end
39
+
40
+ end
41
+
42
+ context "App installed at NimbleNodes" do
43
+
44
+ setup {
45
+ NimbleNodes::App.stubs({
46
+ :name => 'nimble-nodes-test',
47
+ :token => 'token'
48
+ })
49
+ }
50
+
51
+ context "not paused" do
52
+
53
+ setup {
54
+ @module.stubs(:paused?).returns(false)
55
+ }
56
+
57
+ should "be active" do
58
+ assert @module.active?
59
+ end
60
+ end
61
+
62
+ context "paused" do
63
+
64
+ setup {
65
+ @module.stubs(:paused?).returns(true)
66
+ }
67
+
68
+ should "be not active" do
69
+ assert(!@module.active?)
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+
76
+ end
77
+
78
+
79
+
80
+ end
@@ -0,0 +1,93 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + '/../helper'
2
+
3
+ class Test::Unit::TestCase
4
+
5
+ def self.should_not_raise_any_errors_when_fetching_from_server
6
+ should "not raise any errors when fetching from server" do
7
+ assert_nothing_raised { @module.fetch_from_server }
8
+ end
9
+ end
10
+
11
+ def self.should_not_raise_any_errors_on_unknown_keys
12
+ should "not raise errors on any unknown keys" do
13
+ assert_nothing_raised { @module.cache['bogus-key'] }
14
+ end
15
+ end
16
+
17
+
18
+ end
19
+
20
+ class TestSettings < Test::Unit::TestCase
21
+
22
+ context "Settings" do
23
+
24
+ setup {
25
+ @module = NimbleNodes::Settings
26
+ @module.send(:remove_const,'CACHE') if defined?(@module::CACHE)
27
+ }
28
+
29
+ context "App is installed at NimbleNodes.com" do
30
+ setup do
31
+ NimbleNodes::App.stubs({
32
+ :name => "nimble-nodes-test",
33
+ :token => 'test'
34
+ })
35
+ end
36
+
37
+ context "server responds with JSON" do
38
+
39
+ setup {
40
+ @json = '{"paused_at":null,"dynos_pool":{"size":1,"paused_at":null,"max":1,"request_queue":{"max":5,"min":0},"min":1}}'
41
+ @parsed = JSON[@json]
42
+ NimbleNodes::Server.expects(:get).returns(@json)
43
+ }
44
+
45
+ should "only fetch from server once" do
46
+ @module.expects(:fetch_from_server).once
47
+ @module['paused_at']
48
+ @module['dynos_pool']
49
+ end
50
+
51
+ should "save parsed parsed response in cache" do
52
+ cached = @module.cache
53
+ cached.delete('fetched_at')
54
+ assert_equal @parsed, cached
55
+ end
56
+
57
+ should "add fetched_at to server response" do
58
+ assert_not_nil @module['fetched_at']
59
+ end
60
+
61
+ should_not_raise_any_errors_on_unknown_keys
62
+
63
+ should_not_raise_any_errors_when_fetching_from_server
64
+
65
+ end
66
+
67
+ context "server responds with error" do
68
+ setup { NimbleNodes::Server.expects(:get).once.returns(nil) }
69
+ should_not_raise_any_errors_on_unknown_keys
70
+ should_not_raise_any_errors_when_fetching_from_server
71
+ end
72
+
73
+ end
74
+
75
+ context "App is *not* installed at NimbleNodes.com" do
76
+
77
+ setup {
78
+ NimbleNodes::App.stubs({
79
+ :name => nil,
80
+ :token => nil
81
+ })
82
+ NimbleNodes::Server.expects(:get).returns(nil)
83
+ }
84
+
85
+ should_not_raise_any_errors_on_unknown_keys
86
+ should_not_raise_any_errors_when_fetching_from_server
87
+
88
+ end
89
+
90
+
91
+ end
92
+
93
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nimble_nodes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Glasner
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-03-23 00:00:00 -04:00
12
+ date: 2010-04-04 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -22,7 +22,37 @@ dependencies:
22
22
  - !ruby/object:Gem::Version
23
23
  version: "0"
24
24
  version:
25
- description: automatically scales dynos and workers at Heroku
25
+ - !ruby/object:Gem::Dependency
26
+ name: mocha
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: fakeweb
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: json
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ description: coming soon
26
56
  email: jordan@digitalignition.com
27
57
  executables: []
28
58
 
@@ -39,14 +69,20 @@ files:
39
69
  - Rakefile
40
70
  - VERSION
41
71
  - lib/nimble_nodes.rb
72
+ - lib/nimble_nodes/app.rb
42
73
  - lib/nimble_nodes/dynos.rb
43
- - lib/nimble_nodes/filter.rb
44
74
  - lib/nimble_nodes/middleware.rb
75
+ - lib/nimble_nodes/rails/filter.rb
45
76
  - lib/nimble_nodes/report.rb
46
77
  - lib/nimble_nodes/server.rb
78
+ - lib/nimble_nodes/settings.rb
79
+ - lib/nimble_nodes/workers.rb
47
80
  - nimble_nodes.gemspec
48
81
  - test/helper.rb
49
- - test/test_nimble_nodes.rb
82
+ - test/unit/test_app.rb
83
+ - test/unit/test_dynos.rb
84
+ - test/unit/test_nimble_nodes.rb
85
+ - test/unit/test_settings.rb
50
86
  has_rdoc: true
51
87
  homepage: http://github.com/glasner/nimble_nodes
52
88
  licenses: []
@@ -74,7 +110,10 @@ rubyforge_project:
74
110
  rubygems_version: 1.3.5
75
111
  signing_key:
76
112
  specification_version: 3
77
- summary: gem for connecting apps to the NimbleNodes server
113
+ summary: coming soon
78
114
  test_files:
79
115
  - test/helper.rb
80
- - test/test_nimble_nodes.rb
116
+ - test/unit/test_app.rb
117
+ - test/unit/test_dynos.rb
118
+ - test/unit/test_nimble_nodes.rb
119
+ - test/unit/test_settings.rb
@@ -1,15 +0,0 @@
1
- module NimbleNodes
2
-
3
- module Filter
4
-
5
- # Use as a before_filter
6
- def monitor_heroku_app
7
- NimbleNodes.monitor(request.env)
8
- end
9
-
10
-
11
- end
12
-
13
- end
14
-
15
- ActionController::Base.send(:include, NimbleNodes::Filter)
@@ -1,7 +0,0 @@
1
- require 'helper'
2
-
3
- class TestNimbleNodes < Test::Unit::TestCase
4
- should "probably rename this file and start testing for real" do
5
- flunk "hey buddy, you should probably rename this file and start testing for real"
6
- end
7
- end