daikon 0.0.0 → 0.1.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/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