nightcrawler_swift 0.3.0 → 0.4.0
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.
- checksums.yaml +4 -4
- data/Changelog.md +11 -0
- data/Gemfile.lock +1 -1
- data/README.md +40 -25
- data/bin/nswift +8 -0
- data/lib/nightcrawler_swift/cli.rb +208 -0
- data/lib/nightcrawler_swift/command.rb +12 -2
- data/lib/nightcrawler_swift/{delete.rb → commands/delete.rb} +1 -1
- data/lib/nightcrawler_swift/{download.rb → commands/download.rb} +1 -1
- data/lib/nightcrawler_swift/{list.rb → commands/list.rb} +0 -0
- data/lib/nightcrawler_swift/{sync.rb → commands/sync.rb} +2 -2
- data/lib/nightcrawler_swift/commands/upload.rb +25 -0
- data/lib/nightcrawler_swift/connection.rb +44 -23
- data/lib/nightcrawler_swift/exceptions.rb +1 -0
- data/lib/nightcrawler_swift/tasks/asset_sync.rake +7 -1
- data/lib/nightcrawler_swift/version.rb +1 -1
- data/lib/nightcrawler_swift.rb +26 -9
- data/spec/fixtures/auth_success.json +6 -6
- data/spec/lib/nightcrawler_swift/cli_spec.rb +293 -0
- data/spec/lib/nightcrawler_swift/command_spec.rb +55 -14
- data/spec/lib/nightcrawler_swift/{delete_spec.rb → commands/delete_spec.rb} +15 -8
- data/spec/lib/nightcrawler_swift/{download_spec.rb → commands/download_spec.rb} +16 -7
- data/spec/lib/nightcrawler_swift/{list_spec.rb → commands/list_spec.rb} +12 -8
- data/spec/lib/nightcrawler_swift/{sync_spec.rb → commands/sync_spec.rb} +10 -1
- data/spec/lib/nightcrawler_swift/{upload_spec.rb → commands/upload_spec.rb} +23 -8
- data/spec/lib/nightcrawler_swift/connection_spec.rb +32 -20
- data/spec/lib/nightcrawler_swift/tasks/asset_sync_spec.rb +19 -3
- data/spec/lib/nightcrawler_swift_spec.rb +46 -15
- metadata +23 -18
- data/lib/nightcrawler_swift/upload.rb +0 -17
@@ -1,26 +1,13 @@
|
|
1
1
|
module NightcrawlerSwift
|
2
2
|
class Connection
|
3
|
-
attr_accessor :
|
4
|
-
|
5
|
-
# Hash with: bucket, tenant_name, username, password, auth_url
|
6
|
-
#
|
7
|
-
def initialize opts = {}
|
8
|
-
@opts = OpenStruct.new opts
|
9
|
-
raise NightcrawlerSwift::Exceptions::ConfigurationError.new "max_age should be an Integer" if @opts.max_age and not @opts.max_age.is_a? Numeric
|
10
|
-
end
|
3
|
+
attr_accessor :auth_response
|
4
|
+
attr_reader :token_id, :expires_at, :catalog, :admin_url, :upload_url, :public_url
|
11
5
|
|
12
6
|
def connect!
|
13
|
-
|
14
|
-
|
15
|
-
@token_id = auth_response.access["token"]["id"]
|
16
|
-
@expires_at = auth_response.access["token"]["expires"]
|
17
|
-
@expires_at = DateTime.parse(@expires_at).to_time
|
7
|
+
authenticate!
|
8
|
+
configure
|
18
9
|
|
19
|
-
|
20
|
-
@upload_url = "#{@admin_url}/#{opts.bucket}"
|
21
|
-
@public_url = auth_response.access["serviceCatalog"].first["endpoints"].first["publicURL"]
|
22
|
-
|
23
|
-
NightcrawlerSwift.logger.info "Connected, token_id: #{@token_id}"
|
10
|
+
NightcrawlerSwift.logger.debug "[NightcrawlerSwift] Connected, token_id: #{token_id}"
|
24
11
|
self
|
25
12
|
end
|
26
13
|
|
@@ -28,7 +15,17 @@ module NightcrawlerSwift
|
|
28
15
|
!self.token_id.nil? and self.expires_at > Time.now
|
29
16
|
end
|
30
17
|
|
18
|
+
def configure
|
19
|
+
select_token
|
20
|
+
select_catalog
|
21
|
+
select_endpoints
|
22
|
+
configure_urls
|
23
|
+
end
|
24
|
+
|
31
25
|
private
|
26
|
+
def opts
|
27
|
+
NightcrawlerSwift.options
|
28
|
+
end
|
32
29
|
|
33
30
|
def authenticate!
|
34
31
|
auth_options = {
|
@@ -36,15 +33,39 @@ module NightcrawlerSwift
|
|
36
33
|
passwordCredentials: {username: opts.username, password: opts.password}
|
37
34
|
}
|
38
35
|
|
39
|
-
|
40
|
-
opts.auth_url,
|
41
|
-
|
42
|
-
|
36
|
+
resource = RestClient::Resource.new(
|
37
|
+
opts.auth_url,
|
38
|
+
verify_ssl: NightcrawlerSwift.options.verify_ssl,
|
39
|
+
timeout: NightcrawlerSwift.options.timeout
|
43
40
|
)
|
44
41
|
|
45
|
-
|
42
|
+
response = resource.post({ auth: auth_options }.to_json, content_type: :json, accept: :json)
|
43
|
+
|
44
|
+
@auth_response = OpenStruct.new(JSON.parse(response.body))
|
46
45
|
rescue StandardError => e
|
47
46
|
raise Exceptions::ConnectionError.new(e)
|
48
47
|
end
|
48
|
+
|
49
|
+
def select_token
|
50
|
+
@token_id = auth_response.access["token"]["id"]
|
51
|
+
@expires_at = auth_response.access["token"]["expires"]
|
52
|
+
@expires_at = DateTime.parse(@expires_at).to_time
|
53
|
+
end
|
54
|
+
|
55
|
+
def select_catalog
|
56
|
+
catalogs = auth_response.access["serviceCatalog"]
|
57
|
+
@catalog = catalogs.find {|catalog| catalog["type"] == "object-store"}
|
58
|
+
end
|
59
|
+
|
60
|
+
def select_endpoints
|
61
|
+
raise Exceptions::ConfigurationError.new "No catalog of type 'object-store' found" if catalog.nil?
|
62
|
+
@endpoints = catalog["endpoints"].first
|
63
|
+
end
|
64
|
+
|
65
|
+
def configure_urls
|
66
|
+
@admin_url = @endpoints["adminURL"]
|
67
|
+
@upload_url = "#{@admin_url}/#{opts.bucket}"
|
68
|
+
@public_url = @endpoints["publicURL"]
|
69
|
+
end
|
49
70
|
end
|
50
71
|
end
|
@@ -4,7 +4,7 @@ namespace :nightcrawler_swift do
|
|
4
4
|
namespace :rails do
|
5
5
|
|
6
6
|
desc "Synchronizes the public directory with OpenStack Swift"
|
7
|
-
task
|
7
|
+
task sync: ["environment"] do
|
8
8
|
begin
|
9
9
|
NightcrawlerSwift.sync File.join(Rails.root, "public")
|
10
10
|
rescue => e
|
@@ -13,5 +13,11 @@ namespace :nightcrawler_swift do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
desc "Run 'assets:precompile' and synchronizes the public directory with OpenStack Swift"
|
17
|
+
task :asset_sync do
|
18
|
+
Rake::Task["assets:precompile"].invoke
|
19
|
+
Rake::Task["nightcrawler_swift:rails:sync"].invoke
|
20
|
+
end
|
21
|
+
|
16
22
|
end
|
17
23
|
end
|
data/lib/nightcrawler_swift.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "date"
|
2
2
|
require "logger"
|
3
|
+
require "digest"
|
3
4
|
require "ostruct"
|
4
5
|
require "multi_mime"
|
5
6
|
require "rest_client"
|
@@ -7,29 +8,45 @@ require "nightcrawler_swift/version"
|
|
7
8
|
require "nightcrawler_swift/exceptions"
|
8
9
|
require "nightcrawler_swift/command"
|
9
10
|
require "nightcrawler_swift/connection"
|
10
|
-
require "nightcrawler_swift/upload"
|
11
|
-
require "nightcrawler_swift/download"
|
12
|
-
require "nightcrawler_swift/list"
|
13
|
-
require "nightcrawler_swift/delete"
|
14
|
-
require "nightcrawler_swift/sync"
|
11
|
+
require "nightcrawler_swift/commands/upload"
|
12
|
+
require "nightcrawler_swift/commands/download"
|
13
|
+
require "nightcrawler_swift/commands/list"
|
14
|
+
require "nightcrawler_swift/commands/delete"
|
15
|
+
require "nightcrawler_swift/commands/sync"
|
15
16
|
require "nightcrawler_swift/railtie" if defined?(Rails)
|
16
17
|
|
17
18
|
module NightcrawlerSwift
|
18
19
|
class << self
|
19
20
|
|
20
21
|
attr_accessor :logger
|
21
|
-
attr_reader :connection
|
22
|
+
attr_reader :options, :connection
|
22
23
|
|
23
24
|
def logger
|
24
|
-
@logger
|
25
|
+
@logger ||= Logger.new(STDOUT).tap {|l| l.level = Logger::INFO}
|
25
26
|
end
|
26
27
|
|
28
|
+
# Hash with:
|
29
|
+
# - bucket
|
30
|
+
# - tenant_name
|
31
|
+
# - username
|
32
|
+
# - password
|
33
|
+
# - auth_url
|
34
|
+
#
|
35
|
+
# - max_age (optional, default: nil)
|
36
|
+
# - verify_ssl (optional, default: false)
|
37
|
+
# - timeout (in seconds. Optional, default: nil)
|
38
|
+
#
|
27
39
|
def configure opts = {}
|
28
|
-
@
|
40
|
+
@options = OpenStruct.new({verify_ssl: false}.merge(opts))
|
41
|
+
|
42
|
+
if @options.max_age and not @options.max_age.is_a?(Numeric)
|
43
|
+
raise Exceptions::ConfigurationError.new "max_age should be an Integer"
|
44
|
+
end
|
45
|
+
|
46
|
+
@connection = Connection.new
|
29
47
|
end
|
30
48
|
|
31
49
|
def sync dir_path
|
32
|
-
connection.connect!
|
33
50
|
Sync.new.execute(dir_path)
|
34
51
|
end
|
35
52
|
|
@@ -7,9 +7,9 @@
|
|
7
7
|
"type" : "object-store",
|
8
8
|
"endpoints" : [
|
9
9
|
{
|
10
|
-
"publicURL" : "http://public
|
11
|
-
"internalURL" : "http://internal
|
12
|
-
"adminURL" : "http://api
|
10
|
+
"publicURL" : "http://public-url-com",
|
11
|
+
"internalURL" : "http://internal-url-com",
|
12
|
+
"adminURL" : "http://api-url-com",
|
13
13
|
"region" : "RegionOne",
|
14
14
|
"id" : "1"
|
15
15
|
}
|
@@ -21,9 +21,9 @@
|
|
21
21
|
"type" : "identity",
|
22
22
|
"endpoints" : [
|
23
23
|
{
|
24
|
-
"publicURL" : "http://auth
|
25
|
-
"internalURL" : "https://auth
|
26
|
-
"adminURL" : "https://auth
|
24
|
+
"publicURL" : "http://auth-url-com:123/v2.0",
|
25
|
+
"internalURL" : "https://auth-url-com:123/v2.0",
|
26
|
+
"adminURL" : "https://auth-url-com:321/v2.0",
|
27
27
|
"region" : "RegionOne",
|
28
28
|
"id" : "2"
|
29
29
|
}
|
@@ -0,0 +1,293 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "nightcrawler_swift/cli"
|
3
|
+
|
4
|
+
describe NightcrawlerSwift::CLI do
|
5
|
+
|
6
|
+
let :config_dir do
|
7
|
+
File.expand_path(File.join(File.dirname(__FILE__), "../../fixtures"))
|
8
|
+
end
|
9
|
+
|
10
|
+
let :config_file do
|
11
|
+
File.join(config_dir, NightcrawlerSwift::CLI::CONFIG_FILE)
|
12
|
+
end
|
13
|
+
|
14
|
+
let :cache_file do
|
15
|
+
File.join(config_dir, NightcrawlerSwift::CLI::CACHE_FILE)
|
16
|
+
end
|
17
|
+
|
18
|
+
let :connection_success_json do
|
19
|
+
JSON.parse File.read(File.join(File.dirname(__FILE__), "../..", "fixtures/auth_success.json"))
|
20
|
+
end
|
21
|
+
|
22
|
+
let :opts do
|
23
|
+
{
|
24
|
+
"bucket" => "my-bucket-name",
|
25
|
+
"tenant_name" => "tenant_username1",
|
26
|
+
"username" => "username1",
|
27
|
+
"password" => "some-pass",
|
28
|
+
"auth_url" => "https://auth-url-com:123/v2.0/tokens"
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
subject do
|
33
|
+
NightcrawlerSwift::CLI.new argv.dup
|
34
|
+
end
|
35
|
+
|
36
|
+
before do
|
37
|
+
allow(subject).to receive(:user_home_dir).and_return(config_dir)
|
38
|
+
end
|
39
|
+
|
40
|
+
after do
|
41
|
+
File.delete(config_file) if File.exist?(config_file)
|
42
|
+
File.delete(cache_file) if File.exist?(cache_file)
|
43
|
+
end
|
44
|
+
|
45
|
+
shared_examples "CLI with default options" do
|
46
|
+
before do
|
47
|
+
File.open(config_file, "w") {|f| f.write(opts.to_json)}
|
48
|
+
allow(subject).to receive(:execute_command)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "points to a config file in the user home dir" do
|
52
|
+
subject.run
|
53
|
+
path = File.join(config_dir, NightcrawlerSwift::CLI::CONFIG_FILE)
|
54
|
+
expect(subject.options.config_file).to eql File.expand_path(path)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "points to a cache file in the uder home dir" do
|
58
|
+
subject.run
|
59
|
+
path = File.join(config_dir, NightcrawlerSwift::CLI::CACHE_FILE)
|
60
|
+
expect(subject.options.cache_file).to eql File.expand_path(path)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
shared_examples "CLI with parsed parameters" do
|
65
|
+
context "--version or -v" do
|
66
|
+
it "prints the version number" do
|
67
|
+
subject.argv << "-v"
|
68
|
+
expect(subject).to receive(:log).with(NightcrawlerSwift::VERSION)
|
69
|
+
expect { subject.run }.to raise_error SystemExit
|
70
|
+
|
71
|
+
expect(subject).to receive(:log).with(NightcrawlerSwift::VERSION)
|
72
|
+
subject.argv = (argv << "--version")
|
73
|
+
expect { subject.run }.to raise_error SystemExit
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "--help or -h" do
|
78
|
+
before do
|
79
|
+
subject.send :configure_default_options
|
80
|
+
subject.send :configure_opt_parser
|
81
|
+
|
82
|
+
allow(subject).to receive(:configure_default_options)
|
83
|
+
allow(subject).to receive(:configure_opt_parser)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "prints the help" do
|
87
|
+
subject.argv << "-h"
|
88
|
+
expect(subject).to receive(:log).with(subject.opt_parser.help)
|
89
|
+
expect { subject.run }.to raise_error SystemExit
|
90
|
+
|
91
|
+
expect(subject).to receive(:log).with(subject.opt_parser.help)
|
92
|
+
subject.argv = (argv << "--help")
|
93
|
+
expect { subject.run }.to raise_error SystemExit
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "--config or -c" do
|
98
|
+
let :config_file do
|
99
|
+
File.join(config_dir, "#{NightcrawlerSwift::CLI::CONFIG_FILE}-test")
|
100
|
+
end
|
101
|
+
|
102
|
+
before do
|
103
|
+
allow(subject).to receive(:execute_command)
|
104
|
+
allow(subject).to receive(:log)
|
105
|
+
File.open(config_file, "w") {|f| f.write("test")}
|
106
|
+
end
|
107
|
+
|
108
|
+
after do
|
109
|
+
File.delete(config_file) if File.exist?(config_file)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "configures the config_file" do
|
113
|
+
subject.argv << "-c #{config_file}"
|
114
|
+
subject.run
|
115
|
+
expect(subject.options.config_file).to eql config_file
|
116
|
+
|
117
|
+
subject.argv = (argv << "--config=#{config_file}")
|
118
|
+
subject.run
|
119
|
+
expect(subject.options.config_file).to eql config_file
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
shared_examples "CLI that creates a sample config file" do
|
125
|
+
before do
|
126
|
+
allow(subject).to receive(:execute_command)
|
127
|
+
allow(subject).to receive(:log)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "creates a sample config file" do
|
131
|
+
expect(File.exist?(config_file)).to eql false
|
132
|
+
expect { subject.run }.to raise_error SystemExit
|
133
|
+
expect(File.exist?(config_file)).to eql true
|
134
|
+
expect(File.read(config_file)).to eql subject.send(:sample_rcfile)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "flags as not configured" do
|
138
|
+
expect { subject.run }.to raise_error SystemExit
|
139
|
+
expect(subject.options.configured).to eql false
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
shared_examples "CLI that uses the configured command" do
|
144
|
+
let :connection do
|
145
|
+
NightcrawlerSwift::Connection.new
|
146
|
+
end
|
147
|
+
|
148
|
+
before do
|
149
|
+
allow(subject).to receive(command_method)
|
150
|
+
allow(NightcrawlerSwift).to receive(:connection).and_return(connection)
|
151
|
+
File.open(config_file, "w") {|f| f.write(opts.to_json)}
|
152
|
+
end
|
153
|
+
|
154
|
+
it "configures NightcrawlerSwift" do
|
155
|
+
expect(NightcrawlerSwift).to receive(:configure).with opts
|
156
|
+
subject.run
|
157
|
+
end
|
158
|
+
|
159
|
+
context "when exist a previous valid authorization" do
|
160
|
+
it "reuses that" do
|
161
|
+
File.open(cache_file, "w") {|f| f.write(connection_success_json.to_json)}
|
162
|
+
expect(File.exist?(cache_file)).to eql true
|
163
|
+
|
164
|
+
expect(connection).to receive(:configure).and_call_original
|
165
|
+
subject.run
|
166
|
+
expect(connection.auth_response).to eql(OpenStruct.new(connection_success_json))
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
it "writes the auth_response into cache file" do
|
171
|
+
expect(File.exist?(cache_file)).to eql false
|
172
|
+
expect(connection).to receive(:auth_response).and_return(OpenStruct.new(connection_success_json))
|
173
|
+
subject.run
|
174
|
+
expect(File.exist?(cache_file)).to eql true
|
175
|
+
expect(File.read(cache_file)).to eql connection_success_json.to_json
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "command list" do
|
180
|
+
let(:argv) { ["list"] }
|
181
|
+
let(:command) { NightcrawlerSwift::List.new }
|
182
|
+
let(:command_method) { :command_list }
|
183
|
+
let :result do
|
184
|
+
[{
|
185
|
+
"hash"=>"c9df50d4a29542f8b6d426a50c72b3de",
|
186
|
+
"last_modified"=>"2014-08-27T19:35:46.053560",
|
187
|
+
"bytes"=>4994,
|
188
|
+
"name"=>"assets/file.png",
|
189
|
+
"content_type"=>"image/png"
|
190
|
+
}]
|
191
|
+
end
|
192
|
+
|
193
|
+
it_behaves_like "CLI with default options"
|
194
|
+
it_behaves_like "CLI with parsed parameters"
|
195
|
+
it_behaves_like "CLI that creates a sample config file"
|
196
|
+
it_behaves_like "CLI that uses the configured command"
|
197
|
+
|
198
|
+
context "when executing the command" do
|
199
|
+
before do
|
200
|
+
File.open(config_file, "w") {|f| f.write(opts.to_json)}
|
201
|
+
end
|
202
|
+
|
203
|
+
it "lists all files in the bucket/container configured" do
|
204
|
+
expect(NightcrawlerSwift::List).to receive(:new).and_return(command)
|
205
|
+
expect(command).to receive(:execute).and_return(result)
|
206
|
+
expect(subject).to receive(:log).with(result.first["name"])
|
207
|
+
subject.run
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe "command download" do
|
213
|
+
let(:filepath) { "testfile.txt" }
|
214
|
+
let(:argv) { ["download", filepath] }
|
215
|
+
let(:command) { NightcrawlerSwift::Download.new }
|
216
|
+
let(:command_method) { :command_download }
|
217
|
+
|
218
|
+
it_behaves_like "CLI with default options"
|
219
|
+
it_behaves_like "CLI with parsed parameters"
|
220
|
+
it_behaves_like "CLI that creates a sample config file"
|
221
|
+
it_behaves_like "CLI that uses the configured command"
|
222
|
+
|
223
|
+
context "when executing the command" do
|
224
|
+
before do
|
225
|
+
File.open(config_file, "w") {|f| f.write(opts.to_json)}
|
226
|
+
end
|
227
|
+
|
228
|
+
it "downloads the file" do
|
229
|
+
expect(NightcrawlerSwift::Download).to receive(:new).and_return(command)
|
230
|
+
expect(command).to receive(:execute).with(filepath).and_return("test-content")
|
231
|
+
expect(subject).to receive(:log).with("test-content")
|
232
|
+
subject.run
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe "command upload" do
|
238
|
+
let(:swiftpath) { "testfile.txt" }
|
239
|
+
let(:realpath) { File.join(config_dir, swiftpath) }
|
240
|
+
let(:argv) { ["upload", realpath, swiftpath] }
|
241
|
+
let(:command) { NightcrawlerSwift::Upload.new }
|
242
|
+
let(:command_method) { :command_upload }
|
243
|
+
|
244
|
+
it_behaves_like "CLI with default options"
|
245
|
+
it_behaves_like "CLI with parsed parameters"
|
246
|
+
it_behaves_like "CLI that creates a sample config file"
|
247
|
+
it_behaves_like "CLI that uses the configured command"
|
248
|
+
|
249
|
+
context "when executing the command" do
|
250
|
+
before do
|
251
|
+
File.open(config_file, "w") {|f| f.write(opts.to_json)}
|
252
|
+
File.open(realpath, "w") {|f| f.write("test") }
|
253
|
+
end
|
254
|
+
|
255
|
+
after do
|
256
|
+
File.delete(realpath) if File.exist?(realpath)
|
257
|
+
end
|
258
|
+
|
259
|
+
it "uploads the file" do
|
260
|
+
expect(NightcrawlerSwift::Upload).to receive(:new).and_return(command)
|
261
|
+
expect(command).to receive(:execute).with(swiftpath, instance_of(File)).and_return(true)
|
262
|
+
expect(subject).to receive(:log).with("success")
|
263
|
+
subject.run
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
describe "command delete" do
|
269
|
+
let(:filepath) { "testfile.txt" }
|
270
|
+
let(:argv) { ["delete", filepath] }
|
271
|
+
let(:command) { NightcrawlerSwift::Delete.new }
|
272
|
+
let(:command_method) { :command_delete }
|
273
|
+
|
274
|
+
it_behaves_like "CLI with default options"
|
275
|
+
it_behaves_like "CLI with parsed parameters"
|
276
|
+
it_behaves_like "CLI that creates a sample config file"
|
277
|
+
it_behaves_like "CLI that uses the configured command"
|
278
|
+
|
279
|
+
context "when executing the command" do
|
280
|
+
before do
|
281
|
+
File.open(config_file, "w") {|f| f.write(opts.to_json)}
|
282
|
+
end
|
283
|
+
|
284
|
+
it "downloads the file" do
|
285
|
+
expect(NightcrawlerSwift::Delete).to receive(:new).and_return(command)
|
286
|
+
expect(command).to receive(:execute).with(filepath).and_return(true)
|
287
|
+
expect(subject).to receive(:log).with("success")
|
288
|
+
subject.run
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
end
|