stash-sword 0.1.3 → 0.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3b9630eb6e13c298e5510adc24a284f80cd2782d
4
- data.tar.gz: c84b4010037183af57468e22b0b33032f989cedd
3
+ metadata.gz: b73e085f5409cc5c2b3a74c703aacb670bffdc46
4
+ data.tar.gz: d393a54966e95e40d97d6019022781547fecdad2
5
5
  SHA512:
6
- metadata.gz: 1ab2af3fea1f8d220075abe287baeb531265a4483814a7aae7766721c649d5a62099368d943a550e6a0ff6bebc04a36e250d9390df7952bb1f6089624de67e6d
7
- data.tar.gz: ee6a6857b1c898f73312b60086a6cd3cb0af2ca9a177dbcdeca489ab60af8f9cd1c0bd04a9b2f9b61d17ffb77eee24abe56768b062ea680010b875f9b9d3141b
6
+ metadata.gz: 49f4a2eddae1eac20a7b8ee10c707287ca10f2e7390bab19fb7ac17a9e809a049a5f680112aa5059c76f2af6d38336ac297783d42786bb03b35230433e7f9787
7
+ data.tar.gz: 397fcf71c55dad279545b735274293c108989c0e604baa8ad488679cdc88b5beca0a97dfe15fdbfaf85cbd4f8e64167a44d7bacd954ac7dafd4b5af1fcca6664
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.2.3
1
+ 2.2.5
data/CHANGES.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.1.4 (14 November 2016)
2
+
3
+ - Update to Ruby 2.2.5
4
+ - Add `timeout:` parameter to `HTTPHelper`, with a default of 10 minutes.
5
+
1
6
  ## 0.1.3 (15 August 2016)
2
7
 
3
8
  - Use 2.0.0 release version of `rest-client` to fix issues with cookie handling in redirection
data/examples/create.rb CHANGED
@@ -7,7 +7,7 @@ include Stash::Sword
7
7
  password = ARGV[0]
8
8
  username = 'ucop_dash_submitter'
9
9
  collection = 'dash_cdl'
10
- collection_uri = "http://uc3-mrtsword-dev.cdlib.org:39001/mrtsword/collection/#{collection}"
10
+ collection_uri = "http://sword-aws-dev.cdlib.org:39001/mrtsword/collection/#{collection}"
11
11
  zipfile = File.expand_path('../uploads/example.zip', __FILE__)
12
12
 
13
13
  doi = "doi:10.5072/FK#{Time.now.to_i}"
@@ -59,8 +59,8 @@ module Stash
59
59
  def update(edit_iri:, zipfile:)
60
60
  log.debug("Stash::Sword::Client.update(edit_iri: #{edit_iri}, zipfile: #{zipfile})")
61
61
  uri = to_uri(edit_iri).to_s
62
- response = maybe_redirect(do_put(uri, zipfile))
63
- log.debug(response_to_log_msg(response))
62
+ response = do_put(uri, zipfile)
63
+ log.debug(to_log_msg(response))
64
64
  response.code # TODO: what if anything should we return here?
65
65
  rescue => e
66
66
  log_error(e)
@@ -75,15 +75,8 @@ module Stash
75
75
  raise 'no password provided' unless password
76
76
  end
77
77
 
78
- def maybe_redirect(response)
79
- return response unless [301, 302, 307].include?(response.code)
80
- log.debug(response_to_log_msg(response))
81
- log.debug("Response code #{response.code}; redirecting")
82
- response.follow_get_redirection
83
- end
84
-
85
78
  def receipt_from(response)
86
- log.debug(response_to_log_msg(response))
79
+ log.debug(to_log_msg(response))
87
80
 
88
81
  body = response.body.strip
89
82
  return DepositReceipt.parse_xml(body) unless body.empty?
@@ -97,7 +90,7 @@ module Stash
97
90
  return nil unless edit_iri
98
91
 
99
92
  log.debug("Retrieving deposit receipt from Location header Edit-IRI: #{edit_iri}")
100
- body = helper.get(to_uri(edit_iri))
93
+ body = helper.get(uri: to_uri(edit_iri))
101
94
  return nil unless body
102
95
 
103
96
  DepositReceipt.parse_xml(body)
@@ -13,12 +13,18 @@ module Stash
13
13
  # The default number of redirects to follow before erroring out.
14
14
  DEFAULT_MAX_REDIRECTS = 5
15
15
 
16
+ # The default number of seconds to allow before timing out. Defaults to 10 minutes.
17
+ DEFAULT_TIMEOUT = 60 * 10
18
+
16
19
  # @return [String] the User-Agent string to send when making requests
17
20
  attr_accessor :user_agent
18
21
 
19
22
  # @return [Integer] the number of redirects to follow before erroring out
20
23
  attr_accessor :redirect_limit
21
24
 
25
+ # @return [Integer] the number of seconds to allow before timing out
26
+ attr_accessor :timeout
27
+
22
28
  # @return [String] the HTTP Basic Authentication username
23
29
  attr_reader :username
24
30
 
@@ -31,9 +37,10 @@ module Stash
31
37
  # @param redirect_limit [Integer] the number of redirects to follow before erroring out
32
38
  # (defaults to {DEFAULT_MAX_REDIRECTS})
33
39
  # @param logger [Logger, nil] the logger to use, or nil to use a default logger
34
- def initialize(user_agent:, username: nil, password: nil, redirect_limit: DEFAULT_MAX_REDIRECTS, logger: nil)
40
+ def initialize(user_agent:, username: nil, password: nil, redirect_limit: DEFAULT_MAX_REDIRECTS, timeout: DEFAULT_TIMEOUT, logger: nil)
35
41
  @user_agent = user_agent
36
42
  @redirect_limit = redirect_limit
43
+ @timeout = timeout
37
44
  @username = username
38
45
  @password = password
39
46
  @log = logger || default_logger
@@ -53,12 +60,12 @@ module Stash
53
60
 
54
61
  # Posts the specified payload string to the specified URI.
55
62
  def post(uri:, payload:, headers: {}, limit: redirect_limit)
56
- do_post_or_put(method: :post, uri: uri, payload: payload, headers: headers, limit: limit)
63
+ do_post_or_put(method: :post, uri: uri, payload: payload, headers: headers, limit: limit, timeout: timeout)
57
64
  end
58
65
 
59
66
  # Puts the specified payload string to the specified URI.
60
67
  def put(uri:, payload:, headers: {}, limit: redirect_limit)
61
- do_post_or_put(method: :put, uri: uri, payload: payload, headers: headers, limit: limit)
68
+ do_post_or_put(method: :put, uri: uri, payload: payload, headers: headers, limit: limit, timeout: timeout)
62
69
  end
63
70
 
64
71
  private
@@ -70,19 +77,20 @@ module Stash
70
77
  }.freeze
71
78
  end
72
79
 
73
- def do_post_or_put(method:, uri:, payload:, headers:, limit:)
74
- options = request_options(headers, limit, method, payload, uri)
80
+ def do_post_or_put(method:, uri:, payload:, headers:, limit:, timeout:)
81
+ options = request_options(headers, limit, method, payload, uri, timeout)
75
82
  log_hash(options)
76
83
  RestClient::Request.execute(**options)
77
84
  end
78
85
 
79
- def request_options(headers, limit, method, payload, uri)
86
+ def request_options(headers, limit, method, payload, uri, timeout)
80
87
  options = {
81
88
  method: method,
82
89
  url: uri.to_s,
83
90
  payload: payload,
84
91
  headers: headers.merge(default_headers),
85
- max_redirects: limit
92
+ max_redirects: limit,
93
+ timeout: timeout
86
94
  }
87
95
  options[:user] = username if username
88
96
  options[:password] = password if password
@@ -7,21 +7,15 @@ module Stash
7
7
  end
8
8
 
9
9
  def log_error(e)
10
- if e.respond_to?(:response)
11
- log.error(response_to_log_msg(e.response))
12
- else
13
- log.error('Unable to log response')
14
- end
10
+ log.error(to_log_msg(e))
15
11
  end
16
12
 
17
- def response_to_log_msg(response)
18
- [
19
- '-----------------------------------------------------',
20
- "code: #{response.code}",
21
- 'headers:', hash_to_log_msg(response.headers),
22
- "body:\n#{response.body}",
23
- '-----------------------------------------------------'
24
- ].join("\n")
13
+ def to_log_msg(e)
14
+ msg_lines = []
15
+ append_message(msg_lines, e)
16
+ append_response(msg_lines, e)
17
+ append_backtrace(msg_lines, e)
18
+ msg_lines.join("\n")
25
19
  end
26
20
 
27
21
  def log_hash(hash)
@@ -49,7 +43,11 @@ module Stash
49
43
  end
50
44
 
51
45
  def default_logger
52
- logger = Logger.new($stdout, 10, 1024 * 1024)
46
+ LogUtils.create_default_logger($stdout, level)
47
+ end
48
+
49
+ def self.create_default_logger(io, level)
50
+ logger = Logger.new(io, 10, 1024 * 1024)
53
51
  logger.level = level
54
52
  logger.formatter = proc do |severity, datetime, progname, msg|
55
53
  "#{datetime.to_time.utc} #{severity} -#{progname}- #{msg}\n"
@@ -57,6 +55,31 @@ module Stash
57
55
  logger
58
56
  end
59
57
 
58
+ private
59
+
60
+ def append_message(msg_lines, e)
61
+ msg_lines << if e.respond_to?(:message) && e.message
62
+ "message: #{e.message}"
63
+ else
64
+ e.to_s
65
+ end
66
+ end
67
+
68
+ def append_response(msg_lines, e)
69
+ return unless e.respond_to?(:response) && e.response
70
+ response = e.response
71
+ msg_lines.unshift(*[
72
+ "code: #{response.code}",
73
+ 'headers:', hash_to_log_msg(response.headers),
74
+ "body:\n#{response.body}"
75
+ ])
76
+ end
77
+
78
+ def append_backtrace(msg_lines, e)
79
+ return unless e.respond_to?(:backtrace) && e.backtrace
80
+ msg_lines.unshift(*e.backtrace)
81
+ end
82
+
60
83
  end
61
84
  end
62
85
  end
@@ -4,7 +4,7 @@ module Stash
4
4
  NAME = 'stash-sword'.freeze
5
5
 
6
6
  # The version of this gem
7
- VERSION = '0.1.3'.freeze
7
+ VERSION = '0.1.4'.freeze
8
8
 
9
9
  # The copyright notice for this gem
10
10
  COPYRIGHT = 'Copyright (c) 2016 The Regents of the University of California'.freeze
@@ -50,8 +50,20 @@ module Stash
50
50
  end
51
51
  end
52
52
 
53
+ it "gets the entry from the Edit-IRI in the Location: header if it isn't returned in the body" do
54
+ authorized_uri = collection_uri.sub('http://', "http://#{username}:#{password}@")
55
+
56
+ redirect_url = 'http://www.example.org/'
57
+ stub_request(:post, authorized_uri).to_return(status: 201, headers: { 'Location' => redirect_url })
58
+ stub_request(:get, redirect_url.sub('http://', "http://#{username}:#{password}@")).to_return(
59
+ body: '<entry xmlns="http://www.w3.org/2005/Atom"><id>http://merritt.cdlib.org/sword/v2/object/ark:/99999/fk4t157x4p</id><author><name>ucb_dash_submitter</name></author><generator uri="http://www.swordapp.org/" version="2.0" /><link href="http://merritt.cdlib.org/sword/v2/object/ark:/99999/fk4t157x4p" rel="edit" /><link href="http://merritt.cdlib.org/sword/v2/object/ark:/99999/fk4t157x4p" rel="http://purl.org/net/sword/terms/add" /><link href="http://merritt.cdlib.org/sword/v2/object/ark:/99999/fk4t157x4p" rel="edit-media" /><treatment xmlns="http://purl.org/net/sword/terms/">no treatment information available</treatment></entry>'
60
+ )
61
+
62
+ receipt = client.create(zipfile: zipfile, doi: doi)
63
+ expect(receipt).to be_a(DepositReceipt)
64
+ end
65
+
53
66
  it 'returns the entry'
54
- it "gets the entry from the Edit-IRI in the Location: header if it isn't returned in the body"
55
67
  it 'forwards a success response'
56
68
 
57
69
  it 'forwards a 4xx error' do
@@ -115,8 +127,15 @@ module Stash
115
127
  end
116
128
  end
117
129
 
118
- it 'does something clever and asynchronous'
119
- it 'forwards a success response'
130
+ it 'follows redirects' do
131
+ edit_iri = "http://merritt.cdlib.org/sword/v2/object/#{doi}"
132
+ authorized_uri = edit_iri.sub('http://', "http://#{username}:#{password}@")
133
+ redirect_url = 'http://www.example.org/'
134
+ stub_request(:put, authorized_uri).to_return(status: 303, headers: { 'Location' => redirect_url })
135
+ stub_request(:get, redirect_url.sub('http://', "http://#{username}:#{password}@")).to_return(status: 200)
136
+ code = client.update(edit_iri: edit_iri, zipfile: zipfile)
137
+ expect(code).to eq(200)
138
+ end
120
139
 
121
140
  it 'forwards a 4xx error' do
122
141
  edit_iri = "http://merritt.cdlib.org/sword/v2/object/#{doi}"
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ module Stash
4
+ module Sword
5
+ describe LogUtils do
6
+
7
+ attr_reader :log_utils
8
+ attr_reader :rails_env
9
+ attr_reader :log_io
10
+
11
+ before(:all) { @rails_env = ENV['RAILS_ENV'] }
12
+ after(:all) { ENV['RAILS_ENV'] = rails_env }
13
+
14
+ before(:each) do
15
+ @log_io = StringIO.new
16
+ @log_utils = Class.new { include LogUtils }.new
17
+ @log_utils.instance_variable_set(:@log, LogUtils.create_default_logger(@log_io, log_utils.level))
18
+ end
19
+
20
+ def log_str
21
+ @log_io.string
22
+ end
23
+
24
+ it 'sets the log level based on $RAILS_ENV' do
25
+ expected = {
26
+ 'test' => Logger::DEBUG,
27
+ 'development' => Logger::INFO,
28
+ 'stage' => Logger::WARN,
29
+ 'production' => Logger::WARN
30
+ }
31
+ expected.each do |env, lvl|
32
+ ENV['RAILS_ENV'] = env
33
+ expect(Class.new { include LogUtils }.new.level).to eq(lvl)
34
+ end
35
+ end
36
+
37
+ it 'logs an error response' do
38
+ code = 404
39
+ body = 'Your princess is in another castle'
40
+ headers = { 'Location' => 'http://example.org' }
41
+ message = 'I am the message'
42
+
43
+ response = instance_double(RestClient::Response)
44
+ expect(response).to receive(:code) { code }
45
+ expect(response).to receive(:headers) { headers }
46
+ expect(response).to receive(:body) { body }
47
+
48
+ error = RestClient::ExceptionWithResponse.new(response, 999)
49
+ error.message = message
50
+
51
+ log_utils.log_error(error)
52
+ expect(log_str).to include(code.to_s)
53
+ expect(log_str).to include(body)
54
+ headers.each do |k, v|
55
+ expect(log_str).to include("#{k}: #{v}")
56
+ end
57
+ expect(log_str).to include(message)
58
+ end
59
+
60
+ it 'logs an error with a nil response' do
61
+ message = 'I am the message'
62
+ error = RestClient::ExceptionWithResponse.new(nil, 999)
63
+ error.message = message
64
+ log_utils.log_error(error)
65
+ expect(log_str).to include(message)
66
+ end
67
+
68
+ it 'logs an error with a backtrace' do
69
+ backtrace = nil
70
+ begin
71
+ raise RestClient::ExceptionWithResponse.new(nil, 999)
72
+ rescue => e
73
+ backtrace = e.backtrace
74
+ log_utils.log_error(e)
75
+ end
76
+ expect(log_str).to include(backtrace.join("\n"))
77
+ end
78
+ end
79
+ end
80
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stash-sword
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Moles
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-15 00:00:00.000000000 Z
11
+ date: 2016-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -240,6 +240,7 @@ files:
240
240
  - spec/unit/stash/sword2/http_helper_get_spec.rb
241
241
  - spec/unit/stash/sword2/http_helper_post_spec.rb
242
242
  - spec/unit/stash/sword2/http_helper_put_spec.rb
243
+ - spec/unit/stash/sword2/log_spec.rb
243
244
  - spec/unit/stash/sword2/namespaces_spec.rb
244
245
  - spec/unit/stash/sword2/sequence_io_spec.rb
245
246
  - stash-sword.gemspec
@@ -263,7 +264,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
263
264
  version: '0'
264
265
  requirements: []
265
266
  rubyforge_project:
266
- rubygems_version: 2.4.5.1
267
+ rubygems_version: 2.6.8
267
268
  signing_key:
268
269
  specification_version: 4
269
270
  summary: Stash SWORD 2.0 connector
@@ -278,6 +279,6 @@ test_files:
278
279
  - spec/unit/stash/sword2/http_helper_get_spec.rb
279
280
  - spec/unit/stash/sword2/http_helper_post_spec.rb
280
281
  - spec/unit/stash/sword2/http_helper_put_spec.rb
282
+ - spec/unit/stash/sword2/log_spec.rb
281
283
  - spec/unit/stash/sword2/namespaces_spec.rb
282
284
  - spec/unit/stash/sword2/sequence_io_spec.rb
283
- has_rdoc: