daikon 0.0.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "daemons", "~> 1.1.0"
4
+ gem "json_pure", "~> 1.4.6"
5
+ gem "net-http-persistent", "~> 1.4.1"
6
+ gem "redis", "~> 2.1.1"
7
+ gem "SystemTimer", "~> 1.2.1"
8
+
9
+ group :development do
10
+ gem "rspec"
11
+ gem "cucumber"
12
+ gem "jeweler"
13
+ gem "bourne"
14
+ gem "webmock"
15
+ end
@@ -0,0 +1,59 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ SystemTimer (1.2.1)
5
+ addressable (2.2.2)
6
+ bourne (1.0)
7
+ mocha (= 0.9.8)
8
+ builder (2.1.2)
9
+ crack (0.1.8)
10
+ cucumber (0.9.4)
11
+ builder (~> 2.1.2)
12
+ diff-lcs (~> 1.1.2)
13
+ gherkin (~> 2.2.9)
14
+ json (~> 1.4.6)
15
+ term-ansicolor (~> 1.0.5)
16
+ daemons (1.1.0)
17
+ diff-lcs (1.1.2)
18
+ gherkin (2.2.9)
19
+ json (~> 1.4.6)
20
+ term-ansicolor (~> 1.0.5)
21
+ git (1.2.5)
22
+ jeweler (1.5.1)
23
+ bundler (~> 1.0.0)
24
+ git (>= 1.2.5)
25
+ rake
26
+ json (1.4.6)
27
+ json_pure (1.4.6)
28
+ mocha (0.9.8)
29
+ rake
30
+ net-http-persistent (1.4.1)
31
+ rake (0.8.7)
32
+ redis (2.1.1)
33
+ rspec (2.1.0)
34
+ rspec-core (~> 2.1.0)
35
+ rspec-expectations (~> 2.1.0)
36
+ rspec-mocks (~> 2.1.0)
37
+ rspec-core (2.1.0)
38
+ rspec-expectations (2.1.0)
39
+ diff-lcs (~> 1.1.2)
40
+ rspec-mocks (2.1.0)
41
+ term-ansicolor (1.0.5)
42
+ webmock (1.6.1)
43
+ addressable (>= 2.2.2)
44
+ crack (>= 0.1.7)
45
+
46
+ PLATFORMS
47
+ ruby
48
+
49
+ DEPENDENCIES
50
+ SystemTimer (~> 1.2.1)
51
+ bourne
52
+ cucumber
53
+ daemons (~> 1.1.0)
54
+ jeweler
55
+ json_pure (~> 1.4.6)
56
+ net-http-persistent (~> 1.4.1)
57
+ redis (~> 2.1.1)
58
+ rspec
59
+ webmock
File without changes
data/Rakefile CHANGED
@@ -12,15 +12,6 @@ Jeweler::Tasks.new do |gem|
12
12
  gem.summary = gem.description = %Q{daikon, a radishapp.com client}
13
13
  gem.email = "nick@quaran.to"
14
14
  gem.authors = ["Nick Quaranto"]
15
-
16
- gem.add_runtime_dependency "daemons", "~> 1.0.0"
17
- gem.add_runtime_dependency "redis", "~> 2.1.1"
18
- gem.add_runtime_dependency "system_timer", "= 1.0"
19
-
20
- gem.add_development_dependency "rspec", "~> 2.1.0"
21
- gem.add_development_dependency "cucumber", ">= 0"
22
- gem.add_development_dependency "bundler", "~> 1.0.0"
23
- gem.add_development_dependency "jeweler", "~> 1.5.1"
24
15
  end
25
16
  Jeweler::RubygemsDotOrgTasks.new
26
17
 
@@ -5,23 +5,24 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{daikon}
8
- s.version = "0.0.0"
8
+ s.version = "0.1.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Nick Quaranto"]
12
- s.date = %q{2010-11-19}
12
+ s.date = %q{2010-11-21}
13
13
  s.default_executable = %q{daikon}
14
14
  s.description = %q{daikon, a radishapp.com client}
15
15
  s.email = %q{nick@quaran.to}
16
16
  s.executables = ["daikon"]
17
17
  s.extra_rdoc_files = [
18
- "LICENSE.txt",
19
18
  "README.rdoc"
20
19
  ]
21
20
  s.files = [
22
21
  ".document",
23
22
  ".rspec",
24
- "LICENSE.txt",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "MIT-LICENSE",
25
26
  "README.rdoc",
26
27
  "Rakefile",
27
28
  "VERSION",
@@ -57,30 +58,39 @@ Gem::Specification.new do |s|
57
58
  s.specification_version = 3
58
59
 
59
60
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
60
- s.add_runtime_dependency(%q<daemons>, ["~> 1.0.0"])
61
+ s.add_runtime_dependency(%q<daemons>, ["~> 1.1.0"])
62
+ s.add_runtime_dependency(%q<json_pure>, ["~> 1.4.6"])
63
+ s.add_runtime_dependency(%q<net-http-persistent>, ["~> 1.4.1"])
61
64
  s.add_runtime_dependency(%q<redis>, ["~> 2.1.1"])
62
- s.add_runtime_dependency(%q<system_timer>, ["= 1.0"])
63
- s.add_development_dependency(%q<rspec>, ["~> 2.1.0"])
65
+ s.add_runtime_dependency(%q<SystemTimer>, ["~> 1.2.1"])
66
+ s.add_development_dependency(%q<rspec>, [">= 0"])
64
67
  s.add_development_dependency(%q<cucumber>, [">= 0"])
65
- s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
66
- s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
68
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
69
+ s.add_development_dependency(%q<bourne>, [">= 0"])
70
+ s.add_development_dependency(%q<webmock>, [">= 0"])
67
71
  else
68
- s.add_dependency(%q<daemons>, ["~> 1.0.0"])
72
+ s.add_dependency(%q<daemons>, ["~> 1.1.0"])
73
+ s.add_dependency(%q<json_pure>, ["~> 1.4.6"])
74
+ s.add_dependency(%q<net-http-persistent>, ["~> 1.4.1"])
69
75
  s.add_dependency(%q<redis>, ["~> 2.1.1"])
70
- s.add_dependency(%q<system_timer>, ["= 1.0"])
71
- s.add_dependency(%q<rspec>, ["~> 2.1.0"])
76
+ s.add_dependency(%q<SystemTimer>, ["~> 1.2.1"])
77
+ s.add_dependency(%q<rspec>, [">= 0"])
72
78
  s.add_dependency(%q<cucumber>, [">= 0"])
73
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
74
- s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
79
+ s.add_dependency(%q<jeweler>, [">= 0"])
80
+ s.add_dependency(%q<bourne>, [">= 0"])
81
+ s.add_dependency(%q<webmock>, [">= 0"])
75
82
  end
76
83
  else
77
- s.add_dependency(%q<daemons>, ["~> 1.0.0"])
84
+ s.add_dependency(%q<daemons>, ["~> 1.1.0"])
85
+ s.add_dependency(%q<json_pure>, ["~> 1.4.6"])
86
+ s.add_dependency(%q<net-http-persistent>, ["~> 1.4.1"])
78
87
  s.add_dependency(%q<redis>, ["~> 2.1.1"])
79
- s.add_dependency(%q<system_timer>, ["= 1.0"])
80
- s.add_dependency(%q<rspec>, ["~> 2.1.0"])
88
+ s.add_dependency(%q<SystemTimer>, ["~> 1.2.1"])
89
+ s.add_dependency(%q<rspec>, [">= 0"])
81
90
  s.add_dependency(%q<cucumber>, [">= 0"])
82
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
83
- s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
91
+ s.add_dependency(%q<jeweler>, [">= 0"])
92
+ s.add_dependency(%q<bourne>, [">= 0"])
93
+ s.add_dependency(%q<webmock>, [">= 0"])
84
94
  end
85
95
  end
86
96
 
@@ -1,9 +1,13 @@
1
1
  require 'rubygems'
2
+ require 'stringio'
2
3
  require 'logger'
3
4
  require 'shellwords'
4
5
  require 'socket'
5
6
 
7
+ require 'system_timer'
6
8
  require 'daemons'
9
+ require 'json'
10
+ require 'net/http/persistent'
7
11
  require 'redis'
8
12
 
9
13
  __DIR__ = File.dirname(__FILE__)
@@ -18,5 +22,5 @@ require 'daikon/client'
18
22
  require 'daikon/daemon'
19
23
 
20
24
  module Daikon
21
- VERSION = "0.0.0"
25
+ VERSION = "0.1.1"
22
26
  end
@@ -2,26 +2,90 @@ module Daikon
2
2
  class Client
3
3
  include NamespaceTools
4
4
 
5
- attr_accessor :redis, :logger, :config
5
+ EXCEPTIONS = [Timeout::Error,
6
+ Errno::EINVAL,
7
+ Errno::ECONNRESET,
8
+ EOFError,
9
+ Net::HTTPBadResponse,
10
+ Net::HTTPHeaderSyntaxError,
11
+ Net::ProtocolError,
12
+ Net::HTTP::Persistent::Error,
13
+ JSON::ParserError]
14
+
15
+ attr_accessor :redis, :logger, :config, :http, :monitor
16
+
17
+ def setup(config, logger = nil)
18
+ self.config = config
19
+ self.logger = logger
20
+ self.redis = Redis.new(:port => config.redis_port)
21
+ self.http = Net::HTTP::Persistent.new
22
+ http.headers['Authorization'] = config.api_key
23
+
24
+ log "Started Daikon v#{VERSION}"
25
+ end
6
26
 
7
- def initialize(config, logger)
8
- @config = config
9
- @logger = logger
10
- @redis = Redis.new
27
+ def start_monitor
28
+ self.monitor = StringIO.new
29
+ Thread.new do
30
+ Redis.new(:port => config.redis_port).monitor do |line|
31
+ monitor.puts line
32
+ end
33
+ end
34
+ end
11
35
 
12
- logger.info "Started Daikon v#{VERSION}"
36
+ def log(message)
37
+ logger.info message if logger
38
+ end
39
+
40
+ def http_request(method, url)
41
+ request_uri = URI.parse("#{config.server_prefix}/#{url}")
42
+ request_method = Net::HTTP.const_get method.to_s.capitalize
43
+ request = request_method.new request_uri.path
44
+
45
+ yield request if block_given?
46
+
47
+ log "#{method.to_s.upcase} #{request_uri}"
48
+ http.request request_uri, request
13
49
  end
14
50
 
15
51
  def fetch_commands
16
- logger.info "fetch commands and run them"
52
+ raw_commands = http_request(:get, "api/v1/commands.json")
53
+ commands = JSON.parse(raw_commands.body)
54
+
55
+ commands.each do |id, command|
56
+ result = evaluate_redis(command)
57
+
58
+ http_request(:put, "api/v1/commands/#{id}.json") do |request|
59
+ request.body = result.to_json
60
+ request.add_field "Content-Length", request.body.size.to_s
61
+ request.add_field "Content-Type", "application/json"
62
+ end
63
+ end
64
+ rescue *EXCEPTIONS => ex
65
+ log ex.to_s
17
66
  end
18
67
 
19
- def send_info
20
- logger.info "sending INFO"
68
+ def report_info
69
+ http_request(:post, "api/v1/info.json") do |request|
70
+ request.body = redis.info.to_json
71
+ request.add_field "Content-Length", request.body.size.to_s
72
+ request.add_field "Content-Type", "application/json"
73
+ end
74
+ rescue *EXCEPTIONS => ex
75
+ log ex.to_s
21
76
  end
22
77
 
23
78
  def rotate_monitor
24
- logger.info "wrap up and truncate monitor log"
79
+ monitor_data = monitor.string
80
+ monitor.reopen(StringIO.new)
81
+
82
+ http_request(:post, "api/v1/monitor") do |request|
83
+ request.body = Gem.gzip(monitor_data)
84
+ request.add_field "Content-Length", request.body.size.to_s
85
+ request.add_field "Content-Type", "application/x-gzip"
86
+ end
87
+ rescue *EXCEPTIONS => ex
88
+ log ex.to_s
25
89
  end
26
90
 
27
91
  def evaluate_redis(command)
@@ -32,16 +96,16 @@ module Daikon
32
96
  rescue Exception => e
33
97
  STDERR.puts e.message
34
98
  e.backtrace.each {|bt| STDERR.puts bt}
35
- return { "error" => e.message }
99
+ return { "response" => e.message }
36
100
  end
37
- return { "error" => "No command received." } unless argv[0]
101
+ return { "response" => "No command received." } unless argv[0]
38
102
 
39
103
  begin
40
104
  { "response" => execute_redis(argv) }
41
105
  rescue Exception => e
42
106
  STDERR.puts e.message
43
107
  e.backtrace.each {|bt| STDERR.puts bt}
44
- { "error" => e.message }
108
+ { "response" => e.message }
45
109
  end
46
110
  end
47
111
 
@@ -53,47 +117,13 @@ module Daikon
53
117
  # Apply the current namespace to any fields that need it.
54
118
  argv = namespace_input(namespace, *argv)
55
119
 
56
- # Issue the default help text if the command was not recognized.
57
- raise "I'm sorry, I don't recognize that command. #{help}" unless argv.kind_of? Array
58
-
59
- if result = bypass(argv)
60
- result
61
- else
62
- # Send the command to Redis.
63
- result = redis.send(*argv)
64
-
65
- # Remove the namespace from any commands that return a key.
66
- denamespace_output namespace, argv.first, result
67
- end
68
- end
69
-
70
- def bypass(argv)
71
- queue = "transactions-#{namespace}"
120
+ raise "Not a Redis command." unless argv.kind_of? Array
72
121
 
73
- if argv.first == "multi"
74
- redis.del queue
75
- redis.rpush queue, argv.to_json
76
- return "OK"
77
- elsif redis.llen(queue).to_i >= 1
78
- redis.rpush queue, argv.to_json
122
+ # Send the command to Redis.
123
+ result = redis.send(*argv)
79
124
 
80
- if %w( discard exec ).include? argv.first
81
- commands = redis.lrange(queue, 0, -1)
82
- redis.del queue
83
-
84
- return commands.map do |c|
85
- cmd = JSON.parse(c)
86
-
87
- # Send the command to Redis.
88
- result = redis.send(*cmd)
89
-
90
- # Remove the namespace from any commands that return a key.
91
- denamespace_output namespace, cmd.first, result
92
- end.last
93
- end
94
-
95
- return "QUEUED"
96
- end
125
+ # Remove the namespace from any commands that return a key.
126
+ denamespace_output namespace, argv.first, result
97
127
  end
98
128
  end
99
129
  end
@@ -2,11 +2,11 @@ module Daikon
2
2
  class Configuration
3
3
  FLAGS = %w[-p -k -f -s]
4
4
  OPTIONS = %w[redis_port api_key field_id server_prefix]
5
- DEFAULTS = %w[6379 1234567890 1 radishapp.com]
5
+ DEFAULTS = %w[6379 1234567890 1 https://radishapp.com]
6
6
 
7
7
  attr_accessor *OPTIONS
8
8
 
9
- def initialize(argv)
9
+ def initialize(argv = [])
10
10
  FLAGS.each_with_index do |flag, flag_index|
11
11
  argv_index = argv.index(flag)
12
12
  value = if argv_index
@@ -17,6 +17,10 @@ module Daikon
17
17
 
18
18
  send "#{OPTIONS[flag_index]}=", value
19
19
  end
20
+
21
+ if api_key == DEFAULTS[1] && argv.any? { |arg| arg =~ /start|run/ }
22
+ abort "Must supply an api key to start the daemon.\nExample: daikon start #{FLAGS[1]} #{DEFAULTS[1]}"
23
+ end
20
24
  end
21
25
  end
22
26
  end
@@ -1,26 +1,27 @@
1
1
  module Daikon
2
2
  class Daemon
3
3
  def self.start
4
- Daemons.run_proc('daikon') do
4
+ config = Daikon::Configuration.new(ARGV)
5
+
6
+ Daemons.run_proc("daikon", :log_output => true, :backtrace => true) do
5
7
  if ARGV.include?("run")
6
8
  logger = Logger.new(STDOUT)
7
9
  else
8
10
  logger = Logger.new("/tmp/radish.log")
9
11
  end
10
12
 
11
- config = Daikon::Configuration.new(ARGV)
12
- client = Daikon::Client.new(config, logger)
13
13
  count = 0
14
-
15
- logger.info "spawn monitor watcher"
14
+ client = Daikon::Client.new
15
+ client.setup(config, logger)
16
+ client.start_monitor
16
17
 
17
18
  loop do
18
- client.fetch_commands
19
-
20
- if count % 5 == 4
21
- client.send_info
19
+ if count % 5 == 0
20
+ client.report_info
22
21
  end
23
22
 
23
+ client.fetch_commands
24
+
24
25
  if count % 10 == 9
25
26
  client.rotate_monitor
26
27
  end
@@ -40,7 +40,7 @@ module Daikon
40
40
  result
41
41
 
42
42
  when "mget", "rpoplpush", "sinter", "sunion", "sdiff", "info",
43
- "sinterstore", "sunionstore", "sdiffstore"
43
+ "sinterstore", "sunionstore", "sdiffstore", "dbsize"
44
44
 
45
45
  # All arguments are keys.
46
46
 
@@ -1,5 +1,211 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Daikon::Client do
3
+ describe Daikon::Client, "setup" do
4
+ subject { Daikon::Client.new }
5
+ let(:logger) { Logger.new(nil) }
6
+ let(:redis) { 'redis instance' }
4
7
 
8
+ before do
9
+ Redis.stubs(:new => redis)
10
+ subject.stubs(:redis=)
11
+ end
12
+
13
+ context "with defaults" do
14
+ let(:config) { Daikon::Configuration.new(%w[-p 1234]) }
15
+
16
+ before do
17
+ subject.setup(config, logger)
18
+ end
19
+
20
+ it "sets redis to listen on the given port" do
21
+ Redis.should have_received(:new).with(:port => "1234")
22
+ subject.should have_received(:redis=).with(redis)
23
+ end
24
+ end
25
+
26
+ context "with overrides" do
27
+ let(:config) { Daikon::Configuration.new([]) }
28
+
29
+ before do
30
+ subject.setup(config, logger)
31
+ end
32
+
33
+ it "sets redis to listen on the given port" do
34
+ Redis.should have_received(:new).with(:port => "6379")
35
+ subject.should have_received(:redis=).with(redis)
36
+ end
37
+ end
38
+ end
39
+
40
+ shared_examples_for "a command api consumer" do
41
+ it "sends a request for commands" do
42
+ WebMock.should have_requested(:get, "#{server}/api/v1/commands.json").
43
+ with(:headers => {'Authorization' => api_key})
44
+ end
45
+
46
+ it "processes each command" do
47
+ subject.should have_received(:evaluate_redis).with("INCR foo")
48
+ subject.should have_received(:evaluate_redis).with("DECR foo")
49
+ end
50
+
51
+ it "shoots the results back to radish" do
52
+ results = {"response" => "9999"}.to_json
53
+
54
+ headers = {
55
+ "Authorization" => api_key,
56
+ "Content-Length" => results.size.to_s,
57
+ "Content-Type" => "application/json"
58
+ }
59
+
60
+ WebMock.should have_requested(:put, "#{server}/api/v1/commands/42.json").
61
+ with(:body => results, :headers => headers)
62
+
63
+ WebMock.should have_requested(:put, "#{server}/api/v1/commands/43.json").
64
+ with(:body => results, :headers => headers)
65
+ end
66
+ end
67
+
68
+ describe Daikon::Client, "fetching commands" do
69
+ subject { Daikon::Client.new }
70
+ let(:body) { {"42" => "INCR foo", "43" => "DECR foo"}.to_json }
71
+
72
+ before do
73
+ subject.stubs(:evaluate_redis => {"response" => "9999"})
74
+ stub_request(:get, "#{server}/api/v1/commands.json").to_return(:body => body)
75
+ stub_request(:put, %r{#{server}/api/v1/commands/\d+\.json})
76
+
77
+ subject.setup(config)
78
+ subject.fetch_commands
79
+ end
80
+
81
+ context "with default configuration" do
82
+ let(:api_key) { config.api_key }
83
+ let(:server) { "https://radishapp.com" }
84
+ let(:config) { Daikon::Configuration.new([]) }
85
+
86
+ it_should_behave_like "a command api consumer"
87
+ end
88
+
89
+ context "with custom settings" do
90
+ let(:api_key) { "0987654321" }
91
+ let(:server) { "http://localhost:9999" }
92
+ let(:config) { Daikon::Configuration.new(["-k", api_key, "-s", "http://localhost:9999"]) }
93
+
94
+ it_should_behave_like "a command api consumer"
95
+ end
96
+ end
97
+
98
+ describe Daikon::Client, "when server is down" do
99
+ subject { Daikon::Client.new }
100
+ before do
101
+ subject.setup(Daikon::Configuration.new)
102
+ WebMock.stub_request(:any, /#{subject.config.server_prefix}.*/).to_raise(Timeout::Error)
103
+ end
104
+
105
+ it "does not commit suicide" do
106
+ lambda {
107
+ subject.fetch_commands
108
+ }.should_not raise_error
109
+ end
110
+ end
111
+
112
+ describe Daikon::Client, "when it returns bad json" do
113
+ subject { Daikon::Client.new }
114
+ before do
115
+ subject.setup(Daikon::Configuration.new)
116
+ WebMock.stub_request(:any, /#{subject.config.server_prefix}.*/).to_return(:body => "{'bad':'json}")
117
+ end
118
+
119
+ it "does not commit suicide" do
120
+ lambda {
121
+ subject.fetch_commands
122
+ }.should_not raise_error
123
+ end
124
+ end
125
+
126
+ shared_examples_for "a info api consumer" do
127
+ it "shoots the results back to radish" do
128
+
129
+ headers = {
130
+ "Authorization" => api_key,
131
+ "Content-Length" => results.to_json.size.to_s,
132
+ "Content-Type" => "application/json"
133
+ }
134
+
135
+ WebMock.should have_requested(:post, "#{server}/api/v1/info.json").
136
+ with(:body => results.to_json, :headers => headers)
137
+ end
138
+ end
139
+
140
+ describe Daikon::Client, "report info" do
141
+ subject { Daikon::Client.new }
142
+ let(:results) { {"connected_clients"=>"1", "used_cpu_sys_childrens"=>"0.00"}.to_json }
143
+ let(:redis) { stub("redis instance", :info => results) }
144
+
145
+ before do
146
+ stub_request(:post, "#{server}/api/v1/info.json")
147
+ subject.stubs(:redis => redis)
148
+ subject.setup(config)
149
+ subject.report_info
150
+ end
151
+
152
+ context "with default configuration" do
153
+ let(:api_key) { config.api_key }
154
+ let(:server) { "https://radishapp.com" }
155
+ let(:config) { Daikon::Configuration.new }
156
+
157
+ it_should_behave_like "a info api consumer"
158
+ end
159
+
160
+ context "with custom settings" do
161
+ let(:api_key) { "0987654321" }
162
+ let(:server) { "http://localhost:9999" }
163
+ let(:config) { Daikon::Configuration.new(["-k", api_key, "-s", "http://localhost:9999"]) }
164
+
165
+ it_should_behave_like "a info api consumer"
166
+ end
167
+ end
168
+
169
+ shared_examples_for "a monitor api consumer" do
170
+ it "shoots the results back to radish" do
171
+ zipped_data = Gem.gzip(results)
172
+
173
+ headers = {
174
+ "Authorization" => api_key,
175
+ "Content-Length" => zipped_data.size,
176
+ "Content-Type" => "application/x-gzip"
177
+ }
178
+
179
+ WebMock.should have_requested(:post, "#{server}/api/v1/monitor").
180
+ with(:body => zipped_data, :headers => headers)
181
+ end
182
+ end
183
+
184
+ describe Daikon::Client, "rotate monitor" do
185
+ subject { Daikon::Client.new }
186
+ let(:results) { %{1290289048.96581 "info"\n1290289053.568815 "info"} }
187
+ let(:redis) { stub("redis instance", :info => results) }
188
+
189
+ before do
190
+ stub_request(:post, "#{server}/api/v1/monitor")
191
+ subject.monitor = StringIO.new(results)
192
+ subject.setup(config)
193
+ subject.rotate_monitor
194
+ end
195
+
196
+ context "with default configuration" do
197
+ let(:api_key) { config.api_key }
198
+ let(:server) { "https://radishapp.com" }
199
+ let(:config) { Daikon::Configuration.new }
200
+
201
+ it_should_behave_like "a monitor api consumer"
202
+ end
203
+
204
+ context "with custom settings" do
205
+ let(:api_key) { "0987654321" }
206
+ let(:server) { "http://localhost:9999" }
207
+ let(:config) { Daikon::Configuration.new(["-k", api_key, "-s", "http://localhost:9999"]) }
208
+
209
+ it_should_behave_like "a monitor api consumer"
210
+ end
5
211
  end
@@ -13,7 +13,7 @@ describe Daikon::Configuration do
13
13
  end
14
14
 
15
15
  describe Daikon::Configuration do
16
- subject { Daikon::Configuration.new([]) }
16
+ subject { Daikon::Configuration.new(%w[-k 1234567890]) }
17
17
 
18
18
  it "uses the default keys" do
19
19
  subject.redis_port.should == "6379"
@@ -23,6 +23,24 @@ describe Daikon::Configuration do
23
23
  end
24
24
  end
25
25
 
26
+ describe Daikon::Configuration do
27
+ %w[start run restart].each do |command|
28
+ it "raises an error if no api key provided when booting daemon with #{command}" do
29
+ capture do
30
+ lambda {
31
+ Daikon::Configuration.new([command])
32
+ }.should raise_error(SystemExit)
33
+ end
34
+ end
35
+ end
36
+
37
+ it "raises no errors on other commands" do
38
+ lambda {
39
+ Daikon::Configuration.new(["stop"])
40
+ }.should_not raise_error
41
+ end
42
+ end
43
+
26
44
  describe Daikon::Configuration do
27
45
  subject { Daikon::Configuration.new(flags) }
28
46
  let(:flags) { %w[-p 9001 -k deadbeef] }
@@ -7,6 +7,21 @@ require 'daikon'
7
7
  # in ./support/ and its subdirectories.
8
8
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
9
 
10
+ require 'bourne'
11
+
12
+ require 'webmock/rspec'
13
+ WebMock.disable_net_connect!
14
+
10
15
  RSpec.configure do |config|
11
-
16
+ config.mock_with :mocha
17
+ end
18
+
19
+ # http://pivotallabs.com/users/alex/blog/articles/853-capturing-standard-out-in-unit-tests
20
+ def capture
21
+ output = StringIO.new
22
+ $stderr = output
23
+ yield
24
+ output.string
25
+ ensure
26
+ $stderr = STDERR
12
27
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: daikon
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 0
9
- - 0
10
- version: 0.0.0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Nick Quaranto
@@ -15,76 +15,94 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-11-19 00:00:00 -05:00
18
+ date: 2010-11-21 00:00:00 -05:00
19
19
  default_executable: daikon
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: daemons
23
22
  prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
23
+ type: :runtime
24
+ name: daemons
25
+ version_requirements: &id001 !ruby/object:Gem::Requirement
25
26
  none: false
26
27
  requirements:
27
28
  - - ~>
28
29
  - !ruby/object:Gem::Version
29
- hash: 23
30
+ hash: 19
30
31
  segments:
31
32
  - 1
33
+ - 1
32
34
  - 0
33
- - 0
34
- version: 1.0.0
35
+ version: 1.1.0
36
+ requirement: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ prerelease: false
35
39
  type: :runtime
36
- version_requirements: *id001
40
+ name: json_pure
41
+ version_requirements: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ hash: 11
47
+ segments:
48
+ - 1
49
+ - 4
50
+ - 6
51
+ version: 1.4.6
52
+ requirement: *id002
37
53
  - !ruby/object:Gem::Dependency
38
- name: redis
39
54
  prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
55
+ type: :runtime
56
+ name: net-http-persistent
57
+ version_requirements: &id003 !ruby/object:Gem::Requirement
41
58
  none: false
42
59
  requirements:
43
60
  - - ~>
44
61
  - !ruby/object:Gem::Version
45
- hash: 9
62
+ hash: 5
46
63
  segments:
47
- - 2
48
64
  - 1
65
+ - 4
49
66
  - 1
50
- version: 2.1.1
51
- type: :runtime
52
- version_requirements: *id002
67
+ version: 1.4.1
68
+ requirement: *id003
53
69
  - !ruby/object:Gem::Dependency
54
- name: system_timer
55
70
  prerelease: false
56
- requirement: &id003 !ruby/object:Gem::Requirement
71
+ type: :runtime
72
+ name: redis
73
+ version_requirements: &id004 !ruby/object:Gem::Requirement
57
74
  none: false
58
75
  requirements:
59
- - - "="
76
+ - - ~>
60
77
  - !ruby/object:Gem::Version
61
- hash: 15
78
+ hash: 9
62
79
  segments:
80
+ - 2
63
81
  - 1
64
- - 0
65
- version: "1.0"
66
- type: :runtime
67
- version_requirements: *id003
82
+ - 1
83
+ version: 2.1.1
84
+ requirement: *id004
68
85
  - !ruby/object:Gem::Dependency
69
- name: rspec
70
86
  prerelease: false
71
- requirement: &id004 !ruby/object:Gem::Requirement
87
+ type: :runtime
88
+ name: SystemTimer
89
+ version_requirements: &id005 !ruby/object:Gem::Requirement
72
90
  none: false
73
91
  requirements:
74
92
  - - ~>
75
93
  - !ruby/object:Gem::Version
76
- hash: 11
94
+ hash: 29
77
95
  segments:
96
+ - 1
78
97
  - 2
79
98
  - 1
80
- - 0
81
- version: 2.1.0
82
- type: :development
83
- version_requirements: *id004
99
+ version: 1.2.1
100
+ requirement: *id005
84
101
  - !ruby/object:Gem::Dependency
85
- name: cucumber
86
102
  prerelease: false
87
- requirement: &id005 !ruby/object:Gem::Requirement
103
+ type: :development
104
+ name: rspec
105
+ version_requirements: &id006 !ruby/object:Gem::Requirement
88
106
  none: false
89
107
  requirements:
90
108
  - - ">="
@@ -93,40 +111,63 @@ dependencies:
93
111
  segments:
94
112
  - 0
95
113
  version: "0"
96
- type: :development
97
- version_requirements: *id005
114
+ requirement: *id006
98
115
  - !ruby/object:Gem::Dependency
99
- name: bundler
100
116
  prerelease: false
101
- requirement: &id006 !ruby/object:Gem::Requirement
117
+ type: :development
118
+ name: cucumber
119
+ version_requirements: &id007 !ruby/object:Gem::Requirement
102
120
  none: false
103
121
  requirements:
104
- - - ~>
122
+ - - ">="
105
123
  - !ruby/object:Gem::Version
106
- hash: 23
124
+ hash: 3
107
125
  segments:
108
- - 1
109
- - 0
110
126
  - 0
111
- version: 1.0.0
112
- type: :development
113
- version_requirements: *id006
127
+ version: "0"
128
+ requirement: *id007
114
129
  - !ruby/object:Gem::Dependency
130
+ prerelease: false
131
+ type: :development
115
132
  name: jeweler
133
+ version_requirements: &id008 !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ hash: 3
139
+ segments:
140
+ - 0
141
+ version: "0"
142
+ requirement: *id008
143
+ - !ruby/object:Gem::Dependency
116
144
  prerelease: false
117
- requirement: &id007 !ruby/object:Gem::Requirement
145
+ type: :development
146
+ name: bourne
147
+ version_requirements: &id009 !ruby/object:Gem::Requirement
118
148
  none: false
119
149
  requirements:
120
- - - ~>
150
+ - - ">="
121
151
  - !ruby/object:Gem::Version
122
- hash: 1
152
+ hash: 3
123
153
  segments:
124
- - 1
125
- - 5
126
- - 1
127
- version: 1.5.1
154
+ - 0
155
+ version: "0"
156
+ requirement: *id009
157
+ - !ruby/object:Gem::Dependency
158
+ prerelease: false
128
159
  type: :development
129
- version_requirements: *id007
160
+ name: webmock
161
+ version_requirements: &id010 !ruby/object:Gem::Requirement
162
+ none: false
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ hash: 3
167
+ segments:
168
+ - 0
169
+ version: "0"
170
+ requirement: *id010
130
171
  description: daikon, a radishapp.com client
131
172
  email: nick@quaran.to
132
173
  executables:
@@ -134,12 +175,13 @@ executables:
134
175
  extensions: []
135
176
 
136
177
  extra_rdoc_files:
137
- - LICENSE.txt
138
178
  - README.rdoc
139
179
  files:
140
180
  - .document
141
181
  - .rspec
142
- - LICENSE.txt
182
+ - Gemfile
183
+ - Gemfile.lock
184
+ - MIT-LICENSE
143
185
  - README.rdoc
144
186
  - Rakefile
145
187
  - VERSION