borrow_direct 1.1.0 → 1.2.0.pre1

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.
Files changed (91) hide show
  1. checksums.yaml +5 -13
  2. data/.travis.yml +6 -0
  3. data/Gemfile +2 -0
  4. data/README.md +19 -6
  5. data/bd_metrics/finditem_measure.rb +8 -1
  6. data/borrow_direct.gemspec +1 -1
  7. data/lib/borrow_direct/authentication.rb +16 -8
  8. data/lib/borrow_direct/defaults.rb +4 -1
  9. data/lib/borrow_direct/encryption.rb +34 -0
  10. data/lib/borrow_direct/error.rb +17 -0
  11. data/lib/borrow_direct/find_item.rb +32 -18
  12. data/lib/borrow_direct/pickup_location.rb +32 -0
  13. data/lib/borrow_direct/request.rb +30 -8
  14. data/lib/borrow_direct/request_item.rb +15 -7
  15. data/lib/borrow_direct/request_query.rb +18 -4
  16. data/lib/borrow_direct/version.rb +1 -1
  17. data/test/authentication_test.rb +40 -12
  18. data/test/encryption_test.rb +58 -0
  19. data/test/find_item_test.rb +66 -11
  20. data/test/request_item_test.rb +65 -8
  21. data/test/request_query_test.rb +23 -27
  22. data/test/request_test.rb +40 -27
  23. data/test/test_helper.rb +10 -1
  24. data/test/vcr_cassettes/Authentication/Makes_a_request_succesfully.yml +11 -23
  25. data/test/vcr_cassettes/Authentication/Raises_for_bad_library_symbol.yml +12 -23
  26. data/test/vcr_cassettes/Authentication/Raises_for_bad_patron_barcode.yml +12 -24
  27. data/test/vcr_cassettes/Authentication/get_auth_id/Raises_for_bad_api_key.yml +41 -0
  28. data/test/vcr_cassettes/Authentication/get_auth_id/raises_for_a_bad_library_symbol.yml +12 -23
  29. data/test/vcr_cassettes/Authentication/get_auth_id/raises_for_a_bad_patron_barcode.yml +12 -24
  30. data/test/vcr_cassettes/Authentication/get_auth_id/returns_an_auth_id_for_a_good_request.yml +11 -23
  31. data/test/vcr_cassettes/Authentication/get_auth_id/returns_auth_id_with_API_key_from_defaults.yml +40 -0
  32. data/test/vcr_cassettes/Authentication/raw_request_to_verify_HTTP_api/works.yml +11 -23
  33. data/test/vcr_cassettes/FindItem/_find_item_request/Raises_with_bad_api_key.yml +41 -0
  34. data/test/vcr_cassettes/FindItem/_find_item_request/finds_a_locally_available_item.yml +47 -18
  35. data/test/vcr_cassettes/FindItem/_find_item_request/finds_a_requestable_item.yml +66 -18
  36. data/test/vcr_cassettes/FindItem/_find_item_request/finds_an_item_that_does_not_exist_in_BD.yml +66 -19
  37. data/test/vcr_cassettes/FindItem/_find_item_request/raises_proper_error_on_bad_AID.yml +40 -0
  38. data/test/vcr_cassettes/FindItem/_find_item_request/uses_manually_set_auth_id.yml +97 -0
  39. data/test/vcr_cassettes/FindItem/_find_item_request/with_expected_error_PUBFI002/returns_result.yml +46 -9
  40. data/test/vcr_cassettes/FindItem/_find_item_request/works_with_multiple_values.yml +66 -18
  41. data/test/vcr_cassettes/FindItem/find_with_Response/_pickup_location_data/returns_array_of_PickupLocations.yml +97 -0
  42. data/test/vcr_cassettes/FindItem/find_with_Response/has_an_auth_id.yml +66 -18
  43. data/test/vcr_cassettes/FindItem/find_with_Response/has_nil_pickup_locations_when_BD_doesn_t_want_to_give_us_them.yml +46 -9
  44. data/test/vcr_cassettes/FindItem/find_with_Response/has_pickup_locations.yml +66 -18
  45. data/test/vcr_cassettes/FindItem/find_with_Response/knows_locally_available_.yml +47 -18
  46. data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_item_that_BD_returns_PUBFI002.yml +46 -9
  47. data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_item_that_does_not_exist_in_BD.yml +46 -19
  48. data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_item_that_no_libraries_will_lend.yml +275 -18
  49. data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_locally_available_item.yml +47 -18
  50. data/test/vcr_cassettes/FindItem/find_with_Response/requestable_for_requestable_item.yml +66 -18
  51. data/test/vcr_cassettes/FindItem/find_with_Response/requestable_with_multiple_items_if_at_least_one_is_requestable.yml +66 -18
  52. data/test/vcr_cassettes/Request/authentication_id/automatically_fetches_one_when_needed.yml +47 -22
  53. data/test/vcr_cassettes/Request/authentication_id/can_refetch_when_instructed.yml +47 -22
  54. data/test/vcr_cassettes/Request/authentication_id/manually_set_one_will_be_used_without_fetch.yml +40 -0
  55. data/test/vcr_cassettes/Request/authentication_id/starts_out_nil.yml +40 -0
  56. data/test/vcr_cassettes/Request/authentication_id/takes_with_auth_id.yml +40 -0
  57. data/test/vcr_cassettes/Request/can_make_a_succesful_request_with_AID.yml +97 -0
  58. data/test/vcr_cassettes/Request/gets_BD_error_info.yml +49 -12
  59. data/test/vcr_cassettes/Request/gets_BD_error_info_from_a_bad_AID.yml +77 -0
  60. data/test/vcr_cassettes/Request/raises_exception_on_timeout_live.yml +40 -0
  61. data/test/vcr_cassettes/Request/raises_on_bad_path.yml +61 -24
  62. data/test/vcr_cassettes/Request/raises_on_bad_request_hash.yml +50 -35
  63. data/test/vcr_cassettes/Request/uses_timeout_for_HttpClient.yml +40 -0
  64. data/test/vcr_cassettes/Request/with_expected_errors/still_returns_result.yml +47 -10
  65. data/test/vcr_cassettes/RequestItem/make_request/make_request_for_a_locally_available_item.yml +21 -33
  66. data/test/vcr_cassettes/RequestItem/make_request/make_request_for_a_requestable_item.yml +20 -32
  67. data/test/vcr_cassettes/RequestItem/make_request/make_request_for_an_unrequestable_item.yml +21 -33
  68. data/test/vcr_cassettes/RequestItem/make_request/says_no_for_item_that_BD_returns_PUBRI003.yml +77 -0
  69. data/test/vcr_cassettes/RequestItem/make_request/sets_an_auth_id.yml +77 -0
  70. data/test/vcr_cassettes/RequestItem/make_request_/raises_for_unrequestable.yml +21 -33
  71. data/test/vcr_cassettes/RequestItem/make_request_/returns_number_for_succesful_request.yml +20 -32
  72. data/test/vcr_cassettes/RequestItem/raises_proper_error_on_bad_AID.yml +40 -0
  73. data/test/vcr_cassettes/RequestItem/raw_RequestItem_sanity_check.yml +134 -0
  74. data/test/vcr_cassettes/RequestItem/raw_requests_an_unrequestable_item.yml +21 -33
  75. data/test/vcr_cassettes/RequestItem/uses_manually_set_auth_id.yml +20 -32
  76. data/test/vcr_cassettes/RequestItem/with_pickup_location_and_requestable_item/works_with_String_pickup_location.yml +78 -0
  77. data/test/vcr_cassettes/RequestItem/with_pickup_location_and_requestable_item/works_with_structured_PickupLocation.yml +77 -0
  78. data/test/vcr_cassettes/RequestQuery/raises_proper_error_on_bad_AID.yml +40 -0
  79. data/test/vcr_cassettes/RequestQuery/raw_request_query_request/returns_results.yml +117 -325
  80. data/test/vcr_cassettes/RequestQuery/raw_request_to_verify_the_BD_HTTP_API.yml +30 -325
  81. data/test/vcr_cassettes/RequestQuery/requests/fetches_default_records.yml +117 -328
  82. data/test/vcr_cassettes/RequestQuery/requests/fetches_full_records.yml +148 -425
  83. metadata +67 -38
  84. data/test/vcr_cassettes/Authentication/raw_request_to_verify_HTTP_api/.yml +0 -52
  85. data/test/vcr_cassettes/FindItem/find_with_Response/has_nil_auth_id_when_BD_doesn_t_want_to_give_us_one.yml +0 -40
  86. data/test/vcr_cassettes/Request/can_make_a_succesful_request.yml +0 -49
  87. data/test/vcr_cassettes/RequestItem/make_request/raises_for_unrequestable.yml +0 -91
  88. data/test/vcr_cassettes/RequestItem/make_request/returns_number_for_succesful_request.yml +0 -89
  89. data/test/vcr_cassettes/RequestItem/make_request/says_no_for_item_that_BD_returns_PUBRI004.yml +0 -89
  90. data/test/vcr_cassettes/RequestItem/with_pickup_location_and_requestable_item/still_works.yml +0 -90
  91. data/test/vcr_cassettes/top_level_describe/an_inner_describe/.yml +0 -76
@@ -6,14 +6,15 @@ require 'httpclient'
6
6
  describe "Authentication", :vcr => {:tag => :bd_auth} do
7
7
  describe "raw request to verify HTTP api" do
8
8
  it "works" do
9
- uri = BorrowDirect::Defaults.api_base.chomp("/") + "/portal-service/user/authentication/patron"
9
+ uri = BorrowDirect::Defaults.api_base.chomp("/") + "/portal-service/user/authentication"
10
10
 
11
11
 
12
12
  request_hash = {
13
- "AuthenticationInformation" => {
14
- "LibrarySymbol" => VCRFilter[:bd_library_symbol],
15
- "PatronId" => VCRFilter[:bd_patron]
16
- }
13
+ "ApiKey" => VCRFilter[:bd_api_key],
14
+ "PartnershipId" => BorrowDirect::Defaults.partnership_id,
15
+ "UserGroup" => "patron",
16
+ "LibrarySymbol" => VCRFilter[:bd_library_symbol],
17
+ "PatronId" => VCRFilter[:bd_patron]
17
18
  }
18
19
 
19
20
  http = HTTPClient.new
@@ -26,47 +27,74 @@ describe "Authentication", :vcr => {:tag => :bd_auth} do
26
27
 
27
28
  assert_present response_hash
28
29
 
29
- assert_present response_hash["Authentication"]["AuthnUserInfo"]["AId"]
30
+ assert_present response_hash["AuthorizationId"]
30
31
  end
31
32
  end
32
33
 
33
34
  it "Makes a request succesfully" do
34
- bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol])
35
+ bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol], VCRFilter[:bd_api_key])
35
36
  response = bd.authentication_request
36
37
 
37
38
  assert_present response
38
- assert_present response["Authentication"]["AuthnUserInfo"]["AId"]
39
+ assert_present response["AuthorizationId"]
39
40
  end
40
41
 
42
+
43
+
41
44
  it "Raises for bad library symbol" do
42
- bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , "BAD_SYMBOL")
45
+ bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , "BAD_SYMBOL", VCRFilter[:bd_api_key])
43
46
  assert_raises(BorrowDirect::Error) do
44
47
  bd.authentication_request
45
48
  end
46
49
  end
47
50
 
48
51
  it "Raises for bad patron barcode" do
49
- bd = BorrowDirect::Authentication.new("BAD_BARCODE", VCRFilter[:bd_library_symbol])
52
+ bd = BorrowDirect::Authentication.new("BAD_BARCODE", VCRFilter[:bd_library_symbol], VCRFilter[:bd_api_key])
50
53
  assert_raises(BorrowDirect::Error) do
51
54
  bd.authentication_request
52
55
  end
53
56
  end
54
57
 
58
+ it "Raises with no api_key" do
59
+ begin
60
+ orig_api_key = BorrowDirect::Defaults.api_key
61
+ BorrowDirect::Defaults.api_key = nil
62
+
63
+ assert_raises(ArgumentError) do
64
+ bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol])
65
+ end
66
+ ensure
67
+ BorrowDirect::Defaults.api_key = orig_api_key
68
+ end
69
+ end
70
+
71
+
55
72
  describe "get_auth_id" do
56
73
  it "returns an auth_id for a good request" do
74
+ bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol], VCRFilter[:bd_api_key])
75
+ assert_present bd.get_auth_id
76
+ end
77
+
78
+ it "returns auth_id with API key from defaults" do
57
79
  bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol])
58
80
  assert_present bd.get_auth_id
59
81
  end
60
82
 
83
+ it "Raises for bad api_key" do
84
+ assert_raises(BorrowDirect::Error) do
85
+ bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol], "BAD_API_KEY").get_auth_id
86
+ end
87
+ end
88
+
61
89
  it "raises for a bad library symbol" do
62
- bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , "BAD_SYMBOL")
90
+ bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , "BAD_SYMBOL", VCRFilter[:bd_api_key])
63
91
  assert_raises(BorrowDirect::Error) do
64
92
  bd.get_auth_id
65
93
  end
66
94
  end
67
95
 
68
96
  it "raises for a bad patron barcode" do
69
- bd = BorrowDirect::Authentication.new("BAD_BARCODE", VCRFilter[:bd_library_symbol])
97
+ bd = BorrowDirect::Authentication.new("BAD_BARCODE", VCRFilter[:bd_library_symbol], VCRFilter[:bd_api_key])
70
98
  assert_raises(BorrowDirect::Error) do
71
99
  bd.get_auth_id
72
100
  end
@@ -0,0 +1,58 @@
1
+ require 'test_helper'
2
+ require 'borrow_direct/encryption'
3
+
4
+ describe "Relais Encryption" do
5
+ before do
6
+ @sample_private_key = <<-EOS
7
+ -----BEGIN RSA PRIVATE KEY-----
8
+ MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
9
+ wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
10
+ 1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
11
+ 3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
12
+ pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
13
+ GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
14
+ AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
15
+ L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
16
+ X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
17
+ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
18
+ 37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
19
+ -----END RSA PRIVATE KEY-----
20
+ EOS
21
+
22
+ @sample_public_key = <<-EOS
23
+ -----BEGIN PUBLIC KEY-----
24
+ MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0
25
+ FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/
26
+ 3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQAB
27
+ -----END PUBLIC KEY-----
28
+ EOS
29
+ end
30
+
31
+ describe "timestamp" do
32
+ it "creates in GMT" do
33
+ timestamp = BorrowDirect::Encryption.new(@sample_public_key).now_timestamp
34
+
35
+ utc_date = Time.now.utc.to_date
36
+
37
+ assert timestamp =~ /(\d{4})(\d{2})(\d{2}) \d{6}/
38
+
39
+ assert_equal utc_date.year.to_s, $1
40
+ assert_equal "%02d" % utc_date.month, $2
41
+ assert_equal "%02d" % utc_date.day, $3
42
+ end
43
+ end
44
+
45
+ describe "encrypted value" do
46
+ it "is encrypted with datestamp properly" do
47
+ original_value = "$$VALUE$$"
48
+ encrypted = BorrowDirect::Encryption.new(@sample_public_key).encode_with_ts(original_value)
49
+ encrypted = Base64.decode64(encrypted)
50
+
51
+ # Let's decrypt it and see
52
+ private_key = OpenSSL::PKey::RSA.new(@sample_private_key)
53
+ payload = private_key.private_decrypt(encrypted)
54
+
55
+ assert payload =~ /#{original_value}|\d{8} \d{6}/
56
+ end
57
+ end
58
+ end
@@ -4,12 +4,13 @@ require 'borrow_direct/find_item'
4
4
 
5
5
 
6
6
 
7
- describe "FindItem", :vcr do
7
+ describe "FindItem", :vcr => {:tag => :bd_finditem }do
8
8
  before do
9
9
  @requestable_item_isbn = "9810743734" # item is in BD, and can be requested
10
10
  @locally_avail_item_isbn = "0745649890" # item is in BD, but is avail locally so not BD-requestable
11
- @not_requestable_item_isbn = "1441190090" # in BD, and we don't have it, but no libraries let us borrow (in this case, it's an ebook)
11
+ @not_requestable_item_isbn = "1444367072" # in BD, and we don't have it, but no libraries let us borrow (in this case, it's an ebook)
12
12
  @returns_PUBFI002_ISBN = "0109836413" # BD returns an error PUBFI002 for this one, which we want to treat as simply not available.
13
+ @not_in_BD_at_all_isbn = "1898989898" # Not in BD at all, made up ISBN, invalid.
13
14
  end
14
15
 
15
16
 
@@ -39,9 +40,12 @@ describe "FindItem", :vcr do
39
40
  finder = BorrowDirect::FindItem.new("barcodeX", "libraryX")
40
41
  hash = finder.send(:exact_search_request_hash, :isbn, "2")
41
42
 
43
+
42
44
  assert_equal BorrowDirect::Defaults.partnership_id, hash["PartnershipId"]
43
- assert_equal "barcodeX", hash["Credentials"]["Barcode"]
44
- assert_equal "libraryX", hash["Credentials"]["LibrarySymbol"]
45
+
46
+ # These aren't there anymore.
47
+ #assert_equal "barcodeX", hash["Credentials"]["Barcode"]
48
+ #assert_equal "libraryX", hash["Credentials"]["LibrarySymbol"]
45
49
 
46
50
  assert_equal "ISBN", hash["ExactSearch"].first["Type"]
47
51
  assert_equal "2", hash["ExactSearch"].first["Value"]
@@ -80,11 +84,42 @@ describe "FindItem", :vcr do
80
84
  end
81
85
  end
82
86
 
87
+ it "raises proper error on bad AID" do
88
+ e = assert_raises(BorrowDirect::InvalidAidError) do
89
+ BorrowDirect::FindItem.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol]).with_auth_id("bad_expired_aid").find_item_request(:isbn => @requestable_item_isbn)
90
+ end
91
+ assert_present e.message
92
+ assert_present e.bd_code
93
+ assert_present e.aid
94
+ end
95
+
96
+ it "Raises with bad api_key" do
97
+ begin
98
+ orig_api_key = BorrowDirect::Defaults.api_key
99
+ BorrowDirect::Defaults.api_key = "BADAPIKEY"
100
+
101
+ assert_raises(BorrowDirect::Error) do
102
+ BorrowDirect::FindItem.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol]).find_item_request(:isbn => @requestable_item_isbn)
103
+ end
104
+ ensure
105
+ BorrowDirect::Defaults.api_key = orig_api_key
106
+ end
107
+ end
108
+
83
109
 
84
110
  it "finds a requestable item" do
85
111
  assert_present BorrowDirect::FindItem.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol]).find_item_request(:isbn => @requestable_item_isbn)
86
112
  end
87
113
 
114
+ it "uses manually set auth_id" do
115
+ auth_id = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol]).get_auth_id
116
+ bd = BorrowDirect::FindItem.new("bad_patron" , "bad_symbol").with_auth_id(auth_id)
117
+ resp = bd.find_item_request(:isbn => @requestable_item_isbn)
118
+
119
+ assert_present resp
120
+ assert_equal true, resp["Available"]
121
+ end
122
+
88
123
  it "finds a locally available item" do
89
124
  assert_present BorrowDirect::FindItem.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol]).find_item_request(:isbn => @locally_avail_item_isbn)
90
125
  end
@@ -113,8 +148,10 @@ describe "FindItem", :vcr do
113
148
  assert_equal true, @find_item.find(:isbn => @requestable_item_isbn).requestable?
114
149
  end
115
150
 
151
+
152
+
116
153
  it "requestable with multiple items if at least one is requestable" do
117
- assert_equal true, @find_item.find(:isbn => [@requestable_item_isbn, "NO_SUCH_ISBN"]).requestable?
154
+ assert_equal true, @find_item.find(:isbn => [@requestable_item_isbn, @not_in_BD_at_all_isbn]).requestable?
118
155
  end
119
156
 
120
157
  it "not requestable for locally available item" do
@@ -126,7 +163,7 @@ describe "FindItem", :vcr do
126
163
  end
127
164
 
128
165
  it "not requestable for item that does not exist in BD" do
129
- assert_equal false, @find_item.find(:isbn => "NO_SUCH_THING").requestable?
166
+ assert_equal false, @find_item.find(:isbn => @not_in_BD_at_all_isbn).requestable?
130
167
  end
131
168
 
132
169
  it "not requestable for item that no libraries will lend" do
@@ -138,18 +175,36 @@ describe "FindItem", :vcr do
138
175
  end
139
176
 
140
177
  it "has an auth_id" do
178
+ assert @find_item.auth_id.nil?
141
179
  assert_present @find_item.find(:isbn => @requestable_item_isbn).auth_id
142
- end
143
-
144
- it "has nil auth_id when BD doesn't want to give us one" do
145
- assert_nil @find_item.find(:isbn => @returns_PUBFI002_ISBN).auth_id
146
- end
180
+ assert_present @find_item.auth_id
181
+ end
147
182
 
148
183
  it "has pickup locations" do
149
184
  pickup_locations = @find_item.find(:isbn => @requestable_item_isbn).pickup_locations
150
185
 
151
186
  assert_present pickup_locations
152
187
  assert_kind_of Array, pickup_locations
188
+ pickup_locations.each do |location|
189
+ assert_kind_of String, location
190
+ end
191
+ end
192
+
193
+ describe "#pickup_location_data" do
194
+ it "returns array of PickupLocations" do
195
+ pickup_locations = @find_item.find(:isbn => @requestable_item_isbn).pickup_location_data
196
+
197
+ assert_present pickup_locations
198
+ assert_kind_of Array, pickup_locations
199
+ pickup_locations.each do |location|
200
+ assert_kind_of BorrowDirect::PickupLocation, location
201
+ assert_present location.code
202
+ assert_present location.description
203
+
204
+ assert_equal [location.description, location.code], location.to_a
205
+ assert_equal( {"PickupLocationCode" => location.code, "PickupLocationDescription" => location.description}, location.to_h )
206
+ end
207
+ end
153
208
  end
154
209
 
155
210
  it "has nil pickup locations when BD doesn't want to give us them" do
@@ -13,8 +13,38 @@ describe "RequestItem", :vcr => {:tag => :bd_requestitem } do
13
13
  @requestable_item_isbn = "9797994864" # item is in BD, and can be requested
14
14
  @locally_avail_item_isbn = "0745649890" # item is in BD, but is avail locally so not BD-requestable
15
15
  @not_requestable_item_isbn = "1441190090" # in BD, and we don't have it, but no libraries let us borrow (in this case, it's an ebook)
16
- @returns_PUBRI004_ISBN = "0109836413" # BD returns an error PUBRI004 for this one, which we want to treat as simply not available.
16
+ @returns_PUBRI003_ISBN = "0109836413" # BD returns an error PUBRI004 for this one, which we want to treat as simply not available.
17
17
  @pickup_location = "Some location" # BD seems to allow anything, which is disturbing
18
+ @pickup_location_obj = BorrowDirect::PickupLocation.new({"PickupLocationCode" => "a", "PickupLocationDescription" => @pickup_location})
19
+ end
20
+
21
+ it "raw RequestItem sanity check" do
22
+ findable = BorrowDirect::FindItem.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol]).find(:isbn => @requestable_item_isbn)
23
+
24
+ assert findable.requestable?
25
+
26
+ pickup = findable.pickup_locations.first
27
+ aid = findable.auth_id
28
+
29
+ uri = BorrowDirect::Defaults.api_base.chomp("/") + "/dws/item/add?aid=#{CGI.escape aid}"
30
+
31
+ request_hash = {
32
+ "PartnershipId" => BorrowDirect::Defaults.partnership_id,
33
+ "PickupLocation" => pickup,
34
+ "ExactSearch" => [
35
+ {"Type" => "ISBN","Value" => @requestable_item_isbn}
36
+ ]
37
+ }
38
+
39
+ http = HTTPClient.new
40
+ response = http.post uri, JSON.generate(request_hash), BorrowDirect::Request.new('').request_headers
41
+
42
+ assert_equal 200, response.code
43
+ assert_present response.body
44
+
45
+ response_hash = JSON.parse response.body
46
+
47
+ assert_present response_hash
18
48
  end
19
49
 
20
50
 
@@ -43,7 +73,8 @@ describe "RequestItem", :vcr => {:tag => :bd_requestitem } do
43
73
  resp = BorrowDirect::RequestItem.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol]).request_item_request(nil, :isbn => @not_requestable_item_isbn)
44
74
 
45
75
  assert_present resp
46
- assert_present resp["Request"]
76
+
77
+ assert_present resp["RequestLink"]
47
78
  end
48
79
 
49
80
  it "uses manually set auth_id" do
@@ -52,7 +83,17 @@ describe "RequestItem", :vcr => {:tag => :bd_requestitem } do
52
83
  resp = bd.request_item_request(nil, :isbn => @requestable_item_isbn)
53
84
 
54
85
  assert_present resp
55
- assert_present resp["Request"]
86
+
87
+ assert_present resp["RequestNumber"], "Was not able to succesfully make a request: #{resp}"
88
+ end
89
+
90
+ it "raises proper error on bad AID" do
91
+ e = assert_raises(BorrowDirect::InvalidAidError) do
92
+ BorrowDirect::RequestItem.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol]).with_auth_id("bad_expired_aid").make_request(nil, :isbn => @requestable_item_isbn)
93
+ end
94
+ assert_present e.message
95
+ assert_present e.bd_code
96
+ assert_present e.aid
56
97
  end
57
98
 
58
99
  describe "make_request" do
@@ -62,6 +103,15 @@ describe "RequestItem", :vcr => {:tag => :bd_requestitem } do
62
103
  assert_present request_id
63
104
  end
64
105
 
106
+ it "sets an auth_id" do
107
+ requester = BorrowDirect::RequestItem.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol])
108
+
109
+ assert requester.auth_id.nil?
110
+
111
+ requester.make_request(nil, :isbn => @requestable_item_isbn)
112
+ assert_present requester.auth_id
113
+ end
114
+
65
115
  it "make_request for an unrequestable item" do
66
116
  resp = BorrowDirect::RequestItem.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol]).make_request(nil, :isbn => @not_requestable_item_isbn)
67
117
 
@@ -74,18 +124,25 @@ describe "RequestItem", :vcr => {:tag => :bd_requestitem } do
74
124
  assert_nil resp
75
125
  end
76
126
 
77
- it "says no for item that BD returns PUBRI004" do
78
- assert_nil BorrowDirect::RequestItem.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol]).make_request(nil, :isbn => @returns_PUBRI004_ISBN)
127
+ it "says no for item that BD returns PUBRI003" do
128
+ assert_nil BorrowDirect::RequestItem.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol]).make_request(nil, :isbn => @returns_PUBRI003_ISBN)
79
129
  end
80
130
 
81
131
  end
82
132
 
83
- describe "with pickup location and requestable item" do
84
- it "still works" do
133
+ describe "with pickup location and requestable item" do
134
+ it "works with String pickup_location" do
85
135
  request_id = BorrowDirect::RequestItem.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol]).make_request(@pickup_location, :isbn => @requestable_item_isbn)
86
136
 
87
- assert_present request_id
137
+ assert_present request_id, "Was not able to succesfully make a request"
138
+ end
139
+
140
+ it "works with structured PickupLocation" do
141
+ request_id = BorrowDirect::RequestItem.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol]).make_request(@pickup_location_obj, :isbn => @requestable_item_isbn)
142
+
143
+ assert_present request_id, "Was not able to succesfully make a request"
88
144
  end
145
+
89
146
  end
90
147
 
91
148
  describe "make_request!" do
@@ -12,35 +12,22 @@ describe "RequestQuery", :vcr => {:tag => :bd_request_query} do
12
12
  it "raw request to verify the BD HTTP API" do
13
13
 
14
14
  # Get the auth code
15
-
16
- auth_uri = BorrowDirect::Defaults.api_base.chomp("/") + "/portal-service/user/authentication/patron"
17
- auth_hash = {
18
- "AuthenticationInformation" => {
19
- "LibrarySymbol" => VCRFilter[:bd_library_symbol],
20
- "PatronId" => VCRFilter[:bd_patron]
21
- }
22
- }
23
-
24
- headers = { "Content-Type" => "application/json",
25
- "User-Agent" => "ruby borrow_direct gem #{BorrowDirect::VERSION} (HTTPClient #{HTTPClient::VERSION}) https://github.com/jrochkind/borrow_direct",
26
- "Accept-Language" => "en"
27
- }
28
- http = HTTPClient.new
29
- response = http.post auth_uri, JSON.generate(auth_hash), headers
30
- response_hash = JSON.parse response.body
31
- auth_id = response_hash["Authentication"]["AuthnUserInfo"]["AId"]
32
-
15
+ auth_id = BorrowDirect::Authentication.new(VCRFilter[:bd_patron], VCRFilter[:bd_library_symbol]).get_auth_id
33
16
 
34
17
  # Now use it to make a RequestQuery request. Note, BD API requires
35
18
  # you to use the same User-Agent you used to receive the auth id.
36
19
 
37
-
38
20
  query = {
39
21
  "aid" => auth_id,
40
22
  "type" => "open",
41
23
  "fullRecord" => "0"
42
24
  }
43
25
 
26
+ headers = { "Content-Type" => "application/json",
27
+ "User-Agent" => "ruby borrow_direct gem #{BorrowDirect::VERSION} (HTTPClient #{HTTPClient::VERSION}) https://github.com/jrochkind/borrow_direct",
28
+ "Accept-Language" => "en"
29
+ }
30
+
44
31
  uri = BorrowDirect::Defaults.api_base.chomp("/") + "/portal-service/request/query/my"
45
32
 
46
33
  http = HTTPClient.new
@@ -52,8 +39,15 @@ describe "RequestQuery", :vcr => {:tag => :bd_request_query} do
52
39
  response_hash = JSON.parse http_response.body
53
40
 
54
41
  assert_present response_hash
55
- assert_present response_hash["QueryResult"]
56
- assert_kind_of Array, response_hash["QueryResult"]["MyRequestRecords"]
42
+ assert_kind_of Array, response_hash["MyRequestRecords"]
43
+ end
44
+
45
+ it "raises proper error on bad AID" do
46
+ e = assert_raises(BorrowDirect::InvalidAidError) do
47
+ BorrowDirect::RequestQuery.new(VCRFilter[:bd_patron]).with_auth_id("bad_expired_id").request_query_request
48
+ end
49
+ assert_present e.message
50
+ assert_present e.aid
57
51
  end
58
52
 
59
53
  describe "raw request_query_request" do
@@ -63,8 +57,8 @@ describe "RequestQuery", :vcr => {:tag => :bd_request_query} do
63
57
 
64
58
  assert_present response
65
59
  assert_kind_of Hash, response
66
- assert_present response["QueryResult"]["MyRequestRecords"]
67
- assert_kind_of Array, response["QueryResult"]["MyRequestRecords"]
60
+ assert_present response["MyRequestRecords"]
61
+ assert_kind_of Array, response["MyRequestRecords"]
68
62
  end
69
63
  end
70
64
 
@@ -85,10 +79,12 @@ describe "RequestQuery", :vcr => {:tag => :bd_request_query} do
85
79
  assert_includes [true, false], item.send(key)
86
80
  end
87
81
 
88
- [:request_status_date, :date_submitted].each do |key|
89
- assert_present item.send(key)
90
- assert_kind_of DateTime, item.send(key)
91
- end
82
+ # Huh, records don't seem to reliably have these, so we
83
+ # can't test for them, bah.
84
+ #[:request_status_date, :date_submitted].each do |key|
85
+ # assert_present item.send(key)
86
+ # assert_kind_of DateTime, item.send(key)
87
+ #end
92
88
  end
93
89
 
94
90
  it "fetches full records" do
data/test/request_test.rb CHANGED
@@ -4,9 +4,11 @@ require 'borrow_direct/request'
4
4
 
5
5
 
6
6
 
7
- describe "Request", :vcr => {:tag => :bd_request} do
7
+ describe "Request", :vcr => {:tag => :bd_request } do
8
8
  before do
9
9
  @successful_item_isbn = "9810743734"
10
+
11
+ @aid = BorrowDirect::Authentication.new(VCRFilter[:bd_patron], VCRFilter[:bd_library_symbol]).get_auth_id
10
12
  end
11
13
 
12
14
 
@@ -17,8 +19,8 @@ describe "Request", :vcr => {:tag => :bd_request} do
17
19
  end
18
20
 
19
21
  it "raises on bad request hash" do
20
- assert_raises(BorrowDirect::HttpError) do
21
- response = BorrowDirect::Request.new("/dws/item/available").request( "foo" => "bar" )
22
+ assert_raises(BorrowDirect::Error) do
23
+ response = BorrowDirect::Request.new("/dws/item/available").request( {"foo" => "bar"}, @aid )
22
24
  end
23
25
  end
24
26
 
@@ -46,13 +48,28 @@ describe "Request", :vcr => {:tag => :bd_request} do
46
48
  refute_nil e.bd_code
47
49
  end
48
50
 
49
- it "can make a succesful request" do
51
+ it "gets BD error info from a bad AID" do
52
+ request = {
53
+ "PartnershipId" => "BD",
54
+ "ExactSearch" => [
55
+ {
56
+ "Type" => "ISBN",
57
+ "Value" => @successful_item_isbn
58
+ }
59
+ ]
60
+ }
61
+
62
+ e = assert_raises(BorrowDirect::InvalidAidError) do
63
+ response = BorrowDirect::Request.new("/dws/item/available").request( request, "bad_aid" )
64
+ end
65
+
66
+ refute_nil e
67
+ assert_equal "PUBFI003", e.bd_code
68
+ end
69
+
70
+ it "can make a succesful request with AID" do
50
71
  request = {
51
72
  "PartnershipId" => "BD",
52
- "Credentials" => {
53
- "LibrarySymbol" => VCRFilter[:bd_library_symbol],
54
- "Barcode" => VCRFilter[:bd_patron]
55
- },
56
73
  "ExactSearch" => [
57
74
  {
58
75
  "Type" => "ISBN",
@@ -62,7 +79,7 @@ describe "Request", :vcr => {:tag => :bd_request} do
62
79
  }
63
80
 
64
81
 
65
- response = BorrowDirect::Request.new("/dws/item/available").request( request )
82
+ response = BorrowDirect::Request.new("/dws/item/available").request( request, @aid )
66
83
  end
67
84
 
68
85
  it "uses timeout for HttpClient" do
@@ -76,13 +93,12 @@ describe "Request", :vcr => {:tag => :bd_request} do
76
93
  assert_equal 5, http_client.connect_timeout
77
94
  end
78
95
 
96
+
79
97
  it "raises exception on timeout, live" do
98
+ skip "Can't get this to work with VCR and new API"
99
+
80
100
  request = {
81
101
  "PartnershipId" => "BD",
82
- "Credentials" => {
83
- "LibrarySymbol" => VCRFilter[:bd_library_symbol],
84
- "Barcode" => VCRFilter[:bd_patron]
85
- },
86
102
  "ExactSearch" => [
87
103
  {
88
104
  "Type" => "ISBN",
@@ -90,19 +106,20 @@ describe "Request", :vcr => {:tag => :bd_request} do
90
106
  }
91
107
  ]
92
108
  }
93
- bd = BorrowDirect::Request.new("/dws/item/available")
109
+ # Using a Bad URI here keeps VCR from interfering with us too much.
110
+ bd = BorrowDirect::Request.new("/dws/item/available_bad_uri")
94
111
  # tiny timeout, it'll def timeout, and on connect no less
95
- bd.timeout = 0.00001
112
+ bd.timeout = 0.00000001
96
113
  timeout_error = assert_raises(BorrowDirect::HttpTimeoutError) do
97
- response = bd.request( request )
114
+ response = bd.request( request, @aid )
98
115
  end
99
116
  assert_equal bd.timeout, timeout_error.timeout
100
117
 
101
118
  # little bit longer to get maybe a receive timeout instead
102
- bd = BorrowDirect::Request.new("/dws/item/available")
119
+ bd = BorrowDirect::Request.new("/dws/item/available_bad_uri")
103
120
  bd.timeout = 0.10
104
121
  timeout_error = assert_raises(BorrowDirect::HttpTimeoutError) do
105
- response = bd.request( request )
122
+ response = bd.request( request, @aid )
106
123
  end
107
124
  assert_equal bd.timeout, timeout_error.timeout
108
125
  end
@@ -110,22 +127,18 @@ describe "Request", :vcr => {:tag => :bd_request} do
110
127
  describe "with expected errors" do
111
128
  it "still returns result" do
112
129
  request = {
113
- "PartnershipId" => "BAD_ID",
114
- "Credentials" => {
115
- "LibrarySymbol" => "librarySymbol",
116
- "Barcode" => "barcode/patronId"
117
- },
130
+ "PartnershipId" => "BD",
118
131
  "ExactSearch" => [
119
132
  {
120
- "Type" => "type",
121
- "Value" => "value"
133
+ "Type" => "BADBAD",
134
+ "Value" => "2292389283928392382938"
122
135
  }
123
136
  ]
124
137
  }
125
138
 
126
139
  bd = BorrowDirect::Request.new("/dws/item/available")
127
- bd.expected_error_codes << "PUBFI003"
128
- response = bd.request( request )
140
+ bd.expected_error_codes << "PRIFI001"
141
+ response = bd.request( request, @aid )
129
142
 
130
143
  assert_present response
131
144
 
data/test/test_helper.rb CHANGED
@@ -9,6 +9,12 @@ require 'minitest-vcr'
9
9
 
10
10
  require 'borrow_direct'
11
11
 
12
+ # Want to run tests against PRODUCTION BD? It WILL result in real requests being
13
+ # made to BD production system, so you probably don't -- but if you're not sure
14
+ # if production API is really behaving like test, you might want to anyway.
15
+ if ENV["RAILS_ENV"] == "production"
16
+ BorrowDirect::Defaults.api_base = BorrowDirect::Defaults::PRODUCTION_API_BASE
17
+ end
12
18
 
13
19
  # Load support files
14
20
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
@@ -19,13 +25,16 @@ VCR.configure do |c|
19
25
 
20
26
  # BD API requests tend to have their distinguishing
21
27
  # features in a POSTed JSON request body
22
- c.default_cassette_options = { :match_requests_on => [:method, :uri, :body] }
28
+ c.default_cassette_options = { :match_requests_on => [:method, VCR.request_matchers.uri_without_param(:aid), :body] }
23
29
  end
24
30
 
25
31
  MinitestVcr::Spec.configure!
26
32
 
27
33
  VCRFilter.sensitive_data! :bd_library_symbol
28
34
  VCRFilter.sensitive_data! :bd_patron
35
+ VCRFilter.sensitive_data! :bd_api_key
36
+
37
+ BorrowDirect::Defaults.api_key = VCRFilter[:bd_api_key]
29
38
 
30
39
  # Silly way to not have to rewrite all our tests if we
31
40
  # temporarily disable VCR, make VCR.use_cassette a no-op