4me-sdk 1.1.8 → 1.2.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/4me-sdk.gemspec +1 -1
- data/Gemfile.lock +10 -12
- data/README.md +24 -23
- data/lib/sdk4me.rb +1 -0
- data/lib/sdk4me/client.rb +20 -9
- data/lib/sdk4me/client/version.rb +1 -1
- data/spec/lib/sdk4me/attachments_spec.rb +241 -222
- data/spec/lib/sdk4me/certificate_spec.rb +15 -1
- data/spec/lib/sdk4me/client_spec.rb +478 -471
- data/spec/lib/sdk4me/response_spec.rb +251 -230
- data/spec/lib/sdk4me_spec.rb +2 -2
- metadata +8 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dc85cfa0c6b08a248805e24e37b4fe0cde152c64d42443b72ca8db4e5cf2799a
|
|
4
|
+
data.tar.gz: ebfe8f4d1e32e791ef5d109ef6934aa3fa585a60df8cd1f4f000073993cc9a2f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e05769acff36f8c0ffc6758d4078217b4af13cd969814ee85699d0e84951c6b9d34d6d4b2d7fb0fddb2577a2a03b4aeda3b7c687d0ec62916ef8e712ce5224cc
|
|
7
|
+
data.tar.gz: 6cac609bb11b34d97086e701701d7f664ca24500cca943a948e7ce42d7650e2dd2c8f14a0a348dd6d0b2295c90257d1a39411ae0f2e7a8a67202396edf8dc31b
|
data/4me-sdk.gemspec
CHANGED
|
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
spec.add_development_dependency 'bundler', '~> 1'
|
|
35
35
|
spec.add_development_dependency 'rake', '~> 12'
|
|
36
36
|
spec.add_development_dependency 'rspec', '~> 3.3'
|
|
37
|
-
spec.add_development_dependency 'webmock', '~>
|
|
37
|
+
spec.add_development_dependency 'webmock', '~> 3'
|
|
38
38
|
spec.add_development_dependency 'simplecov', '~> 0'
|
|
39
39
|
|
|
40
40
|
end
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
4me-sdk (1.
|
|
4
|
+
4me-sdk (1.2.0)
|
|
5
5
|
activesupport (>= 4.2)
|
|
6
6
|
gem_config (>= 0.3)
|
|
7
7
|
mime-types (>= 3.0)
|
|
@@ -14,23 +14,22 @@ GEM
|
|
|
14
14
|
i18n (>= 0.7, < 2)
|
|
15
15
|
minitest (~> 5.1)
|
|
16
16
|
tzinfo (~> 1.1)
|
|
17
|
-
addressable (2.
|
|
18
|
-
public_suffix (>= 2.0.2, <
|
|
17
|
+
addressable (2.7.0)
|
|
18
|
+
public_suffix (>= 2.0.2, < 5.0)
|
|
19
19
|
concurrent-ruby (1.1.5)
|
|
20
|
-
crack (0.4.
|
|
21
|
-
safe_yaml (~> 1.0.0)
|
|
20
|
+
crack (0.4.4)
|
|
22
21
|
diff-lcs (1.3)
|
|
23
22
|
docile (1.3.1)
|
|
24
23
|
gem_config (0.3.1)
|
|
25
|
-
hashdiff (0.
|
|
24
|
+
hashdiff (1.0.1)
|
|
26
25
|
i18n (1.5.1)
|
|
27
26
|
concurrent-ruby (~> 1.0)
|
|
28
27
|
json (2.1.0)
|
|
29
28
|
mime-types (3.2.2)
|
|
30
29
|
mime-types-data (~> 3.2015)
|
|
31
30
|
mime-types-data (3.2019.0331)
|
|
32
|
-
minitest (5.
|
|
33
|
-
public_suffix (
|
|
31
|
+
minitest (5.13.0)
|
|
32
|
+
public_suffix (4.0.6)
|
|
34
33
|
rake (12.3.1)
|
|
35
34
|
rspec (3.8.0)
|
|
36
35
|
rspec-core (~> 3.8.0)
|
|
@@ -45,7 +44,6 @@ GEM
|
|
|
45
44
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
46
45
|
rspec-support (~> 3.8.0)
|
|
47
46
|
rspec-support (3.8.0)
|
|
48
|
-
safe_yaml (1.0.4)
|
|
49
47
|
simplecov (0.16.1)
|
|
50
48
|
docile (~> 1.1)
|
|
51
49
|
json (>= 1.8, < 3)
|
|
@@ -54,10 +52,10 @@ GEM
|
|
|
54
52
|
thread_safe (0.3.6)
|
|
55
53
|
tzinfo (1.2.5)
|
|
56
54
|
thread_safe (~> 0.1)
|
|
57
|
-
webmock (
|
|
55
|
+
webmock (3.9.1)
|
|
58
56
|
addressable (>= 2.3.6)
|
|
59
57
|
crack (>= 0.3.2)
|
|
60
|
-
hashdiff
|
|
58
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
|
61
59
|
|
|
62
60
|
PLATFORMS
|
|
63
61
|
ruby
|
|
@@ -68,7 +66,7 @@ DEPENDENCIES
|
|
|
68
66
|
rake (~> 12)
|
|
69
67
|
rspec (~> 3.3)
|
|
70
68
|
simplecov (~> 0)
|
|
71
|
-
webmock (~>
|
|
69
|
+
webmock (~> 3)
|
|
72
70
|
|
|
73
71
|
BUNDLED WITH
|
|
74
72
|
1.17.3
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Sdk4me::Client
|
|
2
2
|
|
|
3
|
-
Client for accessing the [4me REST API](
|
|
3
|
+
Client for accessing the [4me REST API](https://developer.4me.com/v1/)
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@ Or install it yourself as:
|
|
|
22
22
|
|
|
23
23
|
```
|
|
24
24
|
Sdk4me.configure do |config|
|
|
25
|
-
config.
|
|
25
|
+
config.access_token = 'd41f5868feb65fc87fa2311a473a8766ea38bc40'
|
|
26
26
|
config.account = 'my-sandbox'
|
|
27
27
|
config.logger = Rails.logger
|
|
28
28
|
...
|
|
@@ -32,17 +32,18 @@ end
|
|
|
32
32
|
All options available:
|
|
33
33
|
|
|
34
34
|
* _logger_: The [Ruby Logger](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html) instance, default: `Logger.new(STDOUT)`
|
|
35
|
-
* _host_: The [4me API host](
|
|
36
|
-
* _api_version_: The [4me API version](
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
35
|
+
* _host_: The [4me API host](https://developer.4me.com/v1/#service-url), default: 'https://api.4me.com'
|
|
36
|
+
* _api_version_: The [4me API version](https://developer.4me.com/v1/#service-url), default: 'v1'
|
|
37
|
+
* _access_token_: (**required**) The [4me access token](https://developer.4me.com/v1/#authentication)
|
|
38
|
+
* _api_token_: (**deprecated**) The [4me API token](https://developer.4me.com/v1/#api-tokens)
|
|
39
|
+
* _account_: Specify a [different account](https://developer.4me.com/v1/#multiple-accounts) to work with
|
|
40
|
+
* _source_: The [source](https://developer.4me.com/v1/general/source/) used when creating new records
|
|
40
41
|
* _max_retry_time_: maximum nr of seconds to retry a request on a failed response (default = 300 = 5 minutes)<br/>
|
|
41
42
|
The sleep time between retries starts at 2 seconds and doubles after each retry, i.e.
|
|
42
43
|
2, 6, 18, 54, 162, 486, 1458, ... seconds.<br/>
|
|
43
44
|
Set to 0 to prevent retries.
|
|
44
45
|
* _read_timeout_: [HTTP read timeout](http://ruby-doc.org/stdlib-2.0.0/libdoc/net/http/rdoc/Net/HTTP.html#method-i-read_timeout-3D) in seconds (default = 25)
|
|
45
|
-
* _block_at_rate_limit_: Set to `true` to block the request until the [rate limit](
|
|
46
|
+
* _block_at_rate_limit_: Set to `true` to block the request until the [rate limit](https://developer.4me.com/v1/#rate-limiting) is lifted, default: `true`<br/>
|
|
46
47
|
The `Retry-After` header is used to compute when the retry should be performed. If that moment is later than the _max_throttle_time_ the request will not be blocked and the throttled response is returned.
|
|
47
48
|
* _max_throttle_time_: maximum nr of seconds to retry a request on a rate limiter (default = 3660 = 1 hour and 1 minute)<br/>
|
|
48
49
|
* _proxy_host_: Define in case HTTP traffic needs to go through a proxy
|
|
@@ -70,7 +71,7 @@ Minimal example:
|
|
|
70
71
|
```
|
|
71
72
|
require 'sdk4me/client'
|
|
72
73
|
|
|
73
|
-
client = Sdk4me::Client.new(
|
|
74
|
+
client = Sdk4me::Client.new(access_token: '3a4e4590179263839...')
|
|
74
75
|
response = client.get('me')
|
|
75
76
|
puts response[:primary_email]
|
|
76
77
|
```
|
|
@@ -84,7 +85,7 @@ response = Sdk4me::Client.new.get('organizations/4321')
|
|
|
84
85
|
puts response[:name]
|
|
85
86
|
```
|
|
86
87
|
|
|
87
|
-
By default this call will return all [fields](
|
|
88
|
+
By default this call will return all [fields](https://developer.4me.com/v1/organizations/#fields) of the Organization.
|
|
88
89
|
|
|
89
90
|
The fields can be accessed using *symbols* and *strings*, and it is possible chain a number of keys in one go:
|
|
90
91
|
```
|
|
@@ -105,8 +106,8 @@ end
|
|
|
105
106
|
puts "Found #{count} organizations"
|
|
106
107
|
```
|
|
107
108
|
|
|
108
|
-
By default this call will return all [collection fields](
|
|
109
|
-
For more fields, check out the [field selection](
|
|
109
|
+
By default this call will return all [collection fields](https://developer.4me.com/v1/organizations/#collection-fields) for each Organization.
|
|
110
|
+
For more fields, check out the [field selection](https://developer.4me.com/v1/general/field_selection/#collection-of-resources) documentation.
|
|
110
111
|
|
|
111
112
|
The fields can be accessed using *symbols* and *strings*, and it is possible chain a number of keys in one go:
|
|
112
113
|
```
|
|
@@ -123,7 +124,7 @@ Note that an `Sdk4me::Exception` could be thrown in case one of the API requests
|
|
|
123
124
|
|
|
124
125
|
The `each` method [described above](#browse-through-a-collection-of-records) is the preferred way to work with collections of data.
|
|
125
126
|
|
|
126
|
-
If you really want to [paginate](
|
|
127
|
+
If you really want to [paginate](https://developer.4me.com/v1/general/pagination/) yourself, the `get` method is your friend.
|
|
127
128
|
|
|
128
129
|
```
|
|
129
130
|
@client = Sdk4me::Client.new
|
|
@@ -141,8 +142,8 @@ next_page = @client.get(response.pagination_link(:next))
|
|
|
141
142
|
last_page = @client.get(response.pagination_link(:last))
|
|
142
143
|
```
|
|
143
144
|
|
|
144
|
-
By default this call will return all [collection fields](
|
|
145
|
-
For more fields, check out the [field selection](
|
|
145
|
+
By default this call will return all [collection fields](https://developer.4me.com/v1/organizations/#collection-fields) for each Organization.
|
|
146
|
+
For more fields, check out the [field selection](https://developer.4me.com/v1/general/field_selection/#collection-of-resources) documentation.
|
|
146
147
|
|
|
147
148
|
The fields can be accessed using *symbols* and *strings*, and it is possible chain a number of keys in one go:
|
|
148
149
|
```
|
|
@@ -243,7 +244,7 @@ end
|
|
|
243
244
|
|
|
244
245
|
### Importing CSV files
|
|
245
246
|
|
|
246
|
-
4me also provides an [Import API](
|
|
247
|
+
4me also provides an [Import API](https://developer.4me.com/v1/import/). The 4me SDK Client can be used to upload files to that API.
|
|
247
248
|
|
|
248
249
|
```
|
|
249
250
|
response = Sdk4me::Client.new.import('\tmp\people.csv', 'people')
|
|
@@ -255,9 +256,9 @@ end
|
|
|
255
256
|
|
|
256
257
|
```
|
|
257
258
|
|
|
258
|
-
The second argument contains the [import type](
|
|
259
|
+
The second argument contains the [import type](https://developer.4me.com/v1/import/#parameters).
|
|
259
260
|
|
|
260
|
-
It is also possible to [monitor the progress](
|
|
261
|
+
It is also possible to [monitor the progress](https://developer.4me.com/v1/import/#import-progress) of the import and block until the import is complete. In that case you will need to add some exception handling to your code.
|
|
261
262
|
|
|
262
263
|
```
|
|
263
264
|
begin
|
|
@@ -277,7 +278,7 @@ Note that blocking for the import to finish is required when you import multiple
|
|
|
277
278
|
|
|
278
279
|
### Exporting CSV files
|
|
279
280
|
|
|
280
|
-
4me also provides an [Export API](
|
|
281
|
+
4me also provides an [Export API](https://developer.4me.com/v1/export/). The 4me SDK Client can be used to download (zipped) CSV files using that API.
|
|
281
282
|
|
|
282
283
|
```
|
|
283
284
|
response = Sdk4me::Client.new.export(['people', 'people_contact_details'], DateTime.new(2012,03,30,23,00,00))
|
|
@@ -289,10 +290,10 @@ end
|
|
|
289
290
|
|
|
290
291
|
```
|
|
291
292
|
|
|
292
|
-
The first argument contains the [export types](
|
|
293
|
+
The first argument contains the [export types](https://developer.4me.com/v1/export/#parameters).
|
|
293
294
|
The second argument is optional and limits the export to all changed records since the given time.
|
|
294
295
|
|
|
295
|
-
It is also possible to [monitor the progress](
|
|
296
|
+
It is also possible to [monitor the progress](https://developer.4me.com/v1/export/#export-progress) of the export and block until the export is complete. In that case you will need to add some exception handling to your code.
|
|
296
297
|
|
|
297
298
|
```
|
|
298
299
|
require 'open-uri'
|
|
@@ -314,7 +315,7 @@ Note that blocking for the export to finish is recommended as you will get direc
|
|
|
314
315
|
|
|
315
316
|
### Blocking
|
|
316
317
|
|
|
317
|
-
When the currently used API token hits the [4me rate limiter](
|
|
318
|
+
When the currently used API token hits the [4me rate limiter](https://developer.4me.com/v1/#rate-limiting) a HTTP 429 response is returned that specifies after how many seconds the rate limit will be lifted.
|
|
318
319
|
|
|
319
320
|
If that time lies within the _max_throttle_time_ the 4me SDK Client will wait and retry the action, if not, the throttled response will be returned. You can verify if a response was throttled using:
|
|
320
321
|
```
|
|
@@ -336,7 +337,7 @@ When exporting translations, the _locale_ parameter is required:
|
|
|
336
337
|
|
|
337
338
|
### Exception handling
|
|
338
339
|
|
|
339
|
-
The standard methods `get`, `post`, `put` and `delete` will always return a Response with an [error message](
|
|
340
|
+
The standard methods `get`, `post`, `put` and `delete` will always return a Response with an [error message](https://developer.4me.com/v1/#http-status-codes) in case something went wrong.
|
|
340
341
|
|
|
341
342
|
By calling `response.valid?` you will know if the action succeeded or not, and `response.message` provides additinal information in case the response was invalid.
|
|
342
343
|
|
data/lib/sdk4me.rb
CHANGED
data/lib/sdk4me/client.rb
CHANGED
|
@@ -27,7 +27,7 @@ module Sdk4me
|
|
|
27
27
|
#
|
|
28
28
|
# Shared configuration for all 4me SDK Clients:
|
|
29
29
|
# Sdk4me.configure do |config|
|
|
30
|
-
# config.
|
|
30
|
+
# config.access_token = 'd41f5868feb65fc87fa2311a473a8766ea38bc40'
|
|
31
31
|
# config.account = 'my-sandbox'
|
|
32
32
|
# ...
|
|
33
33
|
# end
|
|
@@ -39,11 +39,11 @@ module Sdk4me
|
|
|
39
39
|
# - logger: The Ruby Logger instance, default: Logger.new(STDOUT)
|
|
40
40
|
# - host: The 4me API host, default: 'https://api.4me.com'
|
|
41
41
|
# - api_version: The 4me API version, default: 'v1'
|
|
42
|
-
# -
|
|
42
|
+
# - access_token: *required* The 4me access token
|
|
43
43
|
# - account: Specify a different (trusted) account to work with
|
|
44
|
-
# @see
|
|
44
|
+
# @see https://developer.4me.com/v1/#multiple-accounts
|
|
45
45
|
# - source: The Source used when creating new records
|
|
46
|
-
# @see
|
|
46
|
+
# @see https://developer.4me.com/v1/general/source/
|
|
47
47
|
#
|
|
48
48
|
# - max_retry_time: maximum nr of seconds to wait for server to respond (default = 5400 = 1.5 hours)
|
|
49
49
|
# the sleep time between retries starts at 2 seconds and doubles after each retry
|
|
@@ -51,7 +51,7 @@ module Sdk4me
|
|
|
51
51
|
# one retry will always be performed unless you set the value to -1
|
|
52
52
|
# - read_timeout: HTTP GET read timeout in seconds (default = 25)
|
|
53
53
|
# - block_at_rate_limit: Set to +true+ to block the request until the rate limit is lifted, default: +false+
|
|
54
|
-
# @see
|
|
54
|
+
# @see https://developer.4me.com/v1/#rate-limiting
|
|
55
55
|
#
|
|
56
56
|
# - proxy_host: Define in case HTTP traffic needs to go through a proxy
|
|
57
57
|
# - proxy_port: Port of the proxy, defaults to 8080
|
|
@@ -59,12 +59,19 @@ module Sdk4me
|
|
|
59
59
|
# - proxy_password: Proxy password
|
|
60
60
|
def initialize(options = {})
|
|
61
61
|
@options = Sdk4me.configuration.current.merge(options)
|
|
62
|
-
[:host, :api_version
|
|
62
|
+
[:host, :api_version].each do |required_option|
|
|
63
63
|
raise ::Sdk4me::Exception.new("Missing required configuration option #{required_option}") if option(required_option).blank?
|
|
64
64
|
end
|
|
65
|
+
@logger = @options[:logger]
|
|
65
66
|
@ssl, @domain, @port = ssl_domain_port_path(option(:host))
|
|
67
|
+
unless option(:access_token).present?
|
|
68
|
+
if option(:api_token).blank?
|
|
69
|
+
raise ::Sdk4me::Exception.new("Missing required configuration option access_token")
|
|
70
|
+
else
|
|
71
|
+
@logger.info('Use of api_token is deprecated, consider switching to access_token instead.')
|
|
72
|
+
end
|
|
73
|
+
end
|
|
66
74
|
@ssl_verify_none = options[:ssl_verify_none]
|
|
67
|
-
@logger = @options[:logger]
|
|
68
75
|
end
|
|
69
76
|
|
|
70
77
|
# Retrieve an option
|
|
@@ -211,8 +218,12 @@ module Sdk4me
|
|
|
211
218
|
def expand_header(header = {})
|
|
212
219
|
header = DEFAULT_HEADER.merge(header)
|
|
213
220
|
header['X-4me-Account'] = option(:account) if option(:account)
|
|
214
|
-
|
|
215
|
-
|
|
221
|
+
if option(:access_token).present?
|
|
222
|
+
header['AUTHORIZATION'] = 'Bearer ' + option(:access_token)
|
|
223
|
+
else
|
|
224
|
+
token_and_password = option(:api_token).include?(':') ? option(:api_token) : "#{option(:api_token)}:x"
|
|
225
|
+
header['AUTHORIZATION'] = 'Basic ' + [token_and_password].pack('m*').gsub(/\s/, '')
|
|
226
|
+
end
|
|
216
227
|
if option(:source)
|
|
217
228
|
header['X-4me-Source'] = option(:source)
|
|
218
229
|
header['HTTP_USER_AGENT'] = option(:source)
|
|
@@ -2,243 +2,262 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
describe Sdk4me::Attachments do
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
@
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
expect(@attachments.upload_attachments!('/requests', {status: :in_progress})).to be_nil
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it 'should not do anything when :attachments is nil' do
|
|
17
|
-
expect(@attachments.upload_attachments!('/requests', {attachments: nil})).to be_nil
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it 'should not do anything when :attachments is empty' do
|
|
21
|
-
expect(@attachments.upload_attachments!('/requests', {attachments: []})).to be_nil
|
|
22
|
-
expect(@attachments.upload_attachments!('/requests', {attachments: [nil]})).to be_nil
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it 'should show a error if no attachment may be uploaded' do
|
|
26
|
-
stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {name: 'site 1'}.to_json)
|
|
27
|
-
expect_log('Attachments not allowed for /sites/1', :error)
|
|
28
|
-
expect(@attachments.upload_attachments!('/sites/1', {attachments: ['file1.png']})).to be_nil
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
it 'should raise an exception if no attachment may be uploaded' do
|
|
32
|
-
stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {name: 'site 1'}.to_json)
|
|
33
|
-
message = 'Attachments not allowed for /sites/1'
|
|
34
|
-
expect{ @attachments.upload_attachments!('/sites/1', {attachments: ['file1.png'], attachments_exception: true}) }.to raise_error(::Sdk4me::UploadFailed, message)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it 'should add /new to the path for new records' do
|
|
38
|
-
stub_request(:get, 'https://api.4me.com/v1/sites/new?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {missing: 'storage'}.to_json)
|
|
39
|
-
expect_log('Attachments not allowed for /sites', :error)
|
|
40
|
-
expect(@attachments.upload_attachments!('/sites', {attachments: ['file1.png']})).to be_nil
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
[ [:requests, :note],
|
|
44
|
-
[:problems, :note],
|
|
45
|
-
[:contracts, :remarks],
|
|
46
|
-
[:cis, :remarks],
|
|
47
|
-
[:flsas, :remarks],
|
|
48
|
-
[:slas, :remarks],
|
|
49
|
-
[:service_instances, :remarks],
|
|
50
|
-
[:service_offerings, :summary],
|
|
51
|
-
[:any_other_model, :note]].each do |model, attribute|
|
|
52
|
-
|
|
53
|
-
it "should replace :attachments with :#{attribute}_attachments after upload at /#{model}" do
|
|
54
|
-
stub_request(:get, "https://api.4me.com/v1/#{model}/new?attachment_upload_token=true").with(basic_auth: ['secret', 'x']).to_return(body: {storage_upload: 'conf'}.to_json)
|
|
55
|
-
expect(@attachments).to receive(:upload_attachment).with('conf', 'file1.png', false).ordered{ 'uploaded file1.png' }
|
|
56
|
-
expect(@attachments).to receive(:upload_attachment).with('conf', 'file2.zip', false).ordered{ 'uploaded file2.zip' }
|
|
57
|
-
data = {leave: 'me alone', attachments: %w(file1.png file2.zip)}
|
|
58
|
-
@attachments.upload_attachments!("/#{model}", data)
|
|
59
|
-
expect(data[:attachments]).to be_nil
|
|
60
|
-
expect(data[:leave]).to eq('me alone')
|
|
61
|
-
expect(data[:"#{attribute}_attachments"]).to eq(['uploaded file1.png', 'uploaded file2.zip'].to_json)
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
it 'should set raise_exception flag to true when :attachments_exception is set' do
|
|
66
|
-
stub_request(:get, 'https://api.4me.com/v1/requests/new?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {storage_upload: 'conf'}.to_json)
|
|
67
|
-
expect(@attachments).to receive(:upload_attachment).with('conf', 'file1.png', true).ordered{ 'uploaded file1.png' }
|
|
68
|
-
data = {leave: 'me alone', attachments: 'file1.png', attachments_exception: true}
|
|
69
|
-
@attachments.upload_attachments!('/requests', data)
|
|
70
|
-
expect(data[:attachments]).to be_nil
|
|
71
|
-
expect(data[:attachments_exception]).to be_nil
|
|
72
|
-
expect(data[:leave]).to eq('me alone')
|
|
73
|
-
expect(data[:note_attachments]).to eq(['uploaded file1.png'].to_json)
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
context 'inline' do
|
|
78
|
-
it 'should not do anything when no [attachment:...] is present in the note' do
|
|
79
|
-
expect(@attachments.upload_attachments!('/requests', {note: '[attachmen:/type]'})).to be_nil
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
it 'should not do anything when attachment is empty' do
|
|
83
|
-
expect(@attachments.upload_attachments!('/requests', {note: '[attachment:]'})).to be_nil
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
it 'should show a error if no attachment may be uploaded' do
|
|
87
|
-
stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {name: 'site 1'}.to_json)
|
|
88
|
-
expect_log('Attachments not allowed for /sites/1', :error)
|
|
89
|
-
expect(@attachments.upload_attachments!('/sites/1', {note: '[attachment:file1.png]'})).to be_nil
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
it 'should raise an exception if no attachment may be uploaded' do
|
|
93
|
-
stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {name: 'site 1'}.to_json)
|
|
94
|
-
message = 'Attachments not allowed for /sites/1'
|
|
95
|
-
expect{ @attachments.upload_attachments!('/sites/1', {note: '[attachment:file1.png]', attachments_exception: true}) }.to raise_error(::Sdk4me::UploadFailed, message)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
it 'should add /new to the path for new records' do
|
|
99
|
-
stub_request(:get, 'https://api.4me.com/v1/sites/new?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {missing: 'storage'}.to_json)
|
|
100
|
-
expect_log('Attachments not allowed for /sites', :error)
|
|
101
|
-
expect(@attachments.upload_attachments!('/sites', {note: '[attachment:file1.png]'})).to be_nil
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
[ [:requests, :note],
|
|
105
|
-
[:problems, :note],
|
|
106
|
-
[:contracts, :remarks],
|
|
107
|
-
[:cis, :remarks],
|
|
108
|
-
[:flsas, :remarks],
|
|
109
|
-
[:slas, :remarks],
|
|
110
|
-
[:service_instances, :remarks],
|
|
111
|
-
[:service_offerings, :summary],
|
|
112
|
-
[:any_other_model, :note]].each do |model, attribute|
|
|
113
|
-
|
|
114
|
-
it "should replace :attachments with :#{attribute}_attachments after upload at /#{model}" do
|
|
115
|
-
stub_request(:get, "https://api.4me.com/v1/#{model}/new?attachment_upload_token=true").with(basic_auth: ['secret', 'x']).to_return(body: {storage_upload: 'conf'}.to_json)
|
|
116
|
-
expect(@attachments).to receive(:upload_attachment).with('conf', 'file1.png', false).ordered{ {key: 'uploaded file1.png'} }
|
|
117
|
-
expect(@attachments).to receive(:upload_attachment).with('conf', 'file2.zip', false).ordered{ {key: 'uploaded file2.zip'} }
|
|
118
|
-
data = {leave: 'me alone', attribute => '[attachment:file1.png] and [attachment:file2.zip]'}
|
|
119
|
-
@attachments.upload_attachments!("/#{model}", data)
|
|
120
|
-
expect(data[:attachments]).to be_nil
|
|
121
|
-
expect(data[:leave]).to eq('me alone')
|
|
122
|
-
expect(data[:"#{attribute}_attachments"]).to eq([{key: 'uploaded file1.png', inline: true}, {key: 'uploaded file2.zip', inline: true}].to_json)
|
|
123
|
-
expect(data[:"#{attribute}"]).to eq(' and ')
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
it 'should set raise_exception flag to true when :attachments_exception is set' do
|
|
128
|
-
stub_request(:get, 'https://api.4me.com/v1/requests/new?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {storage_upload: 'conf'}.to_json)
|
|
129
|
-
expect(@attachments).to receive(:upload_attachment).with('conf', 'file1.png', true).ordered{ {key: 'uploaded file1.png'} }
|
|
130
|
-
data = {leave: 'me alone', note: '[attachment:file1.png]', attachments_exception: true}
|
|
131
|
-
@attachments.upload_attachments!('/requests', data)
|
|
132
|
-
expect(data[:attachments]).to be_nil
|
|
133
|
-
expect(data[:attachments_exception]).to be_nil
|
|
134
|
-
expect(data[:leave]).to eq('me alone')
|
|
135
|
-
expect(data[:note_attachments]).to eq([{key: 'uploaded file1.png', inline: true}].to_json)
|
|
136
|
-
expect(data[:note]).to eq('')
|
|
137
|
-
end
|
|
5
|
+
def attachments(authentication)
|
|
6
|
+
(@attachments ||= {})[authentication] ||= begin
|
|
7
|
+
client = if authentication == :api_token
|
|
8
|
+
Sdk4me::Client.new(api_token: 'secret', max_retry_time: -1)
|
|
9
|
+
else
|
|
10
|
+
Sdk4me::Client.new(access_token: 'secret', max_retry_time: -1)
|
|
11
|
+
end
|
|
12
|
+
Sdk4me::Attachments.new(client)
|
|
138
13
|
end
|
|
139
|
-
|
|
140
14
|
end
|
|
141
15
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
16
|
+
def credentials(authentication)
|
|
17
|
+
if authentication == :api_token
|
|
18
|
+
{ basic_auth: ['secret', 'x'] }
|
|
19
|
+
else
|
|
20
|
+
{ headers: {'Authorization' => 'Bearer secret'} }
|
|
147
21
|
end
|
|
22
|
+
end
|
|
148
23
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
24
|
+
[:api_token, :access_token].each do |authentication|
|
|
25
|
+
|
|
26
|
+
context "#{authentication} - " do
|
|
27
|
+
context 'upload_attachments!' do
|
|
28
|
+
context 'normal' do
|
|
29
|
+
it 'should not do anything when no :attachments are present' do
|
|
30
|
+
expect(attachments(authentication).upload_attachments!('/requests', {status: :in_progress})).to be_nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'should not do anything when :attachments is nil' do
|
|
34
|
+
expect(attachments(authentication).upload_attachments!('/requests', {attachments: nil})).to be_nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'should not do anything when :attachments is empty' do
|
|
38
|
+
expect(attachments(authentication).upload_attachments!('/requests', {attachments: []})).to be_nil
|
|
39
|
+
expect(attachments(authentication).upload_attachments!('/requests', {attachments: [nil]})).to be_nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'should show a error if no attachment may be uploaded' do
|
|
43
|
+
stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {name: 'site 1'}.to_json)
|
|
44
|
+
expect_log('Attachments not allowed for /sites/1', :error)
|
|
45
|
+
expect(attachments(authentication).upload_attachments!('/sites/1', {attachments: ['file1.png']})).to be_nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'should raise an exception if no attachment may be uploaded' do
|
|
49
|
+
stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {name: 'site 1'}.to_json)
|
|
50
|
+
message = 'Attachments not allowed for /sites/1'
|
|
51
|
+
expect{ attachments(authentication).upload_attachments!('/sites/1', {attachments: ['file1.png'], attachments_exception: true}) }.to raise_error(::Sdk4me::UploadFailed, message)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'should add /new to the path for new records' do
|
|
55
|
+
stub_request(:get, 'https://api.4me.com/v1/sites/new?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {missing: 'storage'}.to_json)
|
|
56
|
+
expect_log('Attachments not allowed for /sites', :error)
|
|
57
|
+
expect(attachments(authentication).upload_attachments!('/sites', {attachments: ['file1.png']})).to be_nil
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
[ [:requests, :note],
|
|
61
|
+
[:problems, :note],
|
|
62
|
+
[:contracts, :remarks],
|
|
63
|
+
[:cis, :remarks],
|
|
64
|
+
[:flsas, :remarks],
|
|
65
|
+
[:slas, :remarks],
|
|
66
|
+
[:service_instances, :remarks],
|
|
67
|
+
[:service_offerings, :summary],
|
|
68
|
+
[:any_other_model, :note]].each do |model, attribute|
|
|
69
|
+
|
|
70
|
+
it "should replace :attachments with :#{attribute}_attachments after upload at /#{model}" do
|
|
71
|
+
stub_request(:get, "https://api.4me.com/v1/#{model}/new?attachment_upload_token=true").with(credentials(authentication)).to_return(body: {storage_upload: 'conf'}.to_json)
|
|
72
|
+
expect(attachments(authentication)).to receive(:upload_attachment).with('conf', 'file1.png', false).ordered{ 'uploaded file1.png' }
|
|
73
|
+
expect(attachments(authentication)).to receive(:upload_attachment).with('conf', 'file2.zip', false).ordered{ 'uploaded file2.zip' }
|
|
74
|
+
data = {leave: 'me alone', attachments: %w(file1.png file2.zip)}
|
|
75
|
+
attachments(authentication).upload_attachments!("/#{model}", data)
|
|
76
|
+
expect(data[:attachments]).to be_nil
|
|
77
|
+
expect(data[:leave]).to eq('me alone')
|
|
78
|
+
expect(data[:"#{attribute}_attachments"]).to eq(['uploaded file1.png', 'uploaded file2.zip'].to_json)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'should set raise_exception flag to true when :attachments_exception is set' do
|
|
83
|
+
stub_request(:get, 'https://api.4me.com/v1/requests/new?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {storage_upload: 'conf'}.to_json)
|
|
84
|
+
expect(attachments(authentication)).to receive(:upload_attachment).with('conf', 'file1.png', true).ordered{ 'uploaded file1.png' }
|
|
85
|
+
data = {leave: 'me alone', attachments: 'file1.png', attachments_exception: true}
|
|
86
|
+
attachments(authentication).upload_attachments!('/requests', data)
|
|
87
|
+
expect(data[:attachments]).to be_nil
|
|
88
|
+
expect(data[:attachments_exception]).to be_nil
|
|
89
|
+
expect(data[:leave]).to eq('me alone')
|
|
90
|
+
expect(data[:note_attachments]).to eq(['uploaded file1.png'].to_json)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
182
93
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
94
|
+
context 'inline' do
|
|
95
|
+
it 'should not do anything when no [attachment:...] is present in the note' do
|
|
96
|
+
expect(attachments(authentication).upload_attachments!('/requests', {note: '[attachmen:/type]'})).to be_nil
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'should not do anything when attachment is empty' do
|
|
100
|
+
expect(attachments(authentication).upload_attachments!('/requests', {note: '[attachment:]'})).to be_nil
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'should show a error if no attachment may be uploaded' do
|
|
104
|
+
stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {name: 'site 1'}.to_json)
|
|
105
|
+
expect_log('Attachments not allowed for /sites/1', :error)
|
|
106
|
+
expect(attachments(authentication).upload_attachments!('/sites/1', {note: '[attachment:file1.png]'})).to be_nil
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it 'should raise an exception if no attachment may be uploaded' do
|
|
110
|
+
stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {name: 'site 1'}.to_json)
|
|
111
|
+
message = 'Attachments not allowed for /sites/1'
|
|
112
|
+
expect{ attachments(authentication).upload_attachments!('/sites/1', {note: '[attachment:file1.png]', attachments_exception: true}) }.to raise_error(::Sdk4me::UploadFailed, message)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it 'should add /new to the path for new records' do
|
|
116
|
+
stub_request(:get, 'https://api.4me.com/v1/sites/new?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {missing: 'storage'}.to_json)
|
|
117
|
+
expect_log('Attachments not allowed for /sites', :error)
|
|
118
|
+
expect(attachments(authentication).upload_attachments!('/sites', {note: '[attachment:file1.png]'})).to be_nil
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
[ [:requests, :note],
|
|
122
|
+
[:problems, :note],
|
|
123
|
+
[:contracts, :remarks],
|
|
124
|
+
[:cis, :remarks],
|
|
125
|
+
[:flsas, :remarks],
|
|
126
|
+
[:slas, :remarks],
|
|
127
|
+
[:service_instances, :remarks],
|
|
128
|
+
[:service_offerings, :summary],
|
|
129
|
+
[:any_other_model, :note]].each do |model, attribute|
|
|
130
|
+
|
|
131
|
+
it "should replace :attachments with :#{attribute}_attachments after upload at /#{model}" do
|
|
132
|
+
stub_request(:get, "https://api.4me.com/v1/#{model}/new?attachment_upload_token=true").with(credentials(authentication)).to_return(body: {storage_upload: 'conf'}.to_json)
|
|
133
|
+
expect(attachments(authentication)).to receive(:upload_attachment).with('conf', 'file1.png', false).ordered{ {key: 'uploaded file1.png'} }
|
|
134
|
+
expect(attachments(authentication)).to receive(:upload_attachment).with('conf', 'file2.zip', false).ordered{ {key: 'uploaded file2.zip'} }
|
|
135
|
+
data = {leave: 'me alone', attribute => '[attachment:file1.png] and [attachment:file2.zip]'}
|
|
136
|
+
attachments(authentication).upload_attachments!("/#{model}", data)
|
|
137
|
+
expect(data[:attachments]).to be_nil
|
|
138
|
+
expect(data[:leave]).to eq('me alone')
|
|
139
|
+
expect(data[:"#{attribute}_attachments"]).to eq([{key: 'uploaded file1.png', inline: true}, {key: 'uploaded file2.zip', inline: true}].to_json)
|
|
140
|
+
expect(data[:"#{attribute}"]).to eq(' and ')
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it 'should set raise_exception flag to true when :attachments_exception is set' do
|
|
145
|
+
stub_request(:get, 'https://api.4me.com/v1/requests/new?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {storage_upload: 'conf'}.to_json)
|
|
146
|
+
expect(attachments(authentication)).to receive(:upload_attachment).with('conf', 'file1.png', true).ordered{ {key: 'uploaded file1.png'} }
|
|
147
|
+
data = {leave: 'me alone', note: '[attachment:file1.png]', attachments_exception: true}
|
|
148
|
+
attachments(authentication).upload_attachments!('/requests', data)
|
|
149
|
+
expect(data[:attachments]).to be_nil
|
|
150
|
+
expect(data[:attachments_exception]).to be_nil
|
|
151
|
+
expect(data[:leave]).to eq('me alone')
|
|
152
|
+
expect(data[:note_attachments]).to eq([{key: 'uploaded file1.png', inline: true}].to_json)
|
|
153
|
+
expect(data[:note]).to eq('')
|
|
154
|
+
end
|
|
155
|
+
end
|
|
188
156
|
|
|
189
|
-
it 'should report an error when 4me confirmation fails' do
|
|
190
|
-
stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: 'OK', status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
|
|
191
|
-
stub_request(:get, "https://api.4me.com/v1/s3_success?sig=99e82e8a046&key=#{@key}").with(basic_auth: ['secret', 'x']).to_return(body: {message: 'oops!'}.to_json)
|
|
192
|
-
expect_log('GET request to api.4me.com:443/v1/s3_success?sig=99e82e8a046&key=attachments%2F5%2Freqs%2F000%2F070%2F451%2Fzxxb4ot60xfd6sjg%2Fupload%2Etxt failed: oops!', :error)
|
|
193
|
-
expect_log("Attachment upload failed: 4me confirmation s3_success?sig=99e82e8a046 for #{@key} failed: oops!", :error)
|
|
194
|
-
expect(@attachments.send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", false)).to be_nil
|
|
195
157
|
end
|
|
196
158
|
|
|
197
|
-
|
|
198
|
-
stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: %(<?xml version="1.0" encoding="UTF-8"?>\n<Error><Code>AccessDenied</Code><Message>Invalid according to Policy</Message><RequestId>1FECC4B719E426B1</RequestId><HostId>15+14lXt+HlF</HostId></Error>), status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
|
|
199
|
-
message = "Attachment upload failed: AWS upload to https://itrp.s3.amazonaws.com/ for #{@key} failed: Invalid according to Policy"
|
|
200
|
-
expect{ @attachments.send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", true) }.to raise_error(::Sdk4me::UploadFailed, message)
|
|
201
|
-
end
|
|
202
|
-
end
|
|
159
|
+
context 'upload_attachment' do
|
|
203
160
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
upload_uri: 'https://api.4me.com/attachments',
|
|
209
|
-
upload_path: 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/'
|
|
210
|
-
}
|
|
211
|
-
@key_template = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}'
|
|
212
|
-
@key = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/upload.txt'
|
|
213
|
-
|
|
214
|
-
@multi_part_body = "--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"Content-Type\"\r\n\r\napplication/octet-stream\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"file\"; filename=\"#{@spec_dir}/support/fixtures/upload.txt\"\r\nContent-Type: text/plain\r\n\r\ncontent\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"key\"\r\n\r\nattachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}\r\n--0123456789ABLEWASIEREISAWELBA9876543210--"
|
|
215
|
-
@multi_part_headers = {'Accept'=>'*/*', 'Content-Type'=>'multipart/form-data; boundary=0123456789ABLEWASIEREISAWELBA9876543210', 'User-Agent'=>'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6'}
|
|
216
|
-
end
|
|
161
|
+
it 'should log an exception when the file could not be found' do
|
|
162
|
+
expect_log('Attachment upload failed: file does not exist: unknown_file', :error)
|
|
163
|
+
expect(attachments(authentication).send(:upload_attachment, nil, 'unknown_file', false)).to be_nil
|
|
164
|
+
end
|
|
217
165
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
166
|
+
it 'should raise an exception when the file could not be found' do
|
|
167
|
+
message = 'Attachment upload failed: file does not exist: unknown_file'
|
|
168
|
+
expect{ attachments(authentication).send(:upload_attachment, nil, 'unknown_file', true) }.to raise_error(::Sdk4me::UploadFailed, message)
|
|
169
|
+
end
|
|
222
170
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
171
|
+
context 'aws' do
|
|
172
|
+
before(:each) do
|
|
173
|
+
@aws_conf = {
|
|
174
|
+
provider: 'aws',
|
|
175
|
+
upload_uri: 'https://itrp.s3.amazonaws.com/',
|
|
176
|
+
access_key: 'AKIA6RYQ',
|
|
177
|
+
success_url: 'https://mycompany.4me.com/s3_success?sig=99e82e8a046',
|
|
178
|
+
policy: 'eydlgIH0=',
|
|
179
|
+
signature: 'nbhdec4k=',
|
|
180
|
+
upload_path: 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/'
|
|
181
|
+
}
|
|
182
|
+
@key_template = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}'
|
|
183
|
+
@key = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/upload.txt'
|
|
184
|
+
|
|
185
|
+
@multi_part_body = "--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"Content-Type\"\r\n\r\napplication/octet-stream\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"x-amz-server-side-encryption\"\r\n\r\nAES256\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"key\"\r\n\r\nattachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"AWSAccessKeyId\"\r\n\r\nAKIA6RYQ\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"acl\"\r\n\r\nprivate\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"signature\"\r\n\r\nnbhdec4k=\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"success_action_status\"\r\n\r\n201\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"policy\"\r\n\r\neydlgIH0=\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"file\"; filename=\"#{@fixture_dir}/upload.txt\"\r\nContent-Type: text/plain\r\n\r\ncontent\r\n--0123456789ABLEWASIEREISAWELBA9876543210--"
|
|
186
|
+
@multi_part_headers = {'Accept'=>'*/*', 'Content-Type'=>'multipart/form-data; boundary=0123456789ABLEWASIEREISAWELBA9876543210', 'User-Agent'=>'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6'}
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it 'should open a file from disk' do
|
|
190
|
+
expect(attachments(authentication)).to receive(:aws_upload).with(@aws_conf, @key_template, @key, kind_of(File))
|
|
191
|
+
expect(attachments(authentication).send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", false)).to eq({key: @key, filesize: 7})
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it 'should sent the upload to AWS' do
|
|
195
|
+
stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: 'OK', status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
|
|
196
|
+
stub_request(:get, "https://api.4me.com/v1/s3_success?sig=99e82e8a046&key=#{@key}").with(credentials(authentication)).to_return(body: {}.to_json)
|
|
197
|
+
expect(attachments(authentication).send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", false)).to eq({key: @key, filesize: 7})
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
it 'should report an error when AWS upload fails' do
|
|
201
|
+
stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: %(<?xml version="1.0" encoding="UTF-8"?>\n<Error><Code>AccessDenied</Code><Message>Invalid according to Policy</Message><RequestId>1FECC4B719E426B1</RequestId><HostId>15+14lXt+HlF</HostId></Error>), status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
|
|
202
|
+
expect_log("Attachment upload failed: AWS upload to https://itrp.s3.amazonaws.com/ for #{@key} failed: Invalid according to Policy", :error)
|
|
203
|
+
expect(attachments(authentication).send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", false)).to be_nil
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
it 'should report an error when 4me confirmation fails' do
|
|
207
|
+
stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: 'OK', status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
|
|
208
|
+
stub_request(:get, "https://api.4me.com/v1/s3_success?sig=99e82e8a046&key=#{@key}").with(credentials(authentication)).to_return(body: {message: 'oops!'}.to_json)
|
|
209
|
+
expect_log('GET request to api.4me.com:443/v1/s3_success?sig=99e82e8a046&key=attachments%2F5%2Freqs%2F000%2F070%2F451%2Fzxxb4ot60xfd6sjg%2Fupload%2Etxt failed: oops!', :error)
|
|
210
|
+
expect_log("Attachment upload failed: 4me confirmation s3_success?sig=99e82e8a046 for #{@key} failed: oops!", :error)
|
|
211
|
+
expect(attachments(authentication).send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", false)).to be_nil
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it 'should raise an exception when AWS upload fails' do
|
|
215
|
+
stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: %(<?xml version="1.0" encoding="UTF-8"?>\n<Error><Code>AccessDenied</Code><Message>Invalid according to Policy</Message><RequestId>1FECC4B719E426B1</RequestId><HostId>15+14lXt+HlF</HostId></Error>), status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
|
|
216
|
+
message = "Attachment upload failed: AWS upload to https://itrp.s3.amazonaws.com/ for #{@key} failed: Invalid according to Policy"
|
|
217
|
+
expect{ attachments(authentication).send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", true) }.to raise_error(::Sdk4me::UploadFailed, message)
|
|
218
|
+
end
|
|
219
|
+
end
|
|
227
220
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
221
|
+
context '4me' do
|
|
222
|
+
before(:each) do
|
|
223
|
+
@sdk4me_conf = {
|
|
224
|
+
provider: 'local',
|
|
225
|
+
upload_uri: 'https://api.4me.com/attachments',
|
|
226
|
+
upload_path: 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/'
|
|
227
|
+
}
|
|
228
|
+
@key_template = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}'
|
|
229
|
+
@key = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/upload.txt'
|
|
230
|
+
|
|
231
|
+
@multi_part_body = "--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"Content-Type\"\r\n\r\napplication/octet-stream\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"file\"; filename=\"#{@spec_dir}/support/fixtures/upload.txt\"\r\nContent-Type: text/plain\r\n\r\ncontent\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"key\"\r\n\r\nattachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}\r\n--0123456789ABLEWASIEREISAWELBA9876543210--"
|
|
232
|
+
@multi_part_headers = {'Accept'=>'*/*', 'Content-Type'=>'multipart/form-data; boundary=0123456789ABLEWASIEREISAWELBA9876543210', 'User-Agent'=>'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6'}
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it 'should open a file from disk' do
|
|
236
|
+
expect(attachments(authentication)).to receive(:upload_to_4me).with(@sdk4me_conf, @key_template, @key, kind_of(File))
|
|
237
|
+
expect(attachments(authentication).send(:upload_attachment, @sdk4me_conf, "#{@fixture_dir}/upload.txt", false)).to eq({key: @key, filesize: 7})
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it 'should sent the upload to 4me' do
|
|
241
|
+
stub_request(:post, 'https://api.4me.com/v1/attachments').with(credentials(authentication)).with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: {}.to_json)
|
|
242
|
+
expect(attachments(authentication).send(:upload_attachment, @sdk4me_conf, "#{@fixture_dir}/upload.txt", false)).to eq({key: @key, filesize: 7})
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
it 'should report an error when 4me upload fails' do
|
|
246
|
+
stub_request(:post, 'https://api.4me.com/v1/attachments').with(credentials(authentication)).with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: {message: 'oops!'}.to_json)
|
|
247
|
+
expect_log('POST request to api.4me.com:443/v1/attachments failed: oops!', :error)
|
|
248
|
+
expect_log("Attachment upload failed: 4me upload to https://api.4me.com/attachments for #{@key} failed: oops!", :error)
|
|
249
|
+
expect(attachments(authentication).send(:upload_attachment, @sdk4me_conf, "#{@fixture_dir}/upload.txt", false)).to be_nil
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it 'should raise an exception when 4me upload fails' do
|
|
253
|
+
stub_request(:post, 'https://api.4me.com/v1/attachments').with(credentials(authentication)).with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: {message: 'oops!'}.to_json)
|
|
254
|
+
expect_log('POST request to api.4me.com:443/v1/attachments failed: oops!', :error)
|
|
255
|
+
message = "Attachment upload failed: 4me upload to https://api.4me.com/attachments for #{@key} failed: oops!"
|
|
256
|
+
expect{ attachments(authentication).send(:upload_attachment, @sdk4me_conf, "#{@fixture_dir}/upload.txt", true) }.to raise_error(::Sdk4me::UploadFailed, message)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
234
259
|
|
|
235
|
-
it 'should raise an exception when 4me upload fails' do
|
|
236
|
-
stub_request(:post, 'https://api.4me.com/v1/attachments').with(basic_auth: ['secret', 'x']).with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: {message: 'oops!'}.to_json)
|
|
237
|
-
expect_log('POST request to api.4me.com:443/v1/attachments failed: oops!', :error)
|
|
238
|
-
message = "Attachment upload failed: 4me upload to https://api.4me.com/attachments for #{@key} failed: oops!"
|
|
239
|
-
expect{ @attachments.send(:upload_attachment, @sdk4me_conf, "#{@fixture_dir}/upload.txt", true) }.to raise_error(::Sdk4me::UploadFailed, message)
|
|
240
260
|
end
|
|
241
261
|
end
|
|
242
|
-
|
|
243
262
|
end
|
|
244
263
|
end
|