etcd 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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