triannon-client 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/.env_example +16 -2
  3. data/.rspec +1 -0
  4. data/README.md +49 -18
  5. data/Rakefile +15 -2
  6. data/lib/triannon-client.rb +12 -6
  7. data/lib/triannon-client/configuration.rb +26 -14
  8. data/lib/triannon-client/triannon_client.rb +139 -44
  9. data/spec/fixtures/vcr_cassettes/{TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/gets_an_open_annotation_by_ID_with_content_type_application/x-turtle_.yml → CRUD/create_annotation.yml} +192 -132
  10. data/spec/fixtures/vcr_cassettes/TriannonClientAUTH/with_authentication/behaves_like_authenticate/-_authenticate_returns_true.yml +343 -0
  11. data/spec/fixtures/vcr_cassettes/TriannonClientCREATE/_post_annotation/with_authentication/behaves_like_create_annotations/POST_401_response_retries_and_logs_RestClient_Exception_message.yml +170 -0
  12. data/spec/fixtures/vcr_cassettes/TriannonClientCREATE/_post_annotation/with_authentication/behaves_like_create_annotations/POST_403_response_does_not_retry_and_logs_RestClient_Exception_message.yml +170 -0
  13. data/spec/fixtures/vcr_cassettes/TriannonClientCREATE/_post_annotation/with_authentication/behaves_like_create_annotations/POST_500_response_does_not_retry_and_logs_RestClient_Exception_message.yml +170 -0
  14. data/spec/fixtures/vcr_cassettes/{TriannonClient/_get_annotations/returns_an_annotation_list_with_an_annotation_created_by_a_prior_POST.yml → TriannonClientCREATE/_post_annotation/with_authentication/behaves_like_create_annotations/does_not_raise_an_error_when_submitting_a_valid_open_annotation.yml} +203 -319
  15. data/spec/fixtures/vcr_cassettes/TriannonClientCREATE/_post_annotation/with_authentication/behaves_like_create_annotations/logs_RuntimeError_message.yml +170 -0
  16. data/spec/fixtures/vcr_cassettes/TriannonClientCREATE/_post_annotation/with_authentication/behaves_like_create_annotations/returns_a_RestClient_Response_object.yml +170 -0
  17. data/spec/fixtures/vcr_cassettes/{TriannonClient/_post_annotation → TriannonClientCREATE/_post_annotation/without_authentication/behaves_like_create_annotations}/does_not_raise_an_error_when_submitting_a_valid_open_annotation.yml +29 -27
  18. data/spec/fixtures/vcr_cassettes/TriannonClientCREATE/clear_annotations.yml +590 -0
  19. data/spec/fixtures/vcr_cassettes/TriannonClientDELETE/_delete_annotation/with_authentication/behaves_like_delete_annotations/returns_TRUE_when_deleting_an_annotation_that_does_NOT_exist.yml +349 -0
  20. data/spec/fixtures/vcr_cassettes/TriannonClientDELETE/_delete_annotation/with_authentication/behaves_like_delete_annotations/returns_TRUE_when_deleting_an_annotation_that_exists.yml +332 -0
  21. data/spec/fixtures/vcr_cassettes/TriannonClientDELETE/_delete_annotation/with_authentication/behaves_like_delete_annotations/validates_the_annotation_ID.yml +288 -0
  22. data/spec/fixtures/vcr_cassettes/{TriannonClient/_delete_annotation/returns_TRUE_when_deleting_an_open_annotation_that_does_NOT_exist.yml → TriannonClientDELETE/_delete_annotation/without_authentication/behaves_like_delete_annotations/returns_TRUE_when_deleting_an_annotation_that_does_NOT_exist.yml} +13 -9
  23. data/spec/fixtures/vcr_cassettes/TriannonClientDELETE/_delete_annotation/without_authentication/behaves_like_delete_annotations/returns_TRUE_when_deleting_an_annotation_that_exists.yml +127 -0
  24. data/spec/fixtures/vcr_cassettes/{TriannonClient/_delete_annotation → TriannonClientDELETE/_delete_annotation/without_authentication/behaves_like_delete_annotations}/validates_the_annotation_ID.yml +7 -5
  25. data/spec/fixtures/vcr_cassettes/TriannonClientDELETE/clear_annotations.yml +594 -0
  26. data/spec/fixtures/vcr_cassettes/{TriannonClient → TriannonClientREAD/GET}/_get_annotations/returns_an_RDF_Graph.yml +30 -23
  27. data/spec/fixtures/vcr_cassettes/{TriannonClient → TriannonClientREAD/GET}/_get_annotations/returns_an_RDF_Graph_that_contains_an_AnnotationList.yml +30 -23
  28. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/_get_annotations/returns_an_annotation_list_with_an_annotation_created_by_a_prior_POST.yml +302 -0
  29. data/spec/fixtures/vcr_cassettes/{TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_application/n-quads_.yml → TriannonClientREAD/GET/_get_iiif_annotation/returns_an_RDF_Graph_of_an_open_annotation.yml} +25 -78
  30. data/spec/fixtures/vcr_cassettes/{TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_application/n-triples_.yml → TriannonClientREAD/GET/_get_oa_annotation/returns_an_RDF_Graph_of_an_open_annotation.yml} +25 -78
  31. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/_response2graph/accepts_a_RestClient_Response_instance.yml +2399 -0
  32. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/csvm_json_.yml +1231 -0
  33. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/n-quads_.yml +1231 -0
  34. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/n-triples_.yml +1231 -0
  35. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/rdf_json_.yml +1231 -0
  36. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/rdf_n3_.yml +1231 -0
  37. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/trig_.yml +1231 -0
  38. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/trix_.yml +1231 -0
  39. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/turtle_.yml +1231 -0
  40. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/x-ld_json_.yml +1231 -0
  41. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/x-trig_.yml +1231 -0
  42. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_text/csv_.yml +1231 -0
  43. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_text/n3_.yml +1231 -0
  44. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_text/plain_.yml +1231 -0
  45. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_text/rdf_n3_.yml +1231 -0
  46. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_text/rdf_turtle_.yml +1231 -0
  47. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_text/tab-separated-values_.yml +1231 -0
  48. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_text/x-nquads_.yml +1231 -0
  49. data/spec/fixtures/vcr_cassettes/{TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_application → TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/gets_an_open_annotation_by_ID_with_content_type_application}/ld_json_.yml +25 -78
  50. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/gets_an_open_annotation_by_ID_with_content_type_application/rdf_xml_.yml +68 -0
  51. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/gets_an_open_annotation_by_ID_with_content_type_application/x-turtle_.yml +69 -0
  52. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_custom_content_type/gets_an_open_annotation_by_ID_with_content_type_text/turtle_.yml +69 -0
  53. data/spec/fixtures/vcr_cassettes/{TriannonClient/GET_annotation_by_ID_/_get_annotation/without_content_type → TriannonClientREAD/GET/annotation_by_ID/using_default_content_type}/checks_the_annotation_ID.yml +25 -78
  54. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/GET/annotation_by_ID/using_default_content_type/returns_an_EMPTY_RDF_graph_with_a_valid_ID_for_NO_annotation_on_the_server.yml +186 -0
  55. data/spec/fixtures/vcr_cassettes/{TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_application/rdf_json_.yml → TriannonClientREAD/GET/annotation_by_ID/using_default_content_type/returns_an_RDF_graph_with_a_valid_ID_for_an_annotation_on_the_server.yml} +25 -78
  56. data/spec/fixtures/vcr_cassettes/TriannonClientREAD/clear_annotations.yml +648 -0
  57. data/spec/fixtures/vcr_cassettes/{TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/gets_an_open_annotation_by_ID_with_content_type_application/rdf_xml_.yml → TriannonClientREAD/create_annotation.yml} +192 -131
  58. data/spec/lib/triannon-client/configuration_spec.rb +83 -27
  59. data/spec/lib/triannon-client/triannon_client_auth_spec.rb +61 -0
  60. data/spec/lib/triannon-client/triannon_client_class_spec.rb +104 -0
  61. data/spec/lib/triannon-client/triannon_client_create_spec.rb +119 -0
  62. data/spec/lib/triannon-client/triannon_client_delete_spec.rb +117 -0
  63. data/spec/lib/triannon-client/triannon_client_read_spec.rb +342 -0
  64. data/spec/spec_helper.rb +140 -4
  65. data/triannon-client.gemspec +1 -1
  66. metadata +112 -153
  67. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/n-quads_.yml +0 -3995
  68. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/n-triples_.yml +0 -3995
  69. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/rdf_json_.yml +0 -3995
  70. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/rdf_n3_.yml +0 -3995
  71. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/trig_.yml +0 -3995
  72. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/trix_.yml +0 -3995
  73. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/turtle_.yml +0 -3995
  74. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/x-ld_json_.yml +0 -3995
  75. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_application/x-trig_.yml +0 -3995
  76. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_text/n3_.yml +0 -3995
  77. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_text/rdf_n3_.yml +0 -3995
  78. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_text/rdf_turtle_.yml +0 -3995
  79. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/cannot_get_an_open_annotation_by_ID_with_content_type_text/x-nquads_.yml +0 -3995
  80. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/gets_an_open_annotation_by_ID_with_content_type_application/ld_json_.yml +0 -4946
  81. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/gets_an_open_annotation_by_ID_with_content_type_text/turtle_.yml +0 -2566
  82. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_application/rdf_n3_.yml +0 -2502
  83. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_application/rdf_xml_.yml +0 -2502
  84. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_application/trig_.yml +0 -2502
  85. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_application/trix_.yml +0 -2502
  86. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_application/turtle_.yml +0 -2502
  87. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_application/x-ld_json_.yml +0 -2502
  88. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_application/x-trig_.yml +0 -2502
  89. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_application/x-turtle_.yml +0 -2502
  90. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_text/n3_.yml +0 -2502
  91. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_text/rdf_n3_.yml +0 -2502
  92. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_text/rdf_turtle_.yml +0 -2502
  93. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_text/turtle_.yml +0 -2502
  94. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/with_content_type/requests_an_open_annotation_by_ID_with_content_type_text/x-nquads_.yml +0 -2502
  95. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/without_content_type/logs_exceptions.yml +0 -2502
  96. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/without_content_type/raises_an_argument_error_with_a_nil_ID.yml +0 -2502
  97. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/without_content_type/raises_an_argument_error_with_an_empty_string_ID.yml +0 -2502
  98. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/without_content_type/raises_an_argument_error_with_an_integer_ID.yml +0 -2502
  99. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/without_content_type/requests_an_open_annotation_by_ID_accepting_a_default_JSON-LD_content.yml +0 -2502
  100. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/without_content_type/returns_an_EMPTY_RDF_graph_for_a_500_server_response.yml +0 -2502
  101. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/without_content_type/returns_an_EMPTY_RDF_graph_with_a_valid_ID_for_NO_annotation_on_the_server.yml +0 -2561
  102. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_annotation/without_content_type/returns_an_RDF_graph_with_a_valid_ID_for_an_annotation_on_the_server.yml +0 -4946
  103. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_iiif_annotation/requests_an_open_annotation_by_ID_using_a_IIIF_profile.yml +0 -2502
  104. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_iiif_annotation/returns_an_RDF_Graph_of_an_open_annotation.yml +0 -2746
  105. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_oa_annotation/requests_an_open_annotation_by_ID_using_an_OA_profile.yml +0 -2502
  106. data/spec/fixtures/vcr_cassettes/TriannonClient/GET_annotation_by_ID_/_get_oa_annotation/returns_an_RDF_Graph_of_an_open_annotation.yml +0 -4946
  107. data/spec/fixtures/vcr_cassettes/TriannonClient/_delete_annotation/does_not_log_exceptions_for_missing_annotations_404_responses_.yml +0 -64
  108. data/spec/fixtures/vcr_cassettes/TriannonClient/_delete_annotation/does_not_log_exceptions_for_missing_annotations_410_responses_.yml +0 -64
  109. data/spec/fixtures/vcr_cassettes/TriannonClient/_delete_annotation/logs_exceptions.yml +0 -64
  110. data/spec/fixtures/vcr_cassettes/TriannonClient/_delete_annotation/returns_FALSE_for_a_500_response_to_a_DELETE_request.yml +0 -64
  111. data/spec/fixtures/vcr_cassettes/TriannonClient/_delete_annotation/returns_TRUE_for_a_200_response_to_a_DELETE_request.yml +0 -64
  112. data/spec/fixtures/vcr_cassettes/TriannonClient/_delete_annotation/returns_TRUE_for_a_202_response_to_a_DELETE_request.yml +0 -64
  113. data/spec/fixtures/vcr_cassettes/TriannonClient/_delete_annotation/returns_TRUE_for_a_204_response_to_a_DELETE_request.yml +0 -64
  114. data/spec/fixtures/vcr_cassettes/TriannonClient/_delete_annotation/returns_TRUE_for_a_404_response_to_a_DELETE_request.yml +0 -64
  115. data/spec/fixtures/vcr_cassettes/TriannonClient/_delete_annotation/returns_TRUE_for_a_410_response_to_a_DELETE_request.yml +0 -64
  116. data/spec/fixtures/vcr_cassettes/TriannonClient/_delete_annotation/returns_TRUE_when_deleting_an_open_annotation_that_exists.yml +0 -2549
  117. data/spec/fixtures/vcr_cassettes/TriannonClient/_post_annotation/logs_exceptions.yml +0 -5355
  118. data/spec/fixtures/vcr_cassettes/TriannonClient/_post_annotation/logs_exceptions_for_RestClient_Exception.yml +0 -5355
  119. data/spec/fixtures/vcr_cassettes/TriannonClient/_post_annotation/returns_a_RestClient_Response_object.yml +0 -2502
  120. data/spec/fixtures/vcr_cassettes/TriannonClient/response_processing_utilities/_annotation_id/returns_a_String_ID_from_the_RDF_URI_of_an_annotation.yml +0 -2502
  121. data/spec/fixtures/vcr_cassettes/TriannonClient/response_processing_utilities/_annotation_id/returns_a_String_ID_that_is_not_empty.yml +0 -2502
  122. data/spec/fixtures/vcr_cassettes/TriannonClient/response_processing_utilities/_annotation_uris/returns_an_RDF_URI_that_is_a_valid_URI.yml +0 -2551
  123. data/spec/fixtures/vcr_cassettes/TriannonClient/response_processing_utilities/_annotation_uris/returns_an_array_of_RDF_URI_from_an_RDF_Graph_of_an_annotation.yml +0 -2502
  124. data/spec/fixtures/vcr_cassettes/TriannonClient/response_processing_utilities/_response2graph/accepts_a_RestClient_Response_instance.yml +0 -4898
  125. data/spec/fixtures/vcr_cassettes/TriannonClient/response_processing_utilities/_response2graph/raises_ArgumentError_when_given_an_empty_String.yml +0 -2502
  126. data/spec/fixtures/vcr_cassettes/TriannonClient/response_processing_utilities/_response2graph/raises_ArgumentError_when_given_nil.yml +0 -2502
  127. data/spec/fixtures/vcr_cassettes/TriannonClient/response_processing_utilities/_response2graph/returns_an_RDF_Graph.yml +0 -2502
  128. data/spec/lib/triannon-client/triannon_client_spec.rb +0 -546
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.shared_examples "authenticate" do |auth_required|
4
+
5
+ let(:tc) {
6
+ if auth_required
7
+ triannon_config_auth
8
+ else
9
+ triannon_config_no_auth
10
+ end
11
+ TriannonClient::TriannonClient.new
12
+ }
13
+
14
+ def check_header
15
+ headers = tc.site.headers
16
+ expect(headers).to include(:Authorization)
17
+ expect(headers[:Authorization]).to match(/Bearer/)
18
+ end
19
+
20
+ it "- #authenticate returns #{auth_required}" do
21
+ if auth_required
22
+ expect(tc.authenticate).to be_truthy
23
+ check_header
24
+ else
25
+ expect(tc.authenticate).to be false
26
+ end
27
+ end
28
+
29
+ it "- #authenticate! returns #{auth_required}" do
30
+ # Authenticate and then test that authenticate!
31
+ # will reset and renew the authentication.
32
+ auth1 = tc.authenticate
33
+ check_header if auth_required
34
+ expect(tc.site.headers).to receive(:delete)
35
+ if auth_required
36
+ # renew the authentication
37
+ expect(tc.authenticate!).to be_truthy
38
+ check_header
39
+ auth2 = tc.site.headers[:Authorization]
40
+ expect(auth1).not_to eql(auth2)
41
+ else
42
+ expect(tc.authenticate!).to be false
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+
49
+ describe 'TriannonClientAUTH', :vcr do
50
+
51
+ context 'without authentication' do
52
+ auth_required = false # it's not required
53
+ it_behaves_like 'authenticate', auth_required
54
+ end
55
+
56
+ context 'with authentication' do
57
+ auth_required = true # it must succeed
58
+ it_behaves_like 'authenticate', auth_required
59
+ end
60
+
61
+ end
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+
3
+ # ::TriannonClient::TriannonClient class specs
4
+
5
+ describe 'TriannonClientClass' do
6
+
7
+ let(:tc) {
8
+ triannon_config_no_auth # spec_helper
9
+ TriannonClient::TriannonClient.new
10
+ }
11
+
12
+ describe 'has constants:' do
13
+ it 'CONTENT_TYPES' do
14
+ const = TriannonClient::TriannonClient::CONTENT_TYPES
15
+ expect(const).to be_instance_of Array
16
+ expect(const).to include('application/ld+json')
17
+ end
18
+ it 'PROFILE_TYPE_IIIF' do
19
+ const = TriannonClient::TriannonClient::PROFILE_IIIF
20
+ expect(const).to be_instance_of String
21
+ expect(const).to include('http://iiif.io/api/presentation/2/context.json')
22
+ end
23
+ it 'PROFILE_TYPE_OA' do
24
+ const = TriannonClient::TriannonClient::PROFILE_OA
25
+ expect(const).to be_instance_of String
26
+ expect(const).to include('http://www.w3.org/ns/oa-context-20130208.json')
27
+ end
28
+ it 'CONTENT_TYPE_IIIF' do
29
+ const = TriannonClient::TriannonClient::CONTENT_TYPE_IIIF
30
+ expect(const).to be_instance_of String
31
+ expect(const).to include('application/ld+json')
32
+ expect(const).to include('http://iiif.io/api/presentation/2/context.json')
33
+ end
34
+ it 'CONTENT_TYPE_OA' do
35
+ const = TriannonClient::TriannonClient::CONTENT_TYPE_OA
36
+ expect(const).to be_instance_of String
37
+ expect(const).to include('application/ld+json')
38
+ expect(const).to include('http://www.w3.org/ns/oa-context-20130208.json')
39
+ end
40
+ it 'JSONLD_TYPE' do
41
+ const = TriannonClient::TriannonClient::JSONLD_TYPE
42
+ expect(const).to be_instance_of String
43
+ expect(const).to eql('application/ld+json')
44
+ end
45
+ end
46
+
47
+ describe 'public attributes:' do
48
+ # attribute accessors
49
+ it 'config' do
50
+ expect(tc).to respond_to(:config)
51
+ end
52
+ it 'site' do
53
+ expect(tc).to respond_to(:site)
54
+ end
55
+ it 'auth' do
56
+ expect(tc).to respond_to(:auth)
57
+ end
58
+ it 'container' do
59
+ expect(tc).to respond_to(:container)
60
+ end
61
+ end
62
+
63
+ describe 'public methods:' do
64
+ # methods
65
+ it 'authenticate' do
66
+ expect(tc).to respond_to(:authenticate)
67
+ end
68
+ it 'delete_annotation' do
69
+ expect(tc).to respond_to(:delete_annotation)
70
+ end
71
+ it 'get_annotations' do
72
+ expect(tc).to respond_to(:get_annotations)
73
+ end
74
+ it 'get_annotation' do
75
+ expect(tc).to respond_to(:get_annotation)
76
+ end
77
+ it 'get_iiif_annotation' do
78
+ expect(tc).to respond_to(:get_iiif_annotation)
79
+ end
80
+ it 'get_oa_annotation' do
81
+ expect(tc).to respond_to(:get_oa_annotation)
82
+ end
83
+ # utilities
84
+ it 'response2graph' do
85
+ expect(tc).to respond_to(:response2graph)
86
+ end
87
+ it 'annotation_id' do
88
+ expect(tc).to respond_to(:annotation_id)
89
+ end
90
+ it 'annotation_uris' do
91
+ expect(tc).to respond_to(:annotation_uris)
92
+ end
93
+ end
94
+
95
+ describe 'private:' do
96
+ it 'check_id' do
97
+ expect(tc).not_to respond_to(:check_id)
98
+ end
99
+ it 'check_content_type' do
100
+ expect(tc).not_to respond_to(:check_content_type)
101
+ end
102
+ end
103
+
104
+ end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.shared_examples "create annotations" do |auth_required|
4
+
5
+ let(:tc) {
6
+ if auth_required
7
+ triannon_config_auth
8
+ else
9
+ triannon_config_no_auth
10
+ end
11
+ TriannonClient::TriannonClient.new
12
+ }
13
+
14
+ def check_authentication(required)
15
+ auth = tc.authenticate
16
+ if required
17
+ expect(auth).to be_truthy
18
+ else
19
+ expect(auth).to be false
20
+ end
21
+ end
22
+
23
+ let(:exception_data) { 'post_exception' }
24
+ let(:exception_post) {
25
+ {
26
+ "commit"=>"Create Annotation",
27
+ "annotation"=>{"data"=>exception_data}
28
+ }
29
+ }
30
+ let(:exception_msg) { 'create_exception' }
31
+
32
+ def raise_restclient_exception(status)
33
+ response = double
34
+ allow(response).to receive(:is_a?).and_return(RestClient::Response)
35
+ allow(response).to receive(:headers).and_return(jsonld_content)
36
+ allow(response).to receive(:body).and_return(exception_msg)
37
+ allow(response).to receive(:code).and_return(status)
38
+ exception = RestClient::Exception.new(response)
39
+ allow_any_instance_of(RestClient::Resource).to receive(:post).with(exception_post).and_raise(exception)
40
+ if status == 401
41
+ expect(tc).to receive(:authenticate).once # retry triggers authentication
42
+ else
43
+ expect(tc).not_to receive(:authenticate) # no retry
44
+ end
45
+ end
46
+
47
+ it 'does not raise an error when submitting a valid open annotation' do
48
+ check_authentication(auth_required)
49
+ response = nil
50
+ expect do
51
+ response = tc.post_annotation(jsonld_oa)
52
+ end.not_to raise_error
53
+ # Double check the POST by deleting the annotation.
54
+ # If the POST was successful, the DELETE should work too.
55
+ graph = tc.response2graph(response)
56
+ uri = tc.annotation_uris(graph).first
57
+ id = tc.annotation_id(uri)
58
+ expect(tc.delete_annotation(id)).to be true
59
+ end
60
+ it 'returns a RestClient::Response object' do
61
+ # The response behaves primarily as a String, so it can not be tested
62
+ # as an instance of RestClient::Response, but it can be tested to respond
63
+ # to RestClient::Response methods.
64
+ check_authentication(auth_required)
65
+ anno = create_annotation
66
+ r = anno[:response]
67
+ expect(r.is_a? RestClient::Response).to be true
68
+ expect(r).to respond_to(:code)
69
+ expect(r).to respond_to(:body)
70
+ expect(r).to respond_to(:headers)
71
+ end
72
+ it 'POST 401 response retries and logs RestClient::Exception message' do
73
+ check_authentication(auth_required)
74
+ raise_restclient_exception(401)
75
+ expect(TriannonClient.configuration.logger).to receive(:error).with(/#{exception_msg}/)
76
+ tc.post_annotation(exception_data)
77
+ end
78
+ it 'POST 403 response does not retry and logs RestClient::Exception message' do
79
+ check_authentication(auth_required)
80
+ raise_restclient_exception(403)
81
+ expect(TriannonClient.configuration.logger).to receive(:error).with(/#{exception_msg}/)
82
+ tc.post_annotation(exception_data)
83
+ end
84
+ it 'POST 500 response does not retry and logs RestClient::Exception message' do
85
+ check_authentication(auth_required)
86
+ raise_restclient_exception(500)
87
+ expect(TriannonClient.configuration.logger).to receive(:error).with(/#{exception_msg}/)
88
+ tc.post_annotation(exception_data)
89
+ end
90
+ it 'logs RuntimeError message' do
91
+ check_authentication(auth_required)
92
+ exception = RuntimeError.new(exception_msg)
93
+ allow_any_instance_of(RestClient::Resource).to receive(:post).with(exception_post).and_raise(exception)
94
+ expect(TriannonClient.configuration.logger).to receive(:error).with(/#{exception_msg}/)
95
+ tc.post_annotation(exception_data)
96
+ end
97
+ end
98
+
99
+
100
+ describe 'TriannonClientCREATE', :vcr do
101
+
102
+ after :all do
103
+ clear_annotations('TriannonClientCREATE/clear_annotations')
104
+ end
105
+
106
+ describe "#post_annotation" do
107
+
108
+ context 'without authentication' do
109
+ auth_required = false # it's not required
110
+ it_behaves_like 'create annotations', auth_required
111
+ end
112
+
113
+ context 'with authentication' do
114
+ auth_required = true # it must succeed
115
+ it_behaves_like 'create annotations', auth_required
116
+ end
117
+ end
118
+
119
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.shared_examples "delete annotations" do |auth_required|
4
+
5
+ let(:tc) {
6
+ if auth_required
7
+ triannon_config_auth
8
+ else
9
+ triannon_config_no_auth
10
+ end
11
+ TriannonClient::TriannonClient.new
12
+ }
13
+
14
+ def test_delete_for_response_code(anno_id, status, result)
15
+ response = double
16
+ allow(response).to receive(:is_a?).and_return(RestClient::Response)
17
+ allow(response).to receive(:headers).and_return(jsonld_content)
18
+ allow(response).to receive(:body).and_return('delete_annotation')
19
+ allow(response).to receive(:code).and_return(status)
20
+ exception = RestClient::Exception.new(response)
21
+ if [401, 404, 410, 500].include? status
22
+ allow_any_instance_of(RestClient::Resource).to receive(:delete).and_raise(exception)
23
+ if status == 401
24
+ expect(tc).to receive(:authenticate).once # retry triggers auth
25
+ else
26
+ expect(tc).not_to receive(:authenticate) # no retry
27
+ end
28
+ else
29
+ allow_any_instance_of(RestClient::Resource).to receive(:delete).and_return(response)
30
+ expect(tc).not_to receive(:authenticate) # no retry
31
+ end
32
+ expect(tc.delete_annotation(anno_id)).to be result
33
+ end
34
+ it "DELETE 200 response returns true" do
35
+ test_delete_for_response_code('200_is_true', 200, true)
36
+ end
37
+ it "DELETE 202 response returns true" do
38
+ test_delete_for_response_code('202_is_true', 202, true)
39
+ end
40
+ it "DELETE 204 response returns true" do
41
+ test_delete_for_response_code('204_is_true', 204, true)
42
+ end
43
+ it "DELETE 401 response initiates a retry with authentication" do
44
+ test_delete_for_response_code('401_is_retry', 401, false)
45
+ end
46
+ it "DELETE 404 response returns true" do
47
+ test_delete_for_response_code('404_is_true', 404, true)
48
+ end
49
+ it "DELETE 410 response returns true" do
50
+ test_delete_for_response_code('410_is_true', 410, true)
51
+ end
52
+ it "DELETE 500 response returns false" do
53
+ test_delete_for_response_code('500_is_false', 500, false)
54
+ end
55
+ it 'DELETE 404|410 does not log exceptions' do
56
+ expect(tc.config.logger).not_to receive(:error)
57
+ test_delete_for_response_code('404_is_true', 404, true)
58
+ test_delete_for_response_code('410_is_true', 410, true)
59
+ end
60
+ it 'DELETE 500 logs exceptions' do
61
+ expect(tc.config.logger).to receive(:error)
62
+ test_delete_for_response_code('500_is_false', 500, false)
63
+ end
64
+ it 'validates the annotation ID' do
65
+ expect(tc).to receive(:check_id)
66
+ tc.delete_annotation('checking_anno_id')
67
+ end
68
+ it 'raises ArgumentError for an invalid annotation ID' do
69
+ expect_any_instance_of(RestClient::Resource).not_to receive(:delete)
70
+ expect { tc.delete_annotation('') }.to raise_error(ArgumentError)
71
+ expect { tc.delete_annotation(nil) }.to raise_error(ArgumentError)
72
+ end
73
+ it 'uses RestClient::Resource.delete to DELETE a valid annotation ID' do
74
+ expect_any_instance_of(RestClient::Resource).to receive(:delete)
75
+ tc.delete_annotation(SecureRandom.uuid)
76
+ end
77
+ it 'returns TRUE when deleting an annotation that exists' do
78
+ anno = create_annotation
79
+ expect( tc.delete_annotation(anno[:id]) ).to be true
80
+ graph = tc.get_annotation(anno[:id])
81
+ graph_is_empty(graph)
82
+ end
83
+ it 'returns TRUE when deleting an annotation that does NOT exist' do
84
+ id = 'anno_does_not_exist'
85
+ graph = tc.get_annotation(id)
86
+ graph_is_empty(graph)
87
+ expect( tc.delete_annotation(id) ).to be true
88
+ end
89
+
90
+ end
91
+
92
+
93
+ describe 'TriannonClientDELETE', :vcr do
94
+
95
+ # before :all do
96
+ # # create a new annotation and call all the response processing utils.
97
+ # @anno = create_annotation('TriannonClientDELETE/create_annotation')
98
+ # end
99
+
100
+ after :all do
101
+ clear_annotations('TriannonClientDELETE/clear_annotations')
102
+ end
103
+
104
+ describe "#delete_annotation" do
105
+
106
+ context 'without authentication' do
107
+ auth_required = false # it's not required
108
+ it_behaves_like 'delete annotations', auth_required
109
+ end
110
+
111
+ context 'with authentication' do
112
+ auth_required = true # it must succeed
113
+ it_behaves_like 'delete annotations', auth_required
114
+ end
115
+ end
116
+
117
+ end
@@ -0,0 +1,342 @@
1
+ require 'spec_helper'
2
+
3
+ # ::TriannonClient::TriannonClient GET specs
4
+ # The GET requests do not require authentication.
5
+
6
+ describe 'TriannonClientREAD', :vcr do
7
+
8
+ before :all do
9
+ # create a new annotation and call all the response processing utils.
10
+ @anno = create_annotation('TriannonClientREAD/create_annotation')
11
+ end
12
+
13
+ after :all do
14
+ clear_annotations('TriannonClientREAD/clear_annotations')
15
+ end
16
+
17
+ let(:tc) {
18
+ # triannon_config_auth
19
+ TriannonClient::TriannonClient.new
20
+ }
21
+
22
+ def request_anno_with_content_type(content_type)
23
+ expect_any_instance_of(RestClient::Resource).to receive(:get).with(hash_including(:accept => content_type) )
24
+ tc.get_annotation(@anno[:id], content_type)
25
+ end
26
+
27
+ def gets_anno_with_content_type(content_type)
28
+ graph = tc.get_annotation(@anno[:id], content_type)
29
+ graph_contains_open_annotation(graph, @anno[:uris])
30
+ end
31
+
32
+ def cannot_get_anno_with_content_type(content_type)
33
+ graph = tc.get_annotation(@anno[:id], content_type)
34
+ graph_is_empty(graph)
35
+ end
36
+
37
+
38
+ let(:exception_msg) { 'get_exception' }
39
+ def raise_restclient_exception(status)
40
+ response = double
41
+ allow(response).to receive(:is_a?).and_return(RestClient::Response)
42
+ allow(response).to receive(:headers).and_return(jsonld_content)
43
+ allow(response).to receive(:body).and_return(exception_msg)
44
+ allow(response).to receive(:code).and_return(status)
45
+ exception = RestClient::Exception.new(response)
46
+ allow_any_instance_of(RestClient::Resource).to receive(:get).with(jsonld_accept).and_raise(exception)
47
+ end
48
+
49
+ context 'GET' do
50
+
51
+ describe "#get_annotations" do
52
+ it 'returns an RDF::Graph' do
53
+ graph = tc.get_annotations
54
+ graph_contains_statements(graph)
55
+ end
56
+ it 'returns an RDF::Graph that contains an AnnotationList' do
57
+ graph = tc.get_annotations
58
+ anno_list_uri = RDF::URI.parse('http://iiif.io/api/presentation/2#AnnotationList')
59
+ result = graph.query([nil, nil, anno_list_uri])
60
+ expect(result.size).to eql(1)
61
+ end
62
+ it 'returns an annotation list with an annotation created by a prior POST' do
63
+ graph = tc.get_annotations
64
+ graph_contains_open_annotation(graph, @anno[:uris])
65
+ end
66
+ it '404 response logs exceptions for RestClient::Exception' do
67
+ raise_restclient_exception(404)
68
+ expect(tc.config.logger).to receive(:error).with(/404/)
69
+ tc.get_annotations
70
+ end
71
+ it '500 response returns an EMPTY RDF graph' do
72
+ raise_restclient_exception(500)
73
+ graph = tc.get_annotations
74
+ graph_is_empty(graph)
75
+ end
76
+ it '500 response logs exceptions for RestClient::Exception' do
77
+ raise_restclient_exception(500)
78
+ expect(tc.config.logger).to receive(:error).with(/#{exception_msg}/)
79
+ tc.get_annotations
80
+ end
81
+ it 'logs exceptions for RuntimeError' do
82
+ exception = RuntimeError.new('get_exception')
83
+ allow_any_instance_of(RestClient::Resource).to receive(:get).with(jsonld_accept).and_raise(exception)
84
+ expect(tc.config.logger).to receive(:error).with(/get_exception/)
85
+ tc.get_annotations
86
+ end
87
+ end
88
+
89
+ describe "#get_iiif_annotation" do
90
+ # the mime type is fixed for this method
91
+ it 'requests an open annotation by ID, using a IIIF profile' do
92
+ graph_contains_open_annotation(@anno[:graph], @anno[:uris])
93
+ content_type = TriannonClient::TriannonClient::CONTENT_TYPE_IIIF
94
+ expect(tc).to receive(:get_annotation).with(@anno[:id], content_type)
95
+ tc.get_iiif_annotation(@anno[:id])
96
+ end
97
+ it 'returns an RDF::Graph of an open annotation' do
98
+ graph = tc.get_iiif_annotation(@anno[:id])
99
+ graph_contains_statements(graph)
100
+ graph_contains_open_annotation(graph, @anno[:uris])
101
+ end
102
+ end
103
+
104
+ describe "#get_oa_annotation" do
105
+ # the mime type is fixed for this method
106
+ it 'requests an open annotation by ID, using an OA profile' do
107
+ graph_contains_open_annotation(@anno[:graph], @anno[:uris])
108
+ content_type = TriannonClient::TriannonClient::CONTENT_TYPE_OA
109
+ expect(tc).to receive(:get_annotation).with(@anno[:id], content_type)
110
+ tc.get_oa_annotation(@anno[:id])
111
+ end
112
+ it 'returns an RDF::Graph of an open annotation' do
113
+ graph = tc.get_oa_annotation(@anno[:id])
114
+ graph_contains_statements(graph)
115
+ graph_contains_open_annotation(graph, @anno[:uris])
116
+ end
117
+ end
118
+
119
+ describe '#response2graph' do
120
+ it 'accepts a RestClient::Response instance' do
121
+ r = @anno[:response]
122
+ expect{tc.response2graph(r)}.not_to raise_error
123
+ end
124
+ it 'returns an RDF::Graph' do
125
+ expect(@anno[:graph]).to be_instance_of RDF::Graph
126
+ graph_contains_statements(@anno[:graph])
127
+ end
128
+ it 'raises ArgumentError when given nil' do
129
+ expect{tc.response2graph(nil)}.to raise_error(ArgumentError)
130
+ end
131
+ it 'raises ArgumentError when given an empty String' do
132
+ expect{tc.response2graph('')}.to raise_error(ArgumentError)
133
+ end
134
+ it 'raises ArgumentError when response content-type is unacceptable' do
135
+ h = {content_type: 'unacceptable'}
136
+ r = double
137
+ allow(r).to receive(:is_a?).and_return(RestClient::Response)
138
+ allow(r).to receive(:headers).and_return(h)
139
+ expect{tc.response2graph('')}.to raise_error(ArgumentError)
140
+ end
141
+ it 'returns an empty RDF::Graph for failure to parse input' do
142
+ r = double
143
+ allow(r).to receive(:is_a?).and_return(RestClient::Response)
144
+ allow(r).to receive(:code).and_return(200)
145
+ allow(r).to receive(:headers).and_return(jsonld_content)
146
+ allow(r).to receive(:body).and_return('malformed json')
147
+ g = tc.response2graph(r)
148
+ expect(g).to be_instance_of RDF::Graph
149
+ expect(g).to be_empty
150
+ h = {content_type: 'application/rdf+xml'}
151
+ allow(r).to receive(:headers).and_return(h)
152
+ allow(r).to receive(:body).and_return('malformed rdf+xml')
153
+ g = tc.response2graph(r)
154
+ expect(g).to be_instance_of RDF::Graph
155
+ expect(g).to be_empty
156
+ # h = {content_type: 'application/turtle'}
157
+ # allow(r).to receive(:headers).and_return(h)
158
+ # allow(r).to receive(:body).and_return('malformed turtle')
159
+ # g = tc.response2graph(r)
160
+ # expect(g).to be_instance_of RDF::Graph
161
+ # expect(g).to be_empty
162
+ end
163
+ it 'logs exceptions and returns an empty RDF::Graph' do
164
+ r = double
165
+ allow(r).to receive(:is_a?).and_return(RestClient::Response)
166
+ allow(r).to receive(:headers).and_return(jsonld_content)
167
+ allow(r).to receive(:body).and_raise(RuntimeError, 'oops!')
168
+ expect(tc.config.logger).to receive(:error).with(/oops!/)
169
+ g = tc.response2graph(r)
170
+ expect(g).to be_instance_of RDF::Graph
171
+ expect(g).to be_empty
172
+ end
173
+
174
+
175
+ end
176
+
177
+ describe "#annotation_uris" do
178
+ it "returns an array of RDF::URI from an RDF::Graph of an annotation" do
179
+ expect(@anno[:graph]).to be_instance_of RDF::Graph
180
+ expect(@anno[:uris]).to be_instance_of Array
181
+ expect(@anno[:uris]).not_to be_empty
182
+ expect(@anno[:uris].first).to be_instance_of RDF::URI
183
+ end
184
+ it "returns an RDF::URI that is a valid URI" do
185
+ expect(@anno[:uris].first).to match(/\A#{URI::regexp}\z/)
186
+ end
187
+ end
188
+
189
+ describe "#annotation_id" do
190
+ it "returns a String ID from the RDF::URI of an annotation" do
191
+ expect(@anno[:uris].first).to be_instance_of RDF::URI
192
+ expect(@anno[:id]).to be_instance_of String
193
+ end
194
+ it "returns a String ID that is not empty" do
195
+ expect(@anno[:id]).to be_instance_of String
196
+ expect(@anno[:id]).not_to be_empty
197
+ end
198
+ end
199
+
200
+ describe "annotation by ID" do
201
+
202
+ context 'using default content type' do
203
+
204
+ it 'checks the annotation ID' do
205
+ expect(tc).to receive(:check_id)
206
+ graph = tc.get_annotation(@anno[:id])
207
+ graph_contains_statements(graph)
208
+ end
209
+ it 'raises an argument error with a nil ID' do
210
+ expect{tc.get_annotation(nil)}.to raise_error(ArgumentError)
211
+ end
212
+ it 'raises an argument error with an integer ID' do
213
+ expect{tc.get_annotation(0)}.to raise_error(ArgumentError)
214
+ end
215
+ it 'raises an argument error with an empty string ID' do
216
+ expect{tc.get_annotation('')}.to raise_error(ArgumentError)
217
+ end
218
+ it 'requests an open annotation by ID, using JSON-LD content' do
219
+ jsonld = TriannonClient::TriannonClient::JSONLD_TYPE
220
+ expect_any_instance_of(RestClient::Resource).to receive(:get).with(hash_including(:accept => jsonld) )
221
+ # does not work using expect(tc.container).to receive(:get) etc.
222
+ tc.get_annotation(@anno[:id])
223
+ end
224
+ it 'returns an RDF graph with a valid ID for an annotation on the server' do
225
+ graph = tc.get_annotation(@anno[:id])
226
+ graph_contains_open_annotation(graph, @anno[:uris])
227
+ end
228
+ it 'returns an EMPTY RDF graph with a valid ID for NO annotation on the server' do
229
+ id = SecureRandom.uuid
230
+ graph = tc.get_annotation(id)
231
+ graph_is_empty(graph)
232
+ end
233
+ it '404 response logs exceptions for RestClient::Exception' do
234
+ raise_restclient_exception(404)
235
+ expect(tc.config.logger).to receive(:error).with(/404/)
236
+ tc.get_annotation('raise_get_exception')
237
+ end
238
+ it '500 response returns an EMPTY RDF graph' do
239
+ raise_restclient_exception(500)
240
+ graph = tc.get_annotation(@anno[:id])
241
+ graph_is_empty(graph)
242
+ end
243
+ it '500 response logs exceptions for RestClient::Exception' do
244
+ raise_restclient_exception(500)
245
+ expect(tc.config.logger).to receive(:error).with(/#{exception_msg}/)
246
+ tc.get_annotation(@anno[:id])
247
+ end
248
+ it 'logs exceptions for RuntimeError' do
249
+ exception = RuntimeError.new('get_exception')
250
+ allow_any_instance_of(RestClient::Resource).to receive(:get).with(jsonld_accept).and_raise(exception)
251
+ expect(tc.config.logger).to receive(:error).with(/get_exception/)
252
+ tc.get_annotation(@anno[:id])
253
+ end
254
+ end # using default content type
255
+
256
+ context 'using custom content type' do
257
+ # Content types could be supported for RDF::Format.content_types.keys,
258
+ # but not all of them are supported. The supported content types for
259
+ # triannon are defined in
260
+ # https://github.com/sul-dlss/triannon/blob/master/config/initializers/mime_types.rb
261
+ # https://github.com/sul-dlss/triannon/blob/master/app/controllers/triannon/annotations_controller.rb
262
+ # https://github.com/sul-dlss/triannon/blob/master/app/controllers/triannon/search_controller.rb
263
+ # The default content type is "application/ld+json" and, at the time of
264
+ # writing, triannon also supports:
265
+ # turtle as: ["application/x-turtle", "text/turtle"]
266
+ # rdf+xml as: ["application/rdf+xml", "text/rdf+xml", "text/rdf"]
267
+ # json as: ["application/json", "text/x-json", "application/jsonrequest"]
268
+ # xml as: ["application/xml", "text/xml", "application/x-xml"]
269
+ # html
270
+
271
+ # The client supports any format in RDF::Format.content_types, so the
272
+ # following are not included (as of July 2015):
273
+ # "application/json" => true,
274
+ # "application/jsonrequest" => true,
275
+ # "text/x-json" => true,
276
+ # "text/rdf+xml" => true,
277
+ # "text/rdf" => true,
278
+ # "application/xml" => true,
279
+ # "text/xml" => true,
280
+ # "application/x-xml" => true,
281
+
282
+ # html and xhtml are supported by RDF::Format, so they can be used,
283
+ # but they fail to return a proper RDF::Graph
284
+ # "text/html"=> true,
285
+ # "application/xhtml+xml"=> true,
286
+
287
+ # content types that work
288
+ content_types = {
289
+ "application/ld+json"=> true,
290
+ "application/rdf+xml"=> true,
291
+ "text/turtle"=> true,
292
+ "application/x-turtle"=> true,
293
+ }
294
+ # content types that fail
295
+ content_types.merge!({
296
+ "application/x-ld+json"=> false,
297
+ "application/rdf+json"=> false,
298
+ "text/rdf+turtle"=> false,
299
+ "application/turtle"=> false,
300
+ "application/n-triples"=> false,
301
+ "application/rdf+n3"=> false,
302
+ "text/n3"=> false,
303
+ "text/rdf+n3"=> false,
304
+ "text/plain"=> false,
305
+ "application/n-quads"=> false,
306
+ "text/x-nquads"=> false,
307
+ "application/trig"=> false,
308
+ "application/x-trig"=> false,
309
+ "application/trix"=> false,
310
+ "text/csv"=> false,
311
+ "text/tab-separated-values"=>false,
312
+ "application/csvm+json"=>false,
313
+ })
314
+ specs = content_types.map do |type,success|
315
+ request_spec = <<EOS
316
+ it 'requests an open annotation by ID, with content type "#{type}"' do
317
+ request_anno_with_content_type('#{type}')
318
+ end
319
+ EOS
320
+ if success
321
+ get_spec = <<EOS
322
+ it 'gets an open annotation by ID, with content type "#{type}"' do
323
+ gets_anno_with_content_type('#{type}')
324
+ end
325
+ EOS
326
+ else
327
+ get_spec = <<EOS
328
+ it 'cannot get an open annotation by ID, with content type "#{type}"' do
329
+ cannot_get_anno_with_content_type('#{type}')
330
+ end
331
+ EOS
332
+ end
333
+ request_spec + get_spec
334
+ end
335
+ eval(specs.join)
336
+ end # using custom content type
337
+
338
+ end # annotation by ID
339
+ end # GET context
340
+
341
+ end
342
+