berkeley_library-tind 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/build.yml +18 -0
- data/.gitignore +388 -0
- data/.idea/inspectionProfiles/Project_Default.xml +20 -0
- data/.idea/misc.xml +4 -0
- data/.idea/modules.xml +8 -0
- data/.idea/tind.iml +138 -0
- data/.idea/vcs.xml +6 -0
- data/.rubocop.yml +334 -0
- data/.ruby-version +1 -0
- data/.simplecov +8 -0
- data/.yardopts +1 -0
- data/CHANGES.md +58 -0
- data/Dockerfile +57 -0
- data/Gemfile +3 -0
- data/Jenkinsfile +18 -0
- data/LICENSE.md +21 -0
- data/README.md +73 -0
- data/Rakefile +20 -0
- data/berkeley_library-tind.gemspec +50 -0
- data/bin/tind-export +14 -0
- data/docker-compose.yml +15 -0
- data/lib/berkeley_library/tind.rb +3 -0
- data/lib/berkeley_library/tind/api.rb +1 -0
- data/lib/berkeley_library/tind/api/api.rb +132 -0
- data/lib/berkeley_library/tind/api/api_exception.rb +131 -0
- data/lib/berkeley_library/tind/api/collection.rb +82 -0
- data/lib/berkeley_library/tind/api/date_range.rb +67 -0
- data/lib/berkeley_library/tind/api/format.rb +32 -0
- data/lib/berkeley_library/tind/api/search.rb +100 -0
- data/lib/berkeley_library/tind/config.rb +103 -0
- data/lib/berkeley_library/tind/export.rb +1 -0
- data/lib/berkeley_library/tind/export/column.rb +54 -0
- data/lib/berkeley_library/tind/export/column_group.rb +144 -0
- data/lib/berkeley_library/tind/export/column_group_list.rb +131 -0
- data/lib/berkeley_library/tind/export/column_width_calculator.rb +76 -0
- data/lib/berkeley_library/tind/export/config.rb +154 -0
- data/lib/berkeley_library/tind/export/csv_exporter.rb +29 -0
- data/lib/berkeley_library/tind/export/export.rb +47 -0
- data/lib/berkeley_library/tind/export/export_command.rb +168 -0
- data/lib/berkeley_library/tind/export/export_exception.rb +8 -0
- data/lib/berkeley_library/tind/export/export_format.rb +67 -0
- data/lib/berkeley_library/tind/export/exporter.rb +105 -0
- data/lib/berkeley_library/tind/export/filter.rb +52 -0
- data/lib/berkeley_library/tind/export/no_results_error.rb +7 -0
- data/lib/berkeley_library/tind/export/ods_exporter.rb +138 -0
- data/lib/berkeley_library/tind/export/row.rb +24 -0
- data/lib/berkeley_library/tind/export/row_metrics.rb +18 -0
- data/lib/berkeley_library/tind/export/table.rb +175 -0
- data/lib/berkeley_library/tind/export/table_metrics.rb +116 -0
- data/lib/berkeley_library/tind/marc.rb +1 -0
- data/lib/berkeley_library/tind/marc/xml_reader.rb +144 -0
- data/lib/berkeley_library/tind/module_info.rb +14 -0
- data/lib/berkeley_library/util/arrays.rb +178 -0
- data/lib/berkeley_library/util/logging.rb +1 -0
- data/lib/berkeley_library/util/ods/spreadsheet.rb +170 -0
- data/lib/berkeley_library/util/ods/xml/content_doc.rb +26 -0
- data/lib/berkeley_library/util/ods/xml/document_node.rb +57 -0
- data/lib/berkeley_library/util/ods/xml/element_node.rb +106 -0
- data/lib/berkeley_library/util/ods/xml/loext/table_protection.rb +26 -0
- data/lib/berkeley_library/util/ods/xml/manifest/file_entry.rb +42 -0
- data/lib/berkeley_library/util/ods/xml/manifest/manifest.rb +73 -0
- data/lib/berkeley_library/util/ods/xml/manifest_doc.rb +26 -0
- data/lib/berkeley_library/util/ods/xml/namespace.rb +46 -0
- data/lib/berkeley_library/util/ods/xml/office/automatic_styles.rb +181 -0
- data/lib/berkeley_library/util/ods/xml/office/body.rb +17 -0
- data/lib/berkeley_library/util/ods/xml/office/document_content.rb +98 -0
- data/lib/berkeley_library/util/ods/xml/office/document_styles.rb +39 -0
- data/lib/berkeley_library/util/ods/xml/office/font_face_decls.rb +30 -0
- data/lib/berkeley_library/util/ods/xml/office/scripts.rb +17 -0
- data/lib/berkeley_library/util/ods/xml/office/spreadsheet.rb +37 -0
- data/lib/berkeley_library/util/ods/xml/office/styles.rb +39 -0
- data/lib/berkeley_library/util/ods/xml/style/cell_style.rb +58 -0
- data/lib/berkeley_library/util/ods/xml/style/column_style.rb +36 -0
- data/lib/berkeley_library/util/ods/xml/style/default_style.rb +31 -0
- data/lib/berkeley_library/util/ods/xml/style/family.rb +85 -0
- data/lib/berkeley_library/util/ods/xml/style/font_face.rb +46 -0
- data/lib/berkeley_library/util/ods/xml/style/paragraph_properties.rb +30 -0
- data/lib/berkeley_library/util/ods/xml/style/row_style.rb +37 -0
- data/lib/berkeley_library/util/ods/xml/style/style.rb +44 -0
- data/lib/berkeley_library/util/ods/xml/style/table_cell_properties.rb +40 -0
- data/lib/berkeley_library/util/ods/xml/style/table_column_properties.rb +30 -0
- data/lib/berkeley_library/util/ods/xml/style/table_properties.rb +25 -0
- data/lib/berkeley_library/util/ods/xml/style/table_row_properties.rb +28 -0
- data/lib/berkeley_library/util/ods/xml/style/table_style.rb +27 -0
- data/lib/berkeley_library/util/ods/xml/style/text_properties.rb +52 -0
- data/lib/berkeley_library/util/ods/xml/styles_doc.rb +26 -0
- data/lib/berkeley_library/util/ods/xml/table/named_expressions.rb +17 -0
- data/lib/berkeley_library/util/ods/xml/table/repeatable.rb +38 -0
- data/lib/berkeley_library/util/ods/xml/table/table.rb +193 -0
- data/lib/berkeley_library/util/ods/xml/table/table_cell.rb +46 -0
- data/lib/berkeley_library/util/ods/xml/table/table_column.rb +43 -0
- data/lib/berkeley_library/util/ods/xml/table/table_row.rb +136 -0
- data/lib/berkeley_library/util/ods/xml/text/p.rb +118 -0
- data/lib/berkeley_library/util/paths.rb +111 -0
- data/lib/berkeley_library/util/stringios.rb +30 -0
- data/lib/berkeley_library/util/strings.rb +42 -0
- data/lib/berkeley_library/util/sys_exits.rb +15 -0
- data/lib/berkeley_library/util/times.rb +22 -0
- data/lib/berkeley_library/util/uris.rb +44 -0
- data/lib/berkeley_library/util/uris/appender.rb +162 -0
- data/lib/berkeley_library/util/uris/requester.rb +62 -0
- data/lib/berkeley_library/util/uris/validator.rb +32 -0
- data/rakelib/bundle.rake +8 -0
- data/rakelib/coverage.rake +11 -0
- data/rakelib/gem.rake +54 -0
- data/rakelib/rubocop.rake +18 -0
- data/rakelib/spec.rake +2 -0
- data/spec/.rubocop.yml +40 -0
- data/spec/berkeley_library/tind/api/api_exception_spec.rb +91 -0
- data/spec/berkeley_library/tind/api/api_spec.rb +143 -0
- data/spec/berkeley_library/tind/api/collection_spec.rb +74 -0
- data/spec/berkeley_library/tind/api/date_range_spec.rb +110 -0
- data/spec/berkeley_library/tind/api/format_spec.rb +54 -0
- data/spec/berkeley_library/tind/api/search_spec.rb +364 -0
- data/spec/berkeley_library/tind/config_spec.rb +86 -0
- data/spec/berkeley_library/tind/export/column_group_spec.rb +29 -0
- data/spec/berkeley_library/tind/export/column_spec.rb +43 -0
- data/spec/berkeley_library/tind/export/config_spec.rb +206 -0
- data/spec/berkeley_library/tind/export/export_command_spec.rb +169 -0
- data/spec/berkeley_library/tind/export/export_format_spec.rb +59 -0
- data/spec/berkeley_library/tind/export/export_matcher.rb +112 -0
- data/spec/berkeley_library/tind/export/export_spec.rb +150 -0
- data/spec/berkeley_library/tind/export/exporter_spec.rb +125 -0
- data/spec/berkeley_library/tind/export/row_spec.rb +118 -0
- data/spec/berkeley_library/tind/export/table_spec.rb +322 -0
- data/spec/berkeley_library/tind/marc/xml_reader_spec.rb +93 -0
- data/spec/berkeley_library/util/arrays_spec.rb +340 -0
- data/spec/berkeley_library/util/ods/spreadsheet_spec.rb +124 -0
- data/spec/berkeley_library/util/ods/xml/content_doc_spec.rb +121 -0
- data/spec/berkeley_library/util/ods/xml/manifest/file_entry_spec.rb +27 -0
- data/spec/berkeley_library/util/ods/xml/manifest/manifest_spec.rb +33 -0
- data/spec/berkeley_library/util/ods/xml/office/document_content_spec.rb +60 -0
- data/spec/berkeley_library/util/ods/xml/style/automatic_styles_spec.rb +37 -0
- data/spec/berkeley_library/util/ods/xml/style/family_spec.rb +57 -0
- data/spec/berkeley_library/util/ods/xml/table/table_row_spec.rb +179 -0
- data/spec/berkeley_library/util/ods/xml/table/table_spec.rb +218 -0
- data/spec/berkeley_library/util/paths_spec.rb +90 -0
- data/spec/berkeley_library/util/stringios_spec.rb +34 -0
- data/spec/berkeley_library/util/strings_spec.rb +27 -0
- data/spec/berkeley_library/util/times_spec.rb +39 -0
- data/spec/berkeley_library/util/uris_spec.rb +118 -0
- data/spec/data/collection-names.txt +438 -0
- data/spec/data/collections.json +4827 -0
- data/spec/data/disjoint-records.xml +187 -0
- data/spec/data/record-184453.xml +58 -0
- data/spec/data/record-184458.xml +63 -0
- data/spec/data/record-187888.xml +78 -0
- data/spec/data/records-api-search-cjk-p1.xml +6381 -0
- data/spec/data/records-api-search-cjk-p2.xml +5 -0
- data/spec/data/records-api-search-p1.xml +4506 -0
- data/spec/data/records-api-search-p2.xml +4509 -0
- data/spec/data/records-api-search-p3.xml +4506 -0
- data/spec/data/records-api-search-p4.xml +4509 -0
- data/spec/data/records-api-search-p5.xml +4506 -0
- data/spec/data/records-api-search-p6.xml +2436 -0
- data/spec/data/records-api-search-p7.xml +5 -0
- data/spec/data/records-api-search.xml +234 -0
- data/spec/data/records-manual-search.xml +547 -0
- data/spec/spec_helper.rb +30 -0
- data/test/profile/table_from_records_profile.rb +46 -0
- metadata +585 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module BerkeleyLibrary
|
4
|
+
module Util
|
5
|
+
module URIs
|
6
|
+
module Validator
|
7
|
+
class << self
|
8
|
+
|
9
|
+
# Returns the specified URL as a URI.
|
10
|
+
# @param url [String, URI] the URL.
|
11
|
+
# @return [URI] the URI.
|
12
|
+
# @raise [URI::InvalidURIError] if `url` cannot be parsed as a URI.
|
13
|
+
def uri_or_nil(url)
|
14
|
+
return unless url
|
15
|
+
|
16
|
+
# noinspection RubyYardReturnMatch
|
17
|
+
url.is_a?(URI) ? url : URI.parse(url.to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns the specified URL as a string.
|
21
|
+
# @param url [String, URI] the URL.
|
22
|
+
# @return [String] the URL.
|
23
|
+
# @raise [URI::InvalidURIError] if `url` cannot be parsed as a URI.
|
24
|
+
def url_str_or_nil(url)
|
25
|
+
uri = Validator.uri_or_nil(url)
|
26
|
+
uri.to_s if uri
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/rakelib/bundle.rake
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'ci/reporter/rake/rspec'
|
2
|
+
|
3
|
+
# Configure CI::Reporter report generation
|
4
|
+
ENV['GENERATE_REPORTS'] ||= 'true'
|
5
|
+
ENV['CI_REPORTS'] = 'artifacts/rspec'
|
6
|
+
|
7
|
+
desc 'Run all specs in spec directory, with coverage'
|
8
|
+
task coverage: ['ci:setup:rspec'] do
|
9
|
+
ENV['COVERAGE'] ||= 'true'
|
10
|
+
Rake::Task[:spec].invoke
|
11
|
+
end
|
data/rakelib/gem.rake
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems/gem_runner'
|
2
|
+
require 'berkeley_library/tind/module_info'
|
3
|
+
|
4
|
+
gem_root_module = BerkeleyLibrary::TIND
|
5
|
+
|
6
|
+
class << gem_root_module
|
7
|
+
def project_root
|
8
|
+
@project_root ||= File.expand_path('..', __dir__)
|
9
|
+
end
|
10
|
+
|
11
|
+
def artifacts_dir
|
12
|
+
return project_root unless ENV['CI']
|
13
|
+
|
14
|
+
@artifacts_dir ||= File.join(project_root, 'artifacts')
|
15
|
+
end
|
16
|
+
|
17
|
+
def gemspec_file
|
18
|
+
@gemspec_file ||= begin
|
19
|
+
gemspec_files = Dir.glob(File.expand_path('*.gemspec', project_root))
|
20
|
+
raise ArgumentError, "Too many .gemspecs: #{gemspec_files.join(', ')}" if gemspec_files.size > 1
|
21
|
+
raise ArgumentError, 'No .gemspec file found' if gemspec_files.empty?
|
22
|
+
|
23
|
+
gemspec_files[0]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def gemspec_basename
|
28
|
+
File.basename(gemspec_file)
|
29
|
+
end
|
30
|
+
|
31
|
+
def output_file
|
32
|
+
@output_file ||= begin
|
33
|
+
gem_name = File.basename(gemspec_file, '.*')
|
34
|
+
version = self::ModuleInfo::VERSION
|
35
|
+
basename = "#{gem_name}-#{version}.gem"
|
36
|
+
File.join(artifacts_dir, basename)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def output_file_relative
|
41
|
+
return File.basename(output_file) unless ENV['CI']
|
42
|
+
|
43
|
+
@output_file_relative ||= begin
|
44
|
+
artifacts_dir_relative = File.basename(artifacts_dir)
|
45
|
+
File.join(artifacts_dir_relative, File.basename(output_file))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Build #{gem_root_module.gemspec_basename} as #{gem_root_module.output_file_relative}"
|
51
|
+
task :gem do
|
52
|
+
args = ['build', gem_root_module.gemspec_file, "--output=#{gem_root_module.output_file}"]
|
53
|
+
Gem::GemRunner.new.run(args)
|
54
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubocop'
|
2
|
+
require 'rubocop/rake_task'
|
3
|
+
|
4
|
+
desc 'Run rubocop with HTML output'
|
5
|
+
RuboCop::RakeTask.new(:rubocop) do |cop|
|
6
|
+
output = ENV['RUBOCOP_OUTPUT'] || 'artifacts/rubocop/index.html'
|
7
|
+
puts "Writing RuboCop inspection report to #{output}"
|
8
|
+
|
9
|
+
cop.verbose = false
|
10
|
+
cop.formatters = ['html']
|
11
|
+
cop.options = ['--out', output]
|
12
|
+
end
|
13
|
+
|
14
|
+
desc 'Run RuboCop with auto-correct, and output results to console'
|
15
|
+
task :ra do
|
16
|
+
# b/c we want console output, we can't just use `rubocop:auto_correct`
|
17
|
+
RuboCop::CLI.new.run(['--safe-auto-correct'])
|
18
|
+
end
|
data/rakelib/spec.rake
ADDED
data/spec/.rubocop.yml
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
inherit_from: ../.rubocop.yml
|
2
|
+
|
3
|
+
AllCops:
|
4
|
+
# Exclude generated files
|
5
|
+
Exclude:
|
6
|
+
- 'suite/**/*'
|
7
|
+
|
8
|
+
Style/ClassAndModuleChildren:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Style/MultilineBlockChain:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
Style/ParallelAssignment:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Layout/LineLength:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Metrics/AbcSize:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Metrics/BlockLength:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Metrics/ClassLength:
|
27
|
+
Enabled: false
|
28
|
+
|
29
|
+
Metrics/ModuleLength:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
Metrics/MethodLength:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
############################################################
|
36
|
+
# Added in Rubocop 0.89
|
37
|
+
|
38
|
+
# Sometimes we're testing the operator
|
39
|
+
Lint/BinaryOperatorWithIdenticalOperands:
|
40
|
+
Enabled: false
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rest-client'
|
3
|
+
|
4
|
+
module BerkeleyLibrary
|
5
|
+
module TIND
|
6
|
+
module API
|
7
|
+
describe APIException do
|
8
|
+
describe :wrap do
|
9
|
+
it 'rejects nil' do
|
10
|
+
expect { APIException.wrap(nil) }.to raise_error(ArgumentError)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'RestClient::RequestFailed' do
|
14
|
+
it 'extracts the status info and response' do
|
15
|
+
url = 'https://example.org'
|
16
|
+
params = { 'foo' => 'bar' }
|
17
|
+
expected_body = 'oops'
|
18
|
+
stub_request(:get, url).with(query: params).to_return(status: 500, body: expected_body)
|
19
|
+
|
20
|
+
expected_msg = 'the wrapper message'
|
21
|
+
expect do
|
22
|
+
RestClient.get(url, params: params)
|
23
|
+
rescue StandardError => e
|
24
|
+
raise APIException.wrap(e, url: url, params: params, detail: expected_msg)
|
25
|
+
end.to raise_error do |e|
|
26
|
+
expect(e).to be_a(APIException)
|
27
|
+
expect(e.cause).to be_a(RestClient::RequestFailed)
|
28
|
+
expect(e.status_code).to eq(500)
|
29
|
+
expect(e.status_message).to eq('500 Internal Server Error')
|
30
|
+
expect(e.body).to eq(expected_body)
|
31
|
+
expect(e.response).to be(e.cause.response)
|
32
|
+
expect(e.url).to eq(url)
|
33
|
+
expect(e.params).to eq(params)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'works with or without parameters' do
|
38
|
+
url = 'https://example.org'
|
39
|
+
expected_body = 'oops'
|
40
|
+
stub_request(:get, url).to_return(status: 500, body: expected_body)
|
41
|
+
|
42
|
+
expected_msg = 'the wrapper message'
|
43
|
+
expect do
|
44
|
+
RestClient.get(url)
|
45
|
+
rescue StandardError => e
|
46
|
+
raise APIException.wrap(e, url: url, detail: expected_msg)
|
47
|
+
end.to raise_error do |e|
|
48
|
+
expect(e).to be_a(APIException)
|
49
|
+
expect(e.cause).to be_a(RestClient::RequestFailed)
|
50
|
+
expect(e.status_code).to eq(500)
|
51
|
+
expect(e.status_message).to eq('500 Internal Server Error')
|
52
|
+
expect(e.body).to eq(expected_body)
|
53
|
+
expect(e.response).to be(e.cause.response)
|
54
|
+
expect(e.url).to eq(url)
|
55
|
+
expect(e.params).to be_nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe 'any exception' do
|
61
|
+
it 'wraps an exception' do
|
62
|
+
expected_msg = 'the message'
|
63
|
+
expect do
|
64
|
+
|
65
|
+
raise expected_msg
|
66
|
+
rescue StandardError => e
|
67
|
+
raise APIException.wrap(e)
|
68
|
+
end.to raise_error do |e|
|
69
|
+
expect(e).to be_a(APIException)
|
70
|
+
expect(e.message).to eq(expected_msg)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'overrides the message' do
|
75
|
+
expected_msg = 'the message'
|
76
|
+
expect do
|
77
|
+
|
78
|
+
raise "not #{expected_msg}"
|
79
|
+
rescue StandardError => e
|
80
|
+
raise APIException.wrap(e, msg: expected_msg)
|
81
|
+
end.to raise_error do |e|
|
82
|
+
expect(e).to be_a(APIException)
|
83
|
+
expect(e.message).to eq(expected_msg)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'webmock'
|
3
|
+
|
4
|
+
module BerkeleyLibrary
|
5
|
+
module TIND
|
6
|
+
RSpec.shared_examples 'a missing key' do |bad_key|
|
7
|
+
before(:each) do
|
8
|
+
expect(BerkeleyLibrary::TIND::Config).to receive(:api_key).and_return(bad_key)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "raises #{API::APIKeyNotSet}" do
|
12
|
+
failure_message = -> { "#{API::APIKeyNotSet} not raised for API key #{bad_key.inspect}" }
|
13
|
+
expect { API.get('some-endpoint') }.to raise_error(API::APIKeyNotSet), failure_message
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
RSpec.shared_examples 'a missing base URL' do |bad_url|
|
18
|
+
before(:each) do
|
19
|
+
allow(BerkeleyLibrary::TIND::Config).to receive(:base_uri).and_return(bad_url)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "raises #{API::APIKeyNotSet}" do
|
23
|
+
failure_message = -> { "#{API::BaseURINotSet} not raised for API key #{bad_url.inspect}" }
|
24
|
+
expect { API.get('some-endpoint') }.to raise_error(API::BaseURINotSet), failure_message
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe API do
|
29
|
+
let(:base_uri) { 'https://tind.example.org/' }
|
30
|
+
let(:api_key) { 'lorem-ipsum-dolor-sit-amet' }
|
31
|
+
|
32
|
+
describe :get do
|
33
|
+
describe 'with invalid API key' do
|
34
|
+
before(:each) do
|
35
|
+
allow(BerkeleyLibrary::TIND::Config).to receive(:base_uri).and_return(base_uri)
|
36
|
+
end
|
37
|
+
|
38
|
+
[nil, '', ' '].each do |bad_key|
|
39
|
+
describe "api_key = #{bad_key.inspect}" do
|
40
|
+
it_behaves_like 'a missing key', bad_key
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'bad TIND base URI' do
|
47
|
+
before(:each) do
|
48
|
+
allow(BerkeleyLibrary::TIND::Config).to receive(:api_key).and_return(api_key)
|
49
|
+
end
|
50
|
+
|
51
|
+
[nil, '', ' '].each do |bad_url|
|
52
|
+
describe "base_uri = #{bad_url.inspect}" do
|
53
|
+
it_behaves_like 'a missing base URL', bad_url
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'with valid config' do
|
59
|
+
before(:each) do
|
60
|
+
allow(BerkeleyLibrary::TIND::Config).to receive(:base_uri).and_return(base_uri)
|
61
|
+
allow(BerkeleyLibrary::TIND::Config).to receive(:api_key).and_return(api_key)
|
62
|
+
end
|
63
|
+
|
64
|
+
describe :get do
|
65
|
+
it "raises #{API::APIException} in the event of an invalid response" do
|
66
|
+
aggregate_failures 'responses' do
|
67
|
+
[207, 400, 401, 403, 404, 405, 418, 451, 500, 503].each do |code|
|
68
|
+
endpoint = "endpoint-#{code}"
|
69
|
+
url_str = API.uri_for(endpoint).to_s
|
70
|
+
stub_request(:get, url_str).to_return(status: code)
|
71
|
+
|
72
|
+
expect { API.get(endpoint) }.to raise_error(API::APIException) do |e|
|
73
|
+
expect(e.message).to include(code.to_s)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'logs the response body if an error occurs in handling' do
|
80
|
+
endpoint = 'test-endpoint'
|
81
|
+
url_str = API.uri_for(endpoint).to_s
|
82
|
+
body_text = 'the body'
|
83
|
+
stub_request(:get, url_str).to_return(status: 200, body: body_text)
|
84
|
+
|
85
|
+
logdev = StringIO.new
|
86
|
+
logger = BerkeleyLibrary::Logging::Loggers.new_readable_logger(logdev)
|
87
|
+
allow(BerkeleyLibrary::Logging).to receive(:logger).and_return(logger)
|
88
|
+
|
89
|
+
msg = 'the error message'
|
90
|
+
expect { API.get(endpoint) { |_| raise(StandardError, msg) } }.to raise_error(StandardError, msg)
|
91
|
+
expect(logdev.string).to include(body_text)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'sends a default user agent' do
|
95
|
+
expected_ua = Config::DEFAULT_USER_AGENT
|
96
|
+
|
97
|
+
endpoint = 'test-endpoint'
|
98
|
+
url_str = API.uri_for(endpoint).to_s
|
99
|
+
body_text = 'the body'
|
100
|
+
stub_request(:get, url_str).with(headers: { 'User-Agent' => expected_ua })
|
101
|
+
.to_return(status: 200, body: body_text)
|
102
|
+
|
103
|
+
result = API.get(endpoint)
|
104
|
+
expect(result).to eq(body_text)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'sends a configured user ageint' do
|
108
|
+
expected_ua = 'Help I am trapped in an HTTP request'
|
109
|
+
Config.user_agent = expected_ua
|
110
|
+
|
111
|
+
endpoint = 'test-endpoint'
|
112
|
+
url_str = API.uri_for(endpoint).to_s
|
113
|
+
body_text = 'the body'
|
114
|
+
stub_request(:get, url_str).with(headers: { 'User-Agent' => expected_ua })
|
115
|
+
.to_return(status: 200, body: body_text)
|
116
|
+
|
117
|
+
result = API.get(endpoint)
|
118
|
+
expect(result).to eq(body_text)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe :format_request do
|
124
|
+
it 'formats a request' do
|
125
|
+
url = 'https://example.org/frob'
|
126
|
+
params = { foo: 'bar', 'qux' => 'baz' }
|
127
|
+
expected_url = 'https://example.org/frob?foo=bar&qux=baz'
|
128
|
+
expect(API.format_request(url, params)).to eq("GET #{expected_url}")
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'works without parameters' do
|
132
|
+
url = 'https://example.org/frob'
|
133
|
+
expect(API.format_request(url)).to eq("GET #{url}")
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'rejects garbage parameters' do
|
137
|
+
# noinspection RubyYardParamTypeMatch
|
138
|
+
expect { API.format_request('https://example.org', Object.new) }.to raise_error(ArgumentError)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'webmock'
|
3
|
+
|
4
|
+
module BerkeleyLibrary
|
5
|
+
module TIND
|
6
|
+
module API
|
7
|
+
describe Collection do
|
8
|
+
let(:base_uri) { 'https://tind.example.org/' }
|
9
|
+
let(:api_key) { 'not-a-real-api-key' }
|
10
|
+
|
11
|
+
before(:each) do
|
12
|
+
@base_uri_orig = BerkeleyLibrary::TIND::Config.instance_variable_get(:@base_uri)
|
13
|
+
BerkeleyLibrary::TIND::Config.base_uri = base_uri
|
14
|
+
|
15
|
+
@api_key_orig = BerkeleyLibrary::TIND::Config.instance_variable_get(:@api_key)
|
16
|
+
BerkeleyLibrary::TIND::Config.api_key = api_key
|
17
|
+
end
|
18
|
+
|
19
|
+
after(:each) do
|
20
|
+
BerkeleyLibrary::TIND::Config.instance_variable_set(:@base_uri, @base_uri_orig)
|
21
|
+
BerkeleyLibrary::TIND::Config.instance_variable_set(:@api_key, @api_key_orig)
|
22
|
+
end
|
23
|
+
|
24
|
+
describe :all do
|
25
|
+
it 'reads the collections from the API' do
|
26
|
+
query_uri = BerkeleyLibrary::Util::URIs.append(base_uri, '/api/v1/collections?depth=100')
|
27
|
+
stub_request(:get, query_uri)
|
28
|
+
.with(headers: { 'Authorization' => 'Token not-a-real-api-key' })
|
29
|
+
.to_return(status: 200, body: File.read('spec/data/collections.json'))
|
30
|
+
|
31
|
+
all_collections = Collection.all
|
32
|
+
expect(all_collections.size).to eq(1)
|
33
|
+
expect(root_collection = all_collections.first).not_to be_nil
|
34
|
+
expect(root_collection.name).to eq('Digital Collections')
|
35
|
+
|
36
|
+
top_level_collections = root_collection.children
|
37
|
+
expect(top_level_collections.map(&:name)).to eq(['Bampfa', 'Bancroft Library', 'Berkeley Library', 'East Asian Library', 'Humanities & Social Sciences', 'Sciences'])
|
38
|
+
|
39
|
+
bancroft = top_level_collections.find { |c| c.name == 'Bancroft Library' }
|
40
|
+
examiner = bancroft.children.find { |c| c.name == 'SFExaminer' }
|
41
|
+
expect(examiner.name_en).to eq('San Francisco Examiner')
|
42
|
+
expect(examiner.size).to eq(15_564)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns an empty array in the event of an error' do
|
46
|
+
query_uri = BerkeleyLibrary::Util::URIs.append(base_uri, '/api/v1/collections?depth=100')
|
47
|
+
stub_request(:get, query_uri).to_return(status: 404)
|
48
|
+
|
49
|
+
expect(Collection.all).to eq([])
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'raises an error if the API key is not set' do
|
53
|
+
BerkeleyLibrary::TIND::API.instance_variable_set(:@api_key, nil)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe :each_collection do
|
58
|
+
it 'yields each collection' do
|
59
|
+
collections_json = File.read('spec/data/collections.json')
|
60
|
+
expected_names = File.readlines('spec/data/collection-names.txt', chomp: true)
|
61
|
+
|
62
|
+
query_uri = BerkeleyLibrary::Util::URIs.append(base_uri, '/api/v1/collections?depth=100')
|
63
|
+
stub_request(:get, query_uri)
|
64
|
+
.with(headers: { 'Authorization' => 'Token not-a-real-api-key' })
|
65
|
+
.to_return(status: 200, body: collections_json)
|
66
|
+
|
67
|
+
actual_names = Collection.each_collection.each_with_object([]) { |c, arr| arr << c.name }
|
68
|
+
expect(actual_names).to contain_exactly(*expected_names)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|