copycopter_client 1.1.2 → 2.0.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.
- data/.gitignore +1 -0
- data/.travis.yml +9 -0
- data/Appraisals +10 -10
- data/Gemfile +1 -1
- data/Gemfile.lock +1 -1
- data/MIT-LICENSE +1 -1
- data/README.md +44 -37
- data/Rakefile +5 -3
- data/copycopter_client.gemspec +27 -30
- data/features/step_definitions/rails_steps.rb +1 -0
- data/gemfiles/2.3.gemfile +1 -1
- data/gemfiles/2.3.gemfile.lock +2 -2
- data/gemfiles/3.0.gemfile +1 -1
- data/gemfiles/3.0.gemfile.lock +29 -29
- data/gemfiles/3.1.gemfile +1 -1
- data/gemfiles/3.1.gemfile.lock +69 -67
- data/lib/copycopter_client.rb +14 -4
- data/lib/copycopter_client/cache.rb +53 -15
- data/lib/copycopter_client/client.rb +20 -17
- data/lib/copycopter_client/configuration.rb +30 -26
- data/lib/copycopter_client/version.rb +2 -3
- data/lib/tasks/copycopter_client_tasks.rake +13 -0
- data/spec/copycopter_client/cache_spec.rb +65 -0
- data/spec/copycopter_client/client_spec.rb +22 -23
- data/spec/copycopter_client/configuration_spec.rb +75 -77
- data/spec/spec_helper.rb +5 -5
- data/spec/support/fake_client.rb +6 -2
- data/spec/support/fake_copycopter_app.rb +41 -30
- metadata +152 -228
- data/.bundle/config +0 -2
- data/AddTrustExternalCARoot.crt +0 -25
- data/CONTRIBUTING.md +0 -38
@@ -18,7 +18,7 @@ describe CopycopterClient do
|
|
18
18
|
build_client(config)
|
19
19
|
end
|
20
20
|
|
21
|
-
describe
|
21
|
+
describe 'opening a connection' do
|
22
22
|
let(:config) { CopycopterClient::Configuration.new }
|
23
23
|
let(:http) { Net::HTTP.new(config.host, config.port) }
|
24
24
|
|
@@ -26,37 +26,36 @@ describe CopycopterClient do
|
|
26
26
|
Net::HTTP.stubs(:new => http)
|
27
27
|
end
|
28
28
|
|
29
|
-
it
|
29
|
+
it 'should timeout when connecting' do
|
30
30
|
project = add_project
|
31
31
|
client = build_client(:api_key => project.api_key, :http_open_timeout => 4)
|
32
32
|
client.download { |ignore| }
|
33
33
|
http.open_timeout.should == 4
|
34
34
|
end
|
35
35
|
|
36
|
-
it
|
36
|
+
it 'should timeout when reading' do
|
37
37
|
project = add_project
|
38
38
|
client = build_client(:api_key => project.api_key, :http_read_timeout => 4)
|
39
39
|
client.download { |ignore| }
|
40
40
|
http.read_timeout.should == 4
|
41
41
|
end
|
42
42
|
|
43
|
-
it
|
43
|
+
it 'uses verified ssl when secure' do
|
44
44
|
project = add_project
|
45
45
|
client = build_client(:api_key => project.api_key, :secure => true)
|
46
46
|
client.download { |ignore| }
|
47
47
|
http.use_ssl?.should == true
|
48
48
|
http.verify_mode.should == OpenSSL::SSL::VERIFY_PEER
|
49
|
-
http.ca_file.should == CopycopterClient::Configuration::CA_FILE
|
50
49
|
end
|
51
50
|
|
52
|
-
it
|
51
|
+
it 'does not use ssl when insecure' do
|
53
52
|
project = add_project
|
54
53
|
client = build_client(:api_key => project.api_key, :secure => false)
|
55
54
|
client.download { |ignore| }
|
56
55
|
http.use_ssl?.should == false
|
57
56
|
end
|
58
57
|
|
59
|
-
it
|
58
|
+
it 'wraps HTTP errors with ConnectionError' do
|
60
59
|
errors = [
|
61
60
|
Timeout::Error.new,
|
62
61
|
Errno::EINVAL.new,
|
@@ -81,39 +80,39 @@ describe CopycopterClient do
|
|
81
80
|
end
|
82
81
|
end
|
83
82
|
|
84
|
-
it
|
83
|
+
it 'handles 500 errors from downloads with ConnectionError' do
|
85
84
|
client = build_client(:api_key => 'raise_error')
|
86
85
|
expect { client.download { |ignore| } }.
|
87
86
|
to raise_error(CopycopterClient::ConnectionError)
|
88
87
|
end
|
89
88
|
|
90
|
-
it
|
89
|
+
it 'handles 500 errors from uploads with ConnectionError' do
|
91
90
|
client = build_client(:api_key => 'raise_error')
|
92
91
|
expect { client.upload({}) }.to raise_error(CopycopterClient::ConnectionError)
|
93
92
|
end
|
94
93
|
|
95
|
-
it
|
94
|
+
it 'handles 404 errors from downloads with ConnectionError' do
|
96
95
|
client = build_client(:api_key => 'bogus')
|
97
96
|
expect { client.download { |ignore| } }.
|
98
97
|
to raise_error(CopycopterClient::InvalidApiKey)
|
99
98
|
end
|
100
99
|
|
101
|
-
it
|
100
|
+
it 'handles 404 errors from uploads with ConnectionError' do
|
102
101
|
client = build_client(:api_key => 'bogus')
|
103
102
|
expect { client.upload({}) }.to raise_error(CopycopterClient::InvalidApiKey)
|
104
103
|
end
|
105
104
|
end
|
106
105
|
|
107
|
-
it
|
106
|
+
it 'downloads published blurbs for an existing project' do
|
108
107
|
project = add_project
|
109
108
|
project.update({
|
110
109
|
'draft' => {
|
111
|
-
'key.one' =>
|
112
|
-
'key.three' =>
|
110
|
+
'key.one' => 'unexpected one',
|
111
|
+
'key.three' => 'unexpected three'
|
113
112
|
},
|
114
113
|
'published' => {
|
115
|
-
'key.one' =>
|
116
|
-
'key.two' =>
|
114
|
+
'key.one' => 'expected one',
|
115
|
+
'key.two' => 'expected two'
|
117
116
|
}
|
118
117
|
})
|
119
118
|
client = build_client(:api_key => project.api_key, :public => true)
|
@@ -127,23 +126,23 @@ describe CopycopterClient do
|
|
127
126
|
}
|
128
127
|
end
|
129
128
|
|
130
|
-
it
|
129
|
+
it 'logs that it performed a download' do
|
131
130
|
logger = FakeLogger.new
|
132
131
|
client = build_client_with_project(:logger => logger)
|
133
132
|
client.download { |ignore| }
|
134
|
-
logger.should have_entry(:info,
|
133
|
+
logger.should have_entry(:info, 'Downloaded translations')
|
135
134
|
end
|
136
135
|
|
137
|
-
it
|
136
|
+
it 'downloads draft blurbs for an existing project' do
|
138
137
|
project = add_project
|
139
138
|
project.update({
|
140
139
|
'draft' => {
|
141
|
-
'key.one' =>
|
142
|
-
'key.two' =>
|
140
|
+
'key.one' => 'expected one',
|
141
|
+
'key.two' => 'expected two'
|
143
142
|
},
|
144
143
|
'published' => {
|
145
|
-
'key.one' =>
|
146
|
-
'key.three' =>
|
144
|
+
'key.one' => 'unexpected one',
|
145
|
+
'key.three' => 'unexpected three'
|
147
146
|
}
|
148
147
|
})
|
149
148
|
client = build_client(:api_key => project.api_key, :public => false)
|
@@ -25,48 +25,42 @@ describe CopycopterClient::Configuration do
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
it { should have_config_option(:proxy_host).
|
29
|
-
it { should have_config_option(:proxy_port).
|
30
|
-
it { should have_config_option(:proxy_user).
|
31
|
-
it { should have_config_option(:proxy_pass).
|
32
|
-
it { should have_config_option(:environment_name).
|
33
|
-
it { should have_config_option(:client_version).
|
34
|
-
it { should have_config_option(:client_name).
|
35
|
-
it { should have_config_option(:client_url).
|
36
|
-
it { should have_config_option(:secure).
|
37
|
-
it { should have_config_option(:host).
|
38
|
-
it { should have_config_option(:http_open_timeout).
|
39
|
-
it { should have_config_option(:http_read_timeout).
|
40
|
-
it { should have_config_option(:port).
|
28
|
+
it { should have_config_option(:proxy_host).overridable.default(nil) }
|
29
|
+
it { should have_config_option(:proxy_port).overridable.default(nil) }
|
30
|
+
it { should have_config_option(:proxy_user).overridable.default(nil) }
|
31
|
+
it { should have_config_option(:proxy_pass).overridable.default(nil) }
|
32
|
+
it { should have_config_option(:environment_name).overridable.default(nil) }
|
33
|
+
it { should have_config_option(:client_version).overridable.default(CopycopterClient::VERSION) }
|
34
|
+
it { should have_config_option(:client_name).overridable.default('Copycopter Client') }
|
35
|
+
it { should have_config_option(:client_url).overridable.default('http://copycopter.com') }
|
36
|
+
it { should have_config_option(:secure).overridable.default(true) }
|
37
|
+
it { should have_config_option(:host).overridable.default('copycopter.com') }
|
38
|
+
it { should have_config_option(:http_open_timeout).overridable.default(2) }
|
39
|
+
it { should have_config_option(:http_read_timeout).overridable.default(5) }
|
40
|
+
it { should have_config_option(:port).overridable }
|
41
41
|
it { should have_config_option(:development_environments).overridable }
|
42
|
-
it { should have_config_option(:api_key).
|
43
|
-
it { should have_config_option(:polling_delay).
|
44
|
-
it { should have_config_option(:framework).
|
45
|
-
it { should have_config_option(:middleware).
|
46
|
-
it { should have_config_option(:client).
|
47
|
-
it { should have_config_option(:cache).
|
48
|
-
|
49
|
-
it
|
50
|
-
should have_config_option(:ca_file).
|
51
|
-
overridable.
|
52
|
-
default(File.join(PROJECT_ROOT, "AddTrustExternalCARoot.crt"))
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should provide default values for secure connections" do
|
42
|
+
it { should have_config_option(:api_key).overridable }
|
43
|
+
it { should have_config_option(:polling_delay).overridable.default(300) }
|
44
|
+
it { should have_config_option(:framework).overridable }
|
45
|
+
it { should have_config_option(:middleware).overridable }
|
46
|
+
it { should have_config_option(:client).overridable }
|
47
|
+
it { should have_config_option(:cache).overridable }
|
48
|
+
|
49
|
+
it 'should provide default values for secure connections' do
|
56
50
|
config = CopycopterClient::Configuration.new
|
57
51
|
config.secure = true
|
58
52
|
config.port.should == 443
|
59
53
|
config.protocol.should == 'https'
|
60
54
|
end
|
61
55
|
|
62
|
-
it
|
56
|
+
it 'should provide default values for insecure connections' do
|
63
57
|
config = CopycopterClient::Configuration.new
|
64
58
|
config.secure = false
|
65
59
|
config.port.should == 80
|
66
60
|
config.protocol.should == 'http'
|
67
61
|
end
|
68
62
|
|
69
|
-
it
|
63
|
+
it 'should not cache inferred ports' do
|
70
64
|
config = CopycopterClient::Configuration.new
|
71
65
|
config.secure = false
|
72
66
|
config.port
|
@@ -74,42 +68,44 @@ describe CopycopterClient::Configuration do
|
|
74
68
|
config.port.should == 443
|
75
69
|
end
|
76
70
|
|
77
|
-
it
|
71
|
+
it 'should act like a hash' do
|
78
72
|
config = CopycopterClient::Configuration.new
|
79
73
|
hash = config.to_hash
|
74
|
+
|
80
75
|
[:api_key, :environment_name, :host, :http_open_timeout,
|
81
76
|
:http_read_timeout, :client_name, :client_url, :client_version, :port,
|
82
77
|
:protocol, :proxy_host, :proxy_pass, :proxy_port, :proxy_user, :secure,
|
83
78
|
:development_environments, :logger, :framework, :ca_file].each do |option|
|
84
79
|
hash[option].should == config[option]
|
85
80
|
end
|
81
|
+
|
86
82
|
hash[:public].should == config.public?
|
87
83
|
end
|
88
84
|
|
89
|
-
it
|
85
|
+
it 'should be mergable' do
|
90
86
|
config = CopycopterClient::Configuration.new
|
91
87
|
hash = config.to_hash
|
92
88
|
config.merge(:key => 'value').should == hash.merge(:key => 'value')
|
93
89
|
end
|
94
90
|
|
95
|
-
it
|
91
|
+
it 'should use development and staging as development environments by default' do
|
96
92
|
config = CopycopterClient::Configuration.new
|
97
93
|
config.development_environments.should =~ %w(development staging)
|
98
94
|
end
|
99
95
|
|
100
|
-
it
|
96
|
+
it 'should use test and cucumber as test environments by default' do
|
101
97
|
config = CopycopterClient::Configuration.new
|
102
98
|
config.test_environments.should =~ %w(test cucumber)
|
103
99
|
end
|
104
100
|
|
105
|
-
it
|
101
|
+
it 'should be test in a test environment' do
|
106
102
|
config = CopycopterClient::Configuration.new
|
107
103
|
config.test_environments = %w(test)
|
108
104
|
config.environment_name = 'test'
|
109
105
|
config.should be_test
|
110
106
|
end
|
111
107
|
|
112
|
-
it
|
108
|
+
it 'should be public in a public environment' do
|
113
109
|
config = CopycopterClient::Configuration.new
|
114
110
|
config.development_environments = %w(development)
|
115
111
|
config.environment_name = 'production'
|
@@ -117,7 +113,7 @@ describe CopycopterClient::Configuration do
|
|
117
113
|
config.should_not be_development
|
118
114
|
end
|
119
115
|
|
120
|
-
it
|
116
|
+
it 'should be development in a development environment' do
|
121
117
|
config = CopycopterClient::Configuration.new
|
122
118
|
config.development_environments = %w(staging)
|
123
119
|
config.environment_name = 'staging'
|
@@ -125,13 +121,14 @@ describe CopycopterClient::Configuration do
|
|
125
121
|
config.should_not be_public
|
126
122
|
end
|
127
123
|
|
128
|
-
it
|
124
|
+
it 'should be public without an environment name' do
|
129
125
|
config = CopycopterClient::Configuration.new
|
130
126
|
config.should be_public
|
131
127
|
end
|
132
128
|
|
133
|
-
it
|
129
|
+
it 'should yield and save a configuration when configuring' do
|
134
130
|
yielded_configuration = nil
|
131
|
+
|
135
132
|
CopycopterClient.configure(false) do |config|
|
136
133
|
yielded_configuration = config
|
137
134
|
end
|
@@ -140,49 +137,50 @@ describe CopycopterClient::Configuration do
|
|
140
137
|
CopycopterClient.configuration.should == yielded_configuration
|
141
138
|
end
|
142
139
|
|
143
|
-
it
|
140
|
+
it 'does not apply the configuration when asked not to' do
|
144
141
|
logger = FakeLogger.new
|
145
142
|
CopycopterClient.configure(false) { |config| config.logger = logger }
|
146
143
|
CopycopterClient.configuration.should_not be_applied
|
147
144
|
logger.entries[:info].should be_empty
|
148
145
|
end
|
149
146
|
|
150
|
-
it
|
147
|
+
it 'should not remove existing config options when configuring twice' do
|
151
148
|
first_config = nil
|
149
|
+
|
152
150
|
CopycopterClient.configure(false) do |config|
|
153
151
|
first_config = config
|
154
152
|
end
|
153
|
+
|
155
154
|
CopycopterClient.configure(false) do |config|
|
156
155
|
config.should == first_config
|
157
156
|
end
|
158
157
|
end
|
159
158
|
|
160
|
-
it
|
159
|
+
it 'starts out unapplied' do
|
161
160
|
CopycopterClient::Configuration.new.should_not be_applied
|
162
161
|
end
|
163
162
|
|
164
|
-
it
|
163
|
+
it 'logs to $stdout by default' do
|
165
164
|
logger = FakeLogger.new
|
166
|
-
Logger.stubs
|
167
|
-
|
165
|
+
Logger.stubs :new => logger
|
168
166
|
config = CopycopterClient::Configuration.new
|
169
167
|
Logger.should have_received(:new).with($stdout)
|
170
168
|
config.logger.original_logger.should == logger
|
171
169
|
end
|
172
170
|
|
173
|
-
it
|
171
|
+
it 'generates environment info without a framework' do
|
174
172
|
subject.environment_name = 'production'
|
175
173
|
subject.environment_info.should == "[Ruby: #{RUBY_VERSION}] [Env: production]"
|
176
174
|
end
|
177
175
|
|
178
|
-
it
|
176
|
+
it 'generates environment info with a framework' do
|
179
177
|
subject.environment_name = 'production'
|
180
178
|
subject.framework = 'Sinatra: 1.0.0'
|
181
179
|
subject.environment_info.
|
182
180
|
should == "[Ruby: #{RUBY_VERSION}] [Sinatra: 1.0.0] [Env: production]"
|
183
181
|
end
|
184
182
|
|
185
|
-
it
|
183
|
+
it 'prefixes log entries' do
|
186
184
|
logger = FakeLogger.new
|
187
185
|
config = CopycopterClient::Configuration.new
|
188
186
|
|
@@ -194,53 +192,53 @@ describe CopycopterClient::Configuration do
|
|
194
192
|
end
|
195
193
|
end
|
196
194
|
|
197
|
-
share_examples_for
|
195
|
+
share_examples_for 'applied configuration' do
|
196
|
+
subject { CopycopterClient::Configuration.new }
|
198
197
|
let(:backend) { stub('i18n-backend') }
|
199
|
-
let(:cache)
|
200
|
-
let(:client)
|
201
|
-
let(:
|
198
|
+
let(:cache) { stub('cache') }
|
199
|
+
let(:client) { stub('client') }
|
200
|
+
let(:logger) { FakeLogger.new }
|
201
|
+
let(:poller) { stub('poller') }
|
202
202
|
let(:process_guard) { stub('process_guard', :start => nil) }
|
203
|
-
let(:logger) { FakeLogger.new }
|
204
|
-
subject { CopycopterClient::Configuration.new }
|
205
203
|
|
206
204
|
before do
|
207
|
-
CopycopterClient::I18nBackend.stubs
|
208
|
-
CopycopterClient::Client.stubs
|
209
|
-
CopycopterClient::Cache.stubs
|
210
|
-
CopycopterClient::Poller.stubs
|
211
|
-
CopycopterClient::ProcessGuard.stubs
|
205
|
+
CopycopterClient::I18nBackend.stubs :new => backend
|
206
|
+
CopycopterClient::Client.stubs :new => client
|
207
|
+
CopycopterClient::Cache.stubs :new => cache
|
208
|
+
CopycopterClient::Poller.stubs :new => poller
|
209
|
+
CopycopterClient::ProcessGuard.stubs :new => process_guard
|
212
210
|
subject.logger = logger
|
213
211
|
apply
|
214
212
|
end
|
215
213
|
|
216
214
|
it { should be_applied }
|
217
215
|
|
218
|
-
it
|
216
|
+
it 'builds and assigns an I18n backend' do
|
219
217
|
CopycopterClient::I18nBackend.should have_received(:new).with(cache)
|
220
218
|
I18n.backend.should == backend
|
221
219
|
end
|
222
220
|
|
223
|
-
it
|
221
|
+
it 'builds and assigns a poller' do
|
224
222
|
CopycopterClient::Poller.should have_received(:new).with(cache, subject.to_hash)
|
225
223
|
end
|
226
224
|
|
227
|
-
it
|
225
|
+
it 'builds a process guard' do
|
228
226
|
CopycopterClient::ProcessGuard.should have_received(:new).
|
229
227
|
with(cache, poller, subject.to_hash)
|
230
228
|
end
|
231
229
|
|
232
|
-
it
|
230
|
+
it 'logs that it is ready' do
|
233
231
|
logger.should have_entry(:info, "Client #{CopycopterClient::VERSION} ready")
|
234
232
|
end
|
235
233
|
|
236
|
-
it
|
234
|
+
it 'logs environment info' do
|
237
235
|
logger.should have_entry(:info, "Environment Info: #{subject.environment_info}")
|
238
236
|
end
|
239
237
|
end
|
240
238
|
|
241
|
-
describe CopycopterClient::Configuration,
|
242
|
-
it_should_behave_like
|
243
|
-
it
|
239
|
+
describe CopycopterClient::Configuration, 'applied when testing' do
|
240
|
+
it_should_behave_like 'applied configuration' do
|
241
|
+
it 'does not start the process guard' do
|
244
242
|
process_guard.should have_received(:start).never
|
245
243
|
end
|
246
244
|
end
|
@@ -251,9 +249,9 @@ describe CopycopterClient::Configuration, "applied when testing" do
|
|
251
249
|
end
|
252
250
|
end
|
253
251
|
|
254
|
-
describe CopycopterClient::Configuration,
|
255
|
-
it_should_behave_like
|
256
|
-
it
|
252
|
+
describe CopycopterClient::Configuration, 'applied when not testing' do
|
253
|
+
it_should_behave_like 'applied configuration' do
|
254
|
+
it 'starts the process guard' do
|
257
255
|
process_guard.should have_received(:start)
|
258
256
|
end
|
259
257
|
end
|
@@ -264,9 +262,9 @@ describe CopycopterClient::Configuration, "applied when not testing" do
|
|
264
262
|
end
|
265
263
|
end
|
266
264
|
|
267
|
-
describe CopycopterClient::Configuration,
|
268
|
-
it_should_behave_like
|
269
|
-
it
|
265
|
+
describe CopycopterClient::Configuration, 'applied when developing with middleware' do
|
266
|
+
it_should_behave_like 'applied configuration' do
|
267
|
+
it 'adds the sync middleware' do
|
270
268
|
middleware.should include(CopycopterClient::RequestSync)
|
271
269
|
end
|
272
270
|
end
|
@@ -280,8 +278,8 @@ describe CopycopterClient::Configuration, "applied when developing with middlewa
|
|
280
278
|
end
|
281
279
|
end
|
282
280
|
|
283
|
-
describe CopycopterClient::Configuration,
|
284
|
-
it_should_behave_like
|
281
|
+
describe CopycopterClient::Configuration, 'applied when developing without middleware' do
|
282
|
+
it_should_behave_like 'applied configuration'
|
285
283
|
|
286
284
|
def apply
|
287
285
|
subject.middleware = nil
|
@@ -290,8 +288,8 @@ describe CopycopterClient::Configuration, "applied when developing without middl
|
|
290
288
|
end
|
291
289
|
end
|
292
290
|
|
293
|
-
describe CopycopterClient::Configuration,
|
294
|
-
it_should_behave_like
|
291
|
+
describe CopycopterClient::Configuration, 'applied with middleware when not developing' do
|
292
|
+
it_should_behave_like 'applied configuration'
|
295
293
|
|
296
294
|
let(:middleware) { MiddlewareStack.new }
|
297
295
|
|
@@ -301,7 +299,7 @@ describe CopycopterClient::Configuration, "applied with middleware when not deve
|
|
301
299
|
subject.apply
|
302
300
|
end
|
303
301
|
|
304
|
-
it
|
302
|
+
it 'does not add the sync middleware' do
|
305
303
|
middleware.should_not include(CopycopterClient::RequestSync)
|
306
304
|
end
|
307
305
|
end
|