etcd 0.0.2 → 0.0.4

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.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MzNhZWZiNTA1ZjAzOTQ0ZjQ4YjUzOTIyZTZiNjEwZGVkZWJkYzllZg==
5
+ data.tar.gz: !binary |-
6
+ Y2ZlOTY4YTcxYTNkNzRhZGRhZDBlNzRlYWUyNjk2Y2VmMzBjYWFmYg==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ YTU1YjdhMmVhNTM1ZWFlOTc3ZmQwN2ZlNDM2N2EyNTI0ZTVjN2FkNTljMzc2
10
+ ODZhYjdiNTU4YmE3NGE0NjdiY2M2MDhhM2VmNWEzZTQ0OTBmMjViYmI3MWVj
11
+ MTkxZjI1YWM4NTU5OWUzMmRiYmY5MzcyNzg0YzljN2Y2OWQ5Njg=
12
+ data.tar.gz: !binary |-
13
+ NjJlNWY1NjQyNmQ0YmU1Y2M1ZTkxYTY3NzRhOTc3Mjc0ODUxODYxOGE2NGY0
14
+ NDE3ZWFkZjMzMGFlNzZhYWIyZTRhMTE5NDUyMjZkNWE3Y2Y4MTI4NzQ4YmRh
15
+ ZGM0MGRlNDM5ZGQ4MzNkN2JhNmEzMTVhN2QzNWNhNjY1NjkyZWM=
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ -c
2
+ -fs
@@ -0,0 +1,14 @@
1
+ before_install:
2
+ - sudo add-apt-repository ppa:duh/golang -y
3
+ - sudo apt-get update -y
4
+ - sudo apt-get install golang -y
5
+ - git clone https://github.com/coreos/etcd
6
+ - cd etcd && bash build
7
+ - bundle install --path .bundle
8
+ rvm:
9
+ - 1.9.3
10
+ - 2.0.0
11
+ branches:
12
+ only:
13
+ - master
14
+ script: "bundle exec rake spec"
data/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ [![Built on Travis](https://secure.travis-ci.org/ranjib/etcd-ruby.png?branch=master)](http://travis-ci.org/ranjib/etcd-ruby)
1
2
  # Etcd
2
3
 
3
4
  A ruby client for [etcd](https://github.com/coreos/etcd)
@@ -65,6 +66,11 @@ client.machines
65
66
  client.leader
66
67
  ```
67
68
 
69
+ ## Contributors
70
+ * Ranjib Dey
71
+ * Jesse Nelson
72
+
73
+
68
74
 
69
75
  ## Contributing
70
76
 
@@ -73,3 +79,4 @@ client.leader
73
79
  3. Commit your changes (`git commit -am 'Add some feature'`)
74
80
  4. Push to the branch (`git push origin my-new-feature`)
75
81
  5. Create new Pull Request
82
+ 6. If applicable, update the README.md
data/Rakefile CHANGED
@@ -1 +1,10 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "rdoc/task"
4
+
5
+ RSpec::Core::RakeTask.new("spec")
6
+
7
+ RDoc::Task.new do |rdoc|
8
+ rdoc.main = "README.rdoc"
9
+ rdoc.rdoc_files.include("README.rdoc", "lib /*.rb")
10
+ end
@@ -20,10 +20,10 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency "mixlib-cli"
22
22
  spec.add_dependency "mixlib-log"
23
- spec.add_dependency "hashie"
23
+ spec.add_dependency "uuid"
24
24
 
25
25
  spec.add_development_dependency "bundler"
26
26
  spec.add_development_dependency "rake"
27
27
  spec.add_development_dependency "rspec"
28
- spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency "simplecov"
29
29
  end
@@ -1,5 +1,15 @@
1
+
2
+ ##
3
+ # This module provides the Etcd:: name space for the gem and few
4
+ # factory methods for Etcd domain objects
1
5
  require 'etcd/client'
2
6
  module Etcd
7
+
8
+ ##
9
+ # Create and return a Etcd::Client object. It takes a hash +opts+
10
+ # as an argument which gets passed to the Etcd::Client.new method
11
+ # directly
12
+ # If +opts+ is not passed default options are used, defined by Etcd::Client.new
3
13
  def self.client(opts={})
4
14
  Etcd::Client.new(opts)
5
15
  end
@@ -1,16 +1,35 @@
1
1
  require 'net/http'
2
2
  require 'json'
3
- require 'hashie'
4
3
  require 'etcd/log'
4
+ require 'etcd/mixins/helpers'
5
+ require 'etcd/mixins/lockable'
6
+ require 'ostruct'
7
+
5
8
 
6
9
  module Etcd
10
+ ##
11
+ # This is the central ruby class for Etcd. It provides methods for all Etcd api calls.
12
+ # It also provides few additional methods beyond the core Etcd api, like Etcd::Client#lock
13
+ # and Etcd::Client#eternal_watch, they are defined in separate modules and included in this
14
+ # class
7
15
  class Client
8
16
 
17
+ include Etcd::Helpers
18
+ include Etcd::Lockable
19
+
9
20
  attr_reader :host, :port, :http, :allow_redirect
10
21
 
22
+ ##
23
+ # Creates a new instance of Etcd::Client. It accepts a hash +opts+ as argument
24
+ #
25
+ # @param [Hash] opts The options for new Etcd::Client object
26
+ # @opts [String] :host IP address of the etcd server (default is '127.0.0.1')
27
+ # @opts [Fixnum] :port Port number of the etcd server (default is 4001)
28
+
11
29
  def initialize(opts={})
12
30
  @host = opts[:host] || '127.0.0.1'
13
31
  @port = opts[:port] || 4001
32
+ @read_timeout = opts[:read_timeout] || 60
14
33
  if opts.has_key?(:allow_redirect)
15
34
  @allow_redirect = opts[:allow_redirect]
16
35
  else
@@ -23,11 +42,11 @@ module Etcd
23
42
  end
24
43
 
25
44
  def machines
26
- api_execute('/machines', :get).split(",")
45
+ api_execute( version_prefix + '/machines', :get).split(",")
27
46
  end
28
47
 
29
48
  def leader
30
- api_execute('/leader', :get)
49
+ api_execute( version_prefix + '/leader', :get)
31
50
  end
32
51
 
33
52
  def key_endpoint
@@ -43,30 +62,26 @@ module Etcd
43
62
  payload = {'value' => value, 'prevValue' => prevValue }
44
63
  payload['ttl'] = ttl unless ttl.nil?
45
64
  response = api_execute(path, :post, payload)
46
- Hashie::Mash.new(JSON.parse(response))
65
+ json2obj(response)
47
66
  end
48
67
 
49
68
  def set(key, value, ttl=nil)
50
69
  path = key_endpoint + key
51
- payload = {'value' => value}
70
+ payload = {'value' => value}
52
71
  payload['ttl'] = ttl unless ttl.nil?
53
72
  response = api_execute(path, :post, payload)
54
- Hashie::Mash.new(JSON.parse(response))
73
+ json2obj(response)
55
74
  end
56
75
 
76
+
57
77
  def delete(key)
58
78
  response = api_execute(key_endpoint + key, :delete)
59
- Hashie::Mash.new(JSON.parse(response))
79
+ json2obj(response)
60
80
  end
61
81
 
62
82
  def get(key)
63
83
  response = api_execute(key_endpoint + key, :get)
64
- obj = JSON.parse(response)
65
- if obj.is_a?(Array)
66
- obj.map{|e| Hashie::Mash.new(e)}
67
- else
68
- Hashie::Mash.new(obj)
69
- end
84
+ json2obj(response)
70
85
  end
71
86
 
72
87
  def watch(key, index=nil)
@@ -75,7 +90,7 @@ module Etcd
75
90
  else
76
91
  api_execute(watch_endpoint + key, :post, {'index' => index})
77
92
  end
78
- Hashie::Mash.new(JSON.parse(response))
93
+ json2obj(response)
79
94
  end
80
95
 
81
96
  def api_execute(path, method, params=nil)
@@ -87,9 +102,10 @@ module Etcd
87
102
  else
88
103
  Net::HTTP.new(host, port)
89
104
  end
105
+ http.read_timeout = @read_timeout
90
106
 
91
107
  case method
92
- when :get
108
+ when :get
93
109
  unless params.nil?
94
110
  encoded_params = URI.encode_www_form(params)
95
111
  path+= "?" + encoded_params
@@ -111,7 +127,7 @@ module Etcd
111
127
  Log.debug("Invoking: '#{req.class}' against '#{path}")
112
128
  res = http.request(req)
113
129
  Log.debug("Response code: #{res.code}")
114
- if res.is_a?(Net::HTTPSuccess)
130
+ if res.is_a?(Net::HTTPSuccess)
115
131
  Log.debug("Http success")
116
132
  res.body
117
133
  elsif redirect?(res.code.to_i) and allow_redirect
@@ -128,5 +144,14 @@ module Etcd
128
144
  def redirect?(code)
129
145
  (code >= 300) and (code < 400)
130
146
  end
147
+
148
+ def json2obj(json)
149
+ obj = JSON.parse(json)
150
+ if obj.is_a?(Array)
151
+ obj.map{|e| OpenStruct.new(e)}
152
+ else
153
+ OpenStruct.new(obj)
154
+ end
155
+ end
131
156
  end
132
157
  end
@@ -0,0 +1,48 @@
1
+ require 'uuid'
2
+
3
+ module Etcd
4
+ class Lock
5
+ class AcqusitionFailure < StandardError; end
6
+ class ReleaseFailure < StandardError; end
7
+
8
+
9
+ attr_reader :lock_id, :key, :value, :client
10
+ attr_reader :retries, :retry_interval, :attempts
11
+
12
+
13
+ def initialize(opts={})
14
+ @client = opts[:client]
15
+ @key = opts[:key] || '/global/lock'
16
+ @value = opts[:value] || 0
17
+ @retries = opts[:retries] || 1
18
+ @retry_interval = opts[:retry_interval] || 1
19
+ @attempts = 0
20
+ end
21
+
22
+ def acquire
23
+ @lock_id = uuid.generate
24
+ begin
25
+ response = client.test_and_set(key, lock_id, value)
26
+ @attempts = 0
27
+ response
28
+ rescue Exception => e
29
+ @attempts += 1
30
+ raise AcqusitionFailure, e.message if attempts >= retries
31
+ sleep retry_interval
32
+ acquire
33
+ end
34
+ end
35
+
36
+ def release
37
+ begin
38
+ response = client.test_and_set(key, value, lock_id)
39
+ rescue Exception => e
40
+ raise ReleaseFailure, e.message
41
+ end
42
+ end
43
+
44
+ def uuid
45
+ @uuid ||= UUID.new
46
+ end
47
+ end
48
+ end
@@ -1,5 +1,7 @@
1
1
  require 'mixlib/log'
2
2
  module Etcd
3
+ ##
4
+ # A wrapper class that extends Mixlib::Log
3
5
  class Log
4
6
  extend Mixlib::Log
5
7
  end
@@ -0,0 +1,22 @@
1
+ require 'etcd/lock'
2
+
3
+ module Etcd
4
+ module Helpers
5
+
6
+ def has_key?(key)
7
+ begin
8
+ get(key)
9
+ true
10
+ rescue Net::HTTPServerException => e
11
+ false
12
+ end
13
+ end
14
+
15
+ def eternal_watch(key, index=nil)
16
+ loop do
17
+ response = watch(key, index)
18
+ yield response
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,16 @@
1
+ module Etcd
2
+ module Lockable
3
+ def lock(opts={})
4
+ opts[:client] = opts[:client] || self
5
+ lock = Lock.new(opts)
6
+ lock.acquire
7
+ begin
8
+ yield lock.lock_id
9
+ rescue Exception => e
10
+ raise e
11
+ ensure
12
+ lock.release
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module Etcd
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -0,0 +1,55 @@
1
+ $:<< "lib/"
2
+
3
+ require 'etcd'
4
+ require 'uuid'
5
+
6
+ ETCD_BIN = ENV['ETCD_BIN'] || './etcd/etcd'
7
+
8
+ require 'functional_spec_helpers'
9
+ require 'functional/lock_spec'
10
+ require 'functional/read_only_client_spec'
11
+ require 'functional/test_and_set_spec'
12
+ require 'functional/watch_spec'
13
+
14
+ include Etcd::FunctionalSpec::Helpers
15
+
16
+ describe "Functional Test Suite" do
17
+
18
+ before(:all) do
19
+ start_etcd_servers
20
+ end
21
+
22
+ after(:all) do
23
+ stop_etcd_servers
24
+ end
25
+
26
+ let(:client) do
27
+ Etcd.client
28
+ end
29
+
30
+ let(:read_only_client) do
31
+ Etcd.client(:allow_redirect=>false, :port=> 4004)
32
+ end
33
+
34
+
35
+ include_examples "read only client"
36
+ include_examples "lock"
37
+ include_examples "test_and_set"
38
+ include_examples "watch"
39
+
40
+ it "#set/#get" do
41
+ key = random_key
42
+ value = uuid.generate
43
+ client.set(key, value)
44
+ expect(client.get(key).value).to eq(value)
45
+ end
46
+
47
+
48
+ it "#leader" do
49
+ expect(client.leader).to eq('http://127.0.0.1:7001')
50
+ end
51
+
52
+ it "#machines" do
53
+ expect(client.machines).to include('http://127.0.0.1:4001')
54
+ end
55
+ end
@@ -0,0 +1,70 @@
1
+ shared_examples "lock" do
2
+
3
+ let(:other_client) do
4
+ Etcd.client
5
+ end
6
+
7
+ it "if the lock is already aquired then another lock acquisition should fail" do
8
+ key = random_key(4)
9
+ value = uuid.generate
10
+ # initialize the lock key
11
+ client.set(key, value)
12
+ thr = Thread.new do
13
+ client.lock(:key=>key, :value=>value) do
14
+ sleep 2
15
+ end
16
+ end
17
+ sleep 1
18
+ expect {
19
+ other_client.lock(:key=>key, :value=> value) do
20
+ puts "Do something"
21
+ end
22
+ }.to raise_error(Etcd::Lock::AcqusitionFailure)
23
+ thr.join
24
+ end
25
+
26
+ it "if the lock is not already aquired then new lock aquisition should pass" do
27
+ key = random_key(4)
28
+ value = uuid.generate
29
+ # initialize the lock key
30
+ client.set(key, value)
31
+ expect {
32
+ client.lock(:key=>key, :value=>value) do
33
+ :foo
34
+ end
35
+ }.to_not raise_error
36
+ end
37
+
38
+ it "should release the lock even if the given block raises exception" do
39
+ key = random_key(4)
40
+ value = uuid.generate
41
+ client.set(key, value)
42
+ expect {
43
+ client.lock(:key=>key, :value=>value) do
44
+ raise StandardError
45
+ end
46
+ }.to raise_error(StandardError)
47
+
48
+ expect{
49
+ other_client.lock(:key=>key, :value=>value) {}
50
+ }.to_not raise_error
51
+ end
52
+
53
+ it "should raise lock release exception if the lock key value is changed " do
54
+ key = random_key(4)
55
+ value = uuid.generate
56
+ # initialize the lock key
57
+ client.set(key, value)
58
+ thr = Thread.new do
59
+ expect{
60
+ client.lock(:key=>key, :value=>value) do
61
+ sleep 3
62
+ end
63
+ }.to raise_error(Etcd::Lock::ReleaseFailure)
64
+
65
+ end
66
+ sleep 1
67
+ other_client.set(key, uuid.generate)
68
+ thr.join
69
+ end
70
+ end
@@ -0,0 +1,24 @@
1
+ shared_examples "read only client" do
2
+ it "should not allow write" do
3
+ key= random_key
4
+ expect{
5
+ read_only_client.set(key, uuid.generate)
6
+ }.to raise_error(Net::HTTPRetriableError)
7
+ end
8
+
9
+ it "should allow reads" do
10
+ key = random_key
11
+ value = uuid.generate
12
+ client.set(key, value)
13
+ sleep 1
14
+ expect(read_only_client.get(key).value).to eq(value)
15
+ end
16
+
17
+ it "should allow watch" do
18
+ key = random_key
19
+ value = uuid.generate
20
+ index = client.set(key, value).index
21
+ expect(read_only_client.watch(key, index).value).to eq(value)
22
+ end
23
+ end
24
+
@@ -0,0 +1,18 @@
1
+ shared_examples "test_and_set" do
2
+ it "should pass when prev value is correct" do
3
+ key = random_key(2)
4
+ old_value = uuid.generate
5
+ new_value = uuid.generate
6
+ client.set(key, old_value)
7
+ client.test_and_set(key, new_value, old_value)
8
+ expect(client.get(key).value).to eq(new_value)
9
+ end
10
+
11
+ it "should fail when prev value is incorrect" do
12
+ key = random_key(2)
13
+ value = uuid.generate
14
+ client.set(key, value)
15
+ expect{ client.test_and_set(key, 10, 2)}.to raise_error(Net::HTTPServerException)
16
+ end
17
+ end
18
+
@@ -0,0 +1,25 @@
1
+ shared_examples "watch" do
2
+ it "without index, returns the value at a particular index" do
3
+ key = random_key(4)
4
+ value1 = uuid.generate
5
+ value2 = uuid.generate
6
+
7
+ index1 = client.set(key, value1).index
8
+ index2 = client.set(key, value2).index
9
+
10
+ expect(client.watch(key, index1).value).to eq(value1)
11
+ expect(client.watch(key, index2).value).to eq(value2)
12
+ end
13
+
14
+ it "with index, waits and return when the key is updated" do
15
+ response = nil
16
+ key = random_key
17
+ value = uuid.generate
18
+ thr = Thread.new do
19
+ response = client.watch(key)
20
+ end
21
+ client.set(key, value)
22
+ thr.join
23
+ expect(response.value).to eq(value)
24
+ end
25
+ end
@@ -0,0 +1,56 @@
1
+ require 'uuid'
2
+
3
+ module Etcd
4
+ module FunctionalSpec
5
+ module Helpers
6
+ def start_etcd_servers
7
+ @tmpdir = Dir.mktmpdir
8
+ pid = spawn_etcd_server(@tmpdir+'/leader')
9
+ @pids = Array(pid)
10
+ puts "Etcd leader process id :#{pid}"
11
+ leader = '127.0.0.1:7001'
12
+
13
+ 4.times do |n|
14
+ client_port = 4002 + n
15
+ server_port = 7002 + n
16
+ pid = spawn_etcd_server(@tmpdir+client_port.to_s, client_port, server_port, leader)
17
+ @pids << pid
18
+ end
19
+ end
20
+
21
+ def stop_etcd_servers
22
+ @pids.each do |pid|
23
+ Process.kill("HUP", pid)
24
+ puts "Killed #{pid}"
25
+ end
26
+ FileUtils.remove_entry_secure @tmpdir
27
+ end
28
+
29
+ def spawn_etcd_server(dir, client_port=4001, server_port=7001, leader = nil)
30
+ args = " -c 127.0.0.1:#{client_port} -s 127.0.0.1:#{server_port} -d #{dir} -n node_#{client_port}"
31
+ command = if leader.nil?
32
+ ETCD_BIN + args
33
+ else
34
+ ETCD_BIN + args + " -C #{leader}"
35
+ end
36
+ puts command
37
+ pid = spawn(command)
38
+ Process.detach(pid)
39
+ sleep 1
40
+ pid
41
+ end
42
+
43
+ def uuid
44
+ @uuid ||= UUID.new
45
+ end
46
+
47
+ def random_key(n=1)
48
+ key=''
49
+ n.times do
50
+ key << '/'+ uuid.generate
51
+ end
52
+ key
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ require 'simplecov'
4
+
5
+ SimpleCov.start do
6
+ add_filter "/.bundle/"
7
+ add_filter "/spec/"
8
+ end
9
+
10
+ $:.unshift(File.expand_path("../lib", __FILE__))
11
+ $:.unshift(File.expand_path("../spec", __FILE__))
12
+
13
+ require 'etcd'
14
+ require 'functional_spec_helpers'
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+ require 'unit/etcd/mixins/helpers_spec'
3
+
4
+ describe Etcd::Client do
5
+
6
+ let(:client) do
7
+ Etcd::Client.new
8
+ end
9
+
10
+ it "should use localhost and 4001 port by default" do
11
+ expect(client.host).to eq('127.0.0.1')
12
+ expect(client.port).to eq(4001)
13
+ end
14
+
15
+ it "shlould follow redirection by default" do
16
+ expect(client.allow_redirect).to be_true
17
+ end
18
+
19
+ it "#machines should make /machines GET http request" do
20
+ client.should_receive(:api_execute).with('/v1/machines', :get).and_return('foobar')
21
+ expect(client.machines).to eq(['foobar'])
22
+ end
23
+
24
+ it "#leader should make /leader GET http request" do
25
+ client.should_receive(:api_execute).with('/v1/leader', :get).and_return('foobar')
26
+ expect(client.leader).to eq('foobar')
27
+ end
28
+
29
+ it "#get('/foo') should make /v1/keys/foo GET http request" do
30
+ client.should_receive(:api_execute).with('/v1/keys/foo', :get).and_return('{"value":1}')
31
+ expect(client.get('/foo').value).to eq(1)
32
+ end
33
+
34
+ describe "#set" do
35
+ it "set('/foo', 1) should invoke /v1/keys/foo POST http request" do
36
+ client.should_receive(:api_execute).with('/v1/keys/foo', :post, {'value'=>1}).and_return('{"value":1}')
37
+ expect(client.set('/foo', 1).value).to eq(1)
38
+ end
39
+ it "set('/foo', 1, 4) should invoke /v1/keys/foo POST http request and set the ttl to 4" do
40
+ client.should_receive(:api_execute).with('/v1/keys/foo', :post, {'value'=>1, 'ttl'=>4}).and_return('{"value":1}')
41
+ expect(client.set('/foo', 1, 4).value).to eq(1)
42
+ end
43
+ end
44
+
45
+ describe "#test_and_set" do
46
+ it "test_and_set('/foo', 1, 4) should invoke /v1/keys/foo POST http request" do
47
+ client.should_receive(:api_execute).with('/v1/keys/foo', :post, {'value'=>1, 'prevValue'=>4}).and_return('{"value":1}')
48
+ expect(client.test_and_set('/foo', 1, 4).value).to eq(1)
49
+ end
50
+ it "test_and_set('/foo', 1, 4, 10) should invoke /v1/keys/foo POST http request and set the ttl to 10" do
51
+ client.should_receive(:api_execute).with('/v1/keys/foo', :post, {'value'=>1, 'prevValue'=>4, 'ttl'=>10}).and_return('{"value":1}')
52
+ expect(client.test_and_set('/foo', 1, 4, 10).value).to eq(1)
53
+ end
54
+ end
55
+
56
+ it "#watch('/foo') should make /v1/watch/foo GET http request" do
57
+ client.should_receive(:api_execute).with('/v1/watch/foo', :get).and_return('{"value":1}')
58
+ expect(client.watch('/foo').value).to eq(1)
59
+ end
60
+
61
+ it "#delete('/foo') should make /v1/keys/foo DELETE http request" do
62
+ client.should_receive(:api_execute).with('/v1/keys/foo', :delete).and_return('{"index":"1"}')
63
+ client.delete('/foo')
64
+ end
65
+
66
+ it_should_behave_like Etcd::Helpers
67
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Etcd::Log do
4
+ it "should support debug, warn, info logging" do
5
+ expect(Etcd::Log).to respond_to(:debug)
6
+ expect(Etcd::Log).to respond_to(:warn)
7
+ expect(Etcd::Log).to respond_to(:info)
8
+ end
9
+ it "should allow users to set a log levels" do
10
+ Etcd::Log.level = :warn
11
+ expect(Etcd::Log.level).to eq(:warn)
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples Etcd::Helpers do
4
+ describe "#has_key" do
5
+ it "should return true when the key is present" do
6
+ client.should_receive(:get).with('/foo/bar').and_return({})
7
+ expect(client.has_key?('/foo/bar')).to be_true
8
+ end
9
+ it "should return false when the key is absent" do
10
+ client.should_receive(:get).with('/foo/bar').and_raise(Net::HTTPServerException.new('',''))
11
+ expect(client.has_key?('/foo/bar')).to be_false
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ describe Etcd do
5
+ describe "#client" do
6
+ it "should return a valid Etcd::Client object" do
7
+ expect(Etcd.client).to be_a_kind_of(Etcd::Client)
8
+ end
9
+ it "should pass the same options to Etcd::Client initilizer" do
10
+ opts = { :host => '10.10.10.10', :port=> 4001 }
11
+ Etcd::Client.should_receive(:new).with(opts)
12
+ Etcd.client(opts)
13
+ end
14
+ end
15
+ end
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: etcd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
5
- prerelease:
4
+ version: 0.0.4
6
5
  platform: ruby
7
6
  authors:
8
7
  - Ranjib Dey
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-08-01 00:00:00.000000000 Z
11
+ date: 2013-08-26 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: mixlib-cli
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ! '>='
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ! '>='
28
25
  - !ruby/object:Gem::Version
@@ -30,7 +27,6 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: mixlib-log
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ! '>='
36
32
  - !ruby/object:Gem::Version
@@ -38,15 +34,13 @@ dependencies:
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
38
  - - ! '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
- name: hashie
42
+ name: uuid
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
45
  - - ! '>='
52
46
  - !ruby/object:Gem::Version
@@ -54,7 +48,6 @@ dependencies:
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
52
  - - ! '>='
60
53
  - !ruby/object:Gem::Version
@@ -62,7 +55,6 @@ dependencies:
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: bundler
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
59
  - - ! '>='
68
60
  - !ruby/object:Gem::Version
@@ -70,7 +62,6 @@ dependencies:
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
66
  - - ! '>='
76
67
  - !ruby/object:Gem::Version
@@ -78,7 +69,6 @@ dependencies:
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rake
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
73
  - - ! '>='
84
74
  - !ruby/object:Gem::Version
@@ -86,7 +76,6 @@ dependencies:
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
80
  - - ! '>='
92
81
  - !ruby/object:Gem::Version
@@ -94,7 +83,6 @@ dependencies:
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: rspec
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
87
  - - ! '>='
100
88
  - !ruby/object:Gem::Version
@@ -102,15 +90,13 @@ dependencies:
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
94
  - - ! '>='
108
95
  - !ruby/object:Gem::Version
109
96
  version: '0'
110
97
  - !ruby/object:Gem::Dependency
111
- name: rspec
98
+ name: simplecov
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
101
  - - ! '>='
116
102
  - !ruby/object:Gem::Version
@@ -118,7 +104,6 @@ dependencies:
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
108
  - - ! '>='
124
109
  - !ruby/object:Gem::Version
@@ -131,6 +116,8 @@ extensions: []
131
116
  extra_rdoc_files: []
132
117
  files:
133
118
  - .gitignore
119
+ - .rspec
120
+ - .travis.yml
134
121
  - Gemfile
135
122
  - LICENSE.txt
136
123
  - README.md
@@ -138,37 +125,55 @@ files:
138
125
  - etcd.gemspec
139
126
  - lib/etcd.rb
140
127
  - lib/etcd/client.rb
128
+ - lib/etcd/lock.rb
141
129
  - lib/etcd/log.rb
130
+ - lib/etcd/mixins/helpers.rb
131
+ - lib/etcd/mixins/lockable.rb
142
132
  - lib/etcd/version.rb
133
+ - spec/functional/client_spec.rb
134
+ - spec/functional/lock_spec.rb
135
+ - spec/functional/read_only_client_spec.rb
136
+ - spec/functional/test_and_set_spec.rb
137
+ - spec/functional/watch_spec.rb
138
+ - spec/functional_spec_helpers.rb
139
+ - spec/spec_helper.rb
140
+ - spec/unit/etcd/client_spec.rb
141
+ - spec/unit/etcd/log_spec.rb
142
+ - spec/unit/etcd/mixins/helpers_spec.rb
143
+ - spec/unit/etcd_spec.rb
143
144
  homepage: https://github.com/ranjib/etcd-ruby
144
145
  licenses:
145
146
  - MIT
147
+ metadata: {}
146
148
  post_install_message:
147
149
  rdoc_options: []
148
150
  require_paths:
149
151
  - lib
150
152
  required_ruby_version: !ruby/object:Gem::Requirement
151
- none: false
152
153
  requirements:
153
154
  - - ! '>='
154
155
  - !ruby/object:Gem::Version
155
156
  version: '0'
156
- segments:
157
- - 0
158
- hash: 1991828162115001123
159
157
  required_rubygems_version: !ruby/object:Gem::Requirement
160
- none: false
161
158
  requirements:
162
159
  - - ! '>='
163
160
  - !ruby/object:Gem::Version
164
161
  version: '0'
165
- segments:
166
- - 0
167
- hash: 1991828162115001123
168
162
  requirements: []
169
163
  rubyforge_project:
170
- rubygems_version: 1.8.23
164
+ rubygems_version: 2.0.3
171
165
  signing_key:
172
- specification_version: 3
166
+ specification_version: 4
173
167
  summary: Ruby client library for etcd
174
- test_files: []
168
+ test_files:
169
+ - spec/functional/client_spec.rb
170
+ - spec/functional/lock_spec.rb
171
+ - spec/functional/read_only_client_spec.rb
172
+ - spec/functional/test_and_set_spec.rb
173
+ - spec/functional/watch_spec.rb
174
+ - spec/functional_spec_helpers.rb
175
+ - spec/spec_helper.rb
176
+ - spec/unit/etcd/client_spec.rb
177
+ - spec/unit/etcd/log_spec.rb
178
+ - spec/unit/etcd/mixins/helpers_spec.rb
179
+ - spec/unit/etcd_spec.rb