desi 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Guardfile CHANGED
@@ -3,3 +3,9 @@
3
3
  guard 'yard' do
4
4
  watch(%r{lib/.+\.rb})
5
5
  end
6
+
7
+ guard 'rspec' do
8
+ watch(%r{^spec/.+_spec\.rb$})
9
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
10
+ watch('spec/spec_helper.rb') { "spec" }
11
+ end
data/README.md CHANGED
@@ -13,7 +13,7 @@ It can:
13
13
  It can be used both as a command-line tool and as a library.
14
14
 
15
15
 
16
- ## Usage
16
+ ## Usage (command-line)
17
17
 
18
18
  $ desi list # List locally installed ElasticSearch releases
19
19
  $ desi releases # List all upstream Elastic Search releases (latest 5 by default)
@@ -25,14 +25,14 @@ It can be used both as a command-line tool and as a library.
25
25
 
26
26
  $ desi indices "^foo" # List all indices whose name match /^foo/
27
27
  $ desi indices "^foo" --delete # Delete all matching indices
28
- $ desi indices "bar$" --empty # Remove all records from the matching
29
- # indices
28
+ $ desi indices "bar$" --empty # Remove all records from the matching indices
30
29
 
31
- ## Examples
30
+ ## Examples (command-line and Ruby)
32
31
 
33
- ### Currently installed releases
32
+ ### Get the list of locally installed releases
34
33
 
35
- The current version is the one symlinked to `$HOME/elasticsearch/current`
34
+ The current version is the one symlinked to `$HOME/elasticsearch/current`, that
35
+ will be spun up by (`desi start`)
36
36
 
37
37
  * command-line
38
38
 
@@ -52,6 +52,54 @@ The current version is the one symlinked to `$HOME/elasticsearch/current`
52
52
  ```
53
53
 
54
54
 
55
+ ### List and delete some indices
56
+
57
+ * command-line
58
+
59
+ ```shell
60
+ $ # List all local indices
61
+ $ desi indices
62
+ Indices from host http://127.0.0.1:9200 matching the pattern /.*/
63
+
64
+ foo
65
+ bar
66
+ baz
67
+
68
+ $ # List all indices on remote cluster 129.168.1.42, reachable on port 9800
69
+ $ desi indices --host 129.168.1.42:9800 foo
70
+ Indices from host http://192.168.1.42:9800 matching the pattern /foo/
71
+
72
+ remotefoo1
73
+ remotefoo2
74
+
75
+ $ # Remove all indices whose name starts with "ba"
76
+ $ desi indices --delete "^ba"
77
+ The following indices from host http://127.0.0.1:9200 are now deleted
78
+ * bar
79
+ * baz
80
+ ```
81
+
82
+
83
+ * library
84
+
85
+ ```ruby
86
+ # All local indices
87
+ Desi::IndexManager.new.list #=> ["foo", "bar", "baz"]
88
+
89
+ # All local indices whose name starts with `b`
90
+ Desi::IndexManager.new.list("^b") #=> ["bar", "baz"]
91
+
92
+ # All indices from distant cluster
93
+ Desi::IndexManager.new(host: "192.168.1.42:9800").list #=> ["remotefoo1", "remotefoo2"]
94
+
95
+ # Delete all local indices whose name starts with `ba`
96
+ Desi::IndexManager.new.delete!("^ba") #=> nil
97
+
98
+ # The indices actually disappeared
99
+ Desi::IndexManager.new.list #=> ["foo"]
100
+ ```
101
+
102
+
55
103
 
56
104
  ## Installation
57
105
 
@@ -69,7 +117,7 @@ Or install it yourself as:
69
117
 
70
118
  ## TODO
71
119
 
72
- * add tests, dammit!
120
+ * add more tests
73
121
 
74
122
  * `desi upgrade` (Upgrade to latest version and migrate data)
75
123
  * `desi switch VERSION` (Switch currently active ES version to VERSION)
data/desi.gemspec CHANGED
@@ -15,6 +15,9 @@ an Elastic Search local install for development purposes.}
15
15
  gem.add_dependency "cocaine"
16
16
  gem.add_dependency "addressable"
17
17
 
18
+ gem.add_development_dependency "rake"
19
+ gem.add_development_dependency "rspec"
20
+ gem.add_development_dependency "guard-rspec"
18
21
  gem.add_development_dependency "guard-yard"
19
22
  gem.add_development_dependency "redcarpet"
20
23
  gem.add_development_dependency "rb-inotify"
@@ -11,7 +11,7 @@ module Desi
11
11
  def initialize(opts = {})
12
12
  @destination_dir = Pathname(opts.fetch(:destination_dir, Desi::LocalInstall.new))
13
13
  @host = URI(opts.fetch(:host, 'http://cloud.github.com/'))
14
- @client = Desi::HttpClient.new(@host)
14
+ @client = opts.fetch(:http_client_factory, Desi::HttpClient).new(@host)
15
15
  @verbose = opts[:verbose]
16
16
  end
17
17
 
@@ -8,8 +8,6 @@ module Desi
8
8
 
9
9
  class HttpClient
10
10
 
11
- attr_reader :uri
12
-
13
11
  def initialize(host_string)
14
12
  @uri = to_uri(host_string)
15
13
 
@@ -10,19 +10,24 @@ module Desi
10
10
 
11
11
  # Initializes a Desi::IndexManager instance
12
12
  #
13
- # @param [#to_hash] opts Hash of extra opts
14
- # @option opts [#to_s] :host Host to manage indices for
15
- # (default: 'http://127.0.0.1:9200')
16
- # @option opts [Boolean] :verbose Whether to output the actions' result
17
- # on STDOUT
13
+ # @param [#to_hash] opts Hash of extra opts
18
14
  #
15
+ # @option opts [#to_s] :host ('http://127.0.0.1:9200') Host to manage indices for
16
+ # @option opts [Boolean] :verbose (nil) Whether to output the actions' result
17
+ # on STDOUT
18
+ # @option opts [#new] :http_client_factory (Desi::HttpClient) HTTP transport class
19
+ # to use
20
+ #
21
+ # @note The +:http_client_factory+ should return an instance that responds
22
+ # to #get and #delete
19
23
  # @return [undefined]
20
24
  #
21
25
  # @api public
22
26
  def initialize(opts = {})
23
27
  @host = opts.fetch(:host, 'http://127.0.0.1:9200')
24
28
  @verbose = opts[:verbose]
25
- @client = Desi::HttpClient.new(@host)
29
+ @outputter = opts.fetch(:outputter, Kernel)
30
+ @client = opts.fetch(:http_client_factory, Desi::HttpClient).new(@host)
26
31
  end
27
32
 
28
33
 
@@ -32,8 +37,8 @@ module Desi
32
37
  # pattern being +/.*/+, all releases will be returned if you do not
33
38
  # specify anything.)
34
39
  #
35
- # @param [#to_s] pattern Regexp pattern used to restrict the selection
36
- # @return [Array<String>] List of index names of the ES cluster
40
+ # @param [#to_s] pattern ('.*') Regexp pattern used to restrict the selection
41
+ # @return [Array<String>] List of index names of the ES cluster
37
42
  #
38
43
  # @note This method will also output its result on STDOUT if +@verbose+ is
39
44
  # true
@@ -45,10 +50,10 @@ module Desi
45
50
  def list(pattern = '.*')
46
51
  pattern = Regexp.new(pattern || '.*')
47
52
 
48
- puts "Indices from host #{@client.uri} matching the pattern #{pattern.inspect}\n\n" if @verbose
53
+ @outputter.puts "Indices from host #{@host} matching the pattern #{pattern.inspect}\n\n" if @verbose
49
54
 
50
55
  list = indices(pattern).sort
51
- list.each {|i| puts i } if @verbose
56
+ list.each {|i| @outputter.puts i } if @verbose
52
57
  list
53
58
  end
54
59
 
@@ -69,11 +74,11 @@ module Desi
69
74
  def delete!(pattern)
70
75
  warn "You must provide a pattern" and exit if pattern.nil?
71
76
 
72
- puts "The following indices from host #{@client.uri} are now deleted" if @verbose
77
+ @outputter.puts "The following indices from host #{@host} are now deleted" if @verbose
73
78
 
74
79
  indices(Regexp.new(pattern)).each do |index|
75
80
  @client.delete(index)
76
- puts " * #{index}" if @verbose
81
+ @outputter.puts " * #{index}" if @verbose
77
82
  end
78
83
  end
79
84
 
@@ -94,11 +99,11 @@ module Desi
94
99
  def empty!(pattern)
95
100
  warn "You must provide a pattern" and exit if pattern.nil?
96
101
 
97
- puts "The following indices from host #{@client.uri} are now emptied" if @verbose
102
+ @outputter.puts "The following indices from host #{@host} are now emptied" if @verbose
98
103
 
99
104
  indices(Regexp.new(pattern)).each do |index|
100
105
  @client.delete("#{index}/_query?q=*")
101
- puts " * #{index}" if @verbose
106
+ @outputter.puts " * #{index}" if @verbose
102
107
  end
103
108
  end
104
109
 
@@ -13,7 +13,7 @@ module Desi
13
13
  @host = opts.fetch(:host, 'http://127.0.0.1:9200')
14
14
  @verbose = opts[:verbose]
15
15
  @local_install = LocalInstall.new
16
- @client = Desi::HttpClient.new(@host)
16
+ @client = opts.fetch(:http_client_factory, Desi::HttpClient).new(@host)
17
17
  end
18
18
 
19
19
  def start
@@ -50,7 +50,7 @@ module Desi
50
50
  if version = running_version
51
51
  msg = "OK. Elastic Search cluster '#{cluster_health.cluster_name}' (v#{version}) is running on #{cluster_health.number_of_nodes} node(s) with status #{cluster_health.status}"
52
52
  else
53
- msg = "KO. No Elastic Search instance was found running on #{@client.uri}"
53
+ msg = "KO. No Elastic Search instance was found running on #{@host}"
54
54
  end
55
55
  puts msg if @verbose
56
56
  msg
data/lib/desi/upstream.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require "desi/http_client"
4
+ require "json"
4
5
 
5
6
  module Desi
6
7
  class Upstream
@@ -11,8 +12,8 @@ module Desi
11
12
  end
12
13
  end
13
14
 
14
- def initialize
15
- @client = Desi::HttpClient.new('https://api.github.com/')
15
+ def initialize(opts = {})
16
+ @client = opts.fetch(:http_client_factory, Desi::HttpClient).new('https://api.github.com/')
16
17
  end
17
18
 
18
19
  def releases
data/lib/desi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Desi
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1,134 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+ require "desi/index_manager"
5
+ require "json"
6
+
7
+ describe Desi::IndexManager do
8
+
9
+ subject { described_class.new(http_client_factory: http_client_factory) }
10
+
11
+ let(:http_client_factory) { double(new: http_client) }
12
+ let(:http_client) { double('http_client') }
13
+
14
+ def stub_request(method, path, payload)
15
+ http_client.stub(method).with(path).and_return(
16
+ mock("response", body: JSON.unparse(payload))
17
+ )
18
+ end
19
+
20
+ def stub_indices(*names)
21
+ stub_request(:get, '_status', {"indices" => Hash[Array(names).zip]})
22
+ end
23
+
24
+ before do
25
+ stub_indices('foo', 'bar')
26
+ end
27
+
28
+ describe "#list" do
29
+ context "with no specified pattern" do
30
+ it "returns the names of all indices" do
31
+ subject.list.should == %w[bar foo]
32
+ end
33
+ end
34
+
35
+ context "with a pattern" do
36
+ it "returns the matching indices" do
37
+ subject.list('oo').should == %w[foo]
38
+ end
39
+ end
40
+
41
+ context "when verbose is on" do
42
+ let(:outputter) { double("outputter") }
43
+
44
+ subject do
45
+ described_class.new(
46
+ http_client_factory: http_client_factory,
47
+ outputter: outputter,
48
+ verbose: true)
49
+ end
50
+
51
+ it "also outputs on STDOUT" do
52
+ outputter.should_receive(:puts).at_least(:once)
53
+ subject.list('oo')
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "#delete!" do
59
+ context "when the mandatory pattern is not specified" do
60
+ it "raises an ArgumentError" do
61
+ expect { subject.delete! }.to raise_error(ArgumentError)
62
+ end
63
+ end
64
+
65
+ it "deletes all matching indices" do
66
+ http_client.should_receive(:delete).with("foo")
67
+ http_client.should_not_receive(:delete).with("bar")
68
+
69
+ subject.delete!('f.*')
70
+ end
71
+
72
+ context "when verbose is on" do
73
+ let(:outputter) { double("outputter") }
74
+
75
+ subject do
76
+ described_class.new(
77
+ http_client_factory: http_client_factory,
78
+ outputter: outputter,
79
+ verbose: true)
80
+ end
81
+
82
+ it "also outputs on STDOUT" do
83
+ http_client.stub(:delete)
84
+
85
+ outputter.should_receive(:puts).at_least(:once)
86
+ subject.delete!('f.*')
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "#empty!" do
92
+ context "when the mandatory pattern is not specified" do
93
+ it "raises an ArgumentError" do
94
+ expect { subject.empty! }.to raise_error(ArgumentError)
95
+ end
96
+ end
97
+
98
+ it "deletes all matching indices" do
99
+ http_client.should_receive(:delete).with("foo/_query?q=*")
100
+ http_client.should_not_receive(:delete).with("bar")
101
+
102
+ subject.empty!('f.*')
103
+ end
104
+
105
+ context "when verbose is on" do
106
+ let(:outputter) { double("outputter") }
107
+
108
+ subject do
109
+ described_class.new(
110
+ http_client_factory: http_client_factory,
111
+ outputter: outputter,
112
+ verbose: true)
113
+ end
114
+
115
+ it "also outputs on STDOUT" do
116
+ http_client.stub(:delete)
117
+
118
+ outputter.should_receive(:puts).at_least(:once)
119
+ subject.empty!('f.*')
120
+ end
121
+ end
122
+ end
123
+
124
+ context "when given another host" do
125
+ let(:factory_for_remote_host) { double("http_client_factory") }
126
+
127
+ it "sends the other host's url to initialize the client" do
128
+ factory_for_remote_host.should_receive(:new).with("http://foobar.com")
129
+
130
+ described_class.new(host: "http://foobar.com", http_client_factory: factory_for_remote_host)
131
+ end
132
+ end
133
+
134
+ end
@@ -0,0 +1,11 @@
1
+ RSpec.configure do |config|
2
+ config.treat_symbols_as_metadata_keys_with_true_values = true
3
+ config.run_all_when_everything_filtered = true
4
+ config.filter_run :focus
5
+
6
+ # Run specs in random order to surface order dependencies. If you find an
7
+ # order dependency and want to debug it, you can fix the order by providing
8
+ # the seed, which is printed after each run.
9
+ # --seed 1234
10
+ config.order = 'random'
11
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: desi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -59,6 +59,54 @@ dependencies:
59
59
  - - ! '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: guard-rspec
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
62
110
  - !ruby/object:Gem::Dependency
63
111
  name: guard-yard
64
112
  requirement: !ruby/object:Gem::Requirement
@@ -119,6 +167,7 @@ extensions: []
119
167
  extra_rdoc_files: []
120
168
  files:
121
169
  - .gitignore
170
+ - .rspec
122
171
  - .yardopts
123
172
  - Gemfile
124
173
  - Guardfile
@@ -138,6 +187,8 @@ files:
138
187
  - lib/desi/runner.rb
139
188
  - lib/desi/upstream.rb
140
189
  - lib/desi/version.rb
190
+ - spec/desi/index_manager_spec.rb
191
+ - spec/spec_helper.rb
141
192
  - tasks/yard.rake
142
193
  homepage: https://github.com/AF83/desi/
143
194
  licenses: []
@@ -151,17 +202,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
151
202
  - - ! '>='
152
203
  - !ruby/object:Gem::Version
153
204
  version: '0'
205
+ segments:
206
+ - 0
207
+ hash: 1725098947325688636
154
208
  required_rubygems_version: !ruby/object:Gem::Requirement
155
209
  none: false
156
210
  requirements:
157
211
  - - ! '>='
158
212
  - !ruby/object:Gem::Version
159
213
  version: '0'
214
+ segments:
215
+ - 0
216
+ hash: 1725098947325688636
160
217
  requirements: []
161
218
  rubyforge_project:
162
219
  rubygems_version: 1.8.24
163
220
  signing_key:
164
221
  specification_version: 3
165
222
  summary: A developer tool to quickly set up an Elastic Search local install.
166
- test_files: []
223
+ test_files:
224
+ - spec/desi/index_manager_spec.rb
225
+ - spec/spec_helper.rb
167
226
  has_rdoc: