triannon-client 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+