From c3be85bc434e5fc8d7f4f7968612c06c94153bfa Mon Sep 17 00:00:00 2001 From: Alex Skrenchuk Date: Mon, 28 Jul 2025 16:39:29 -0700 Subject: [PATCH 1/3] Avoid following PURL redirects and split PURL tests into a separate file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated PURL-related tests to assert only the HTTP 302 status and Location header, without following the redirect to the BioPortal UI. This avoids triggering Cloudflare bot protection during CI runs. We do not want to test UI behavior here — we only verify that the correct redirect is served by the PURL resolver. Testing how the UI handles or rewrites URLs (e.g., with query parameters or concept ID fragments) is out of scope for these tests. Split PURL resolution tests into a new file test_class_purl.rb to separate concerns from core class model tests in test_class.rb Resolves ncbo/ontologies_api_ruby_client/issues/41 --- Gemfile.lock | 2 +- test/models/test_class.rb | 55 ------------------------------- test/models/test_class_purl.rb | 59 ++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 56 deletions(-) create mode 100644 test/models/test_class_purl.rb diff --git a/Gemfile.lock b/Gemfile.lock index 4a01ba6..94cafd0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -100,7 +100,7 @@ GEM unicode-display_width (3.1.4) unicode-emoji (~> 4.0, >= 4.0.4) unicode-emoji (4.0.4) - uri (1.0.2) + uri (1.0.3) PLATFORMS arm64-darwin-24 diff --git a/test/models/test_class.rb b/test/models/test_class.rb index 0229ffe..b6a07e5 100644 --- a/test/models/test_class.rb +++ b/test/models/test_class.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require 'faraday/follow_redirects' require_relative '../test_case' class ClassTest < LinkedData::Client::TestCase @@ -16,58 +15,4 @@ def test_find assert_equal ontology, cls.links['ontology'] assert cls.hasChildren end - - # Test PURL generation for a class in an OWL format ontology - def test_purl_owl - cls = LinkedData::Client::Models::Class.find( - 'http://bioontology.org/ontologies/Activity.owl#Activity', - 'https://data.bioontology.org/ontologies/BRO' - ) - refute_nil cls - - res = fetch_response(cls.purl) - assert_equal 200, res.status - assert_equal 'https://bioportal.bioontology.org/ontologies/BRO'\ - '?p=classes&conceptid=http%3A%2F%2Fbioontology.org%2Fontologies%2FActivity.owl%23Activity', - res.env[:url].to_s - end - - # Test PURL generation for a class in a UMLS format ontology - def test_purl_umls - cls = LinkedData::Client::Models::Class.find( - 'http://purl.bioontology.org/ontology/SNOMEDCT/64572001', - 'https://bioportal.bioontology.org/ontologies/SNOMEDCT' - ) - refute_nil cls - - res = fetch_response(cls.purl) - assert_equal 200, res.status - assert_equal 'https://bioportal.bioontology.org/ontologies/SNOMEDCT?p=classes&conceptid=64572001', - res.env[:url].to_s - end - - # Test PURL generation for a class in an OBO format ontology - def test_purl_obo - cls = LinkedData::Client::Models::Class.find( - 'http://purl.obolibrary.org/obo/DOID_4', - 'https://bioportal.bioontology.org/ontologies/DOID' - ) - refute_nil cls - - res = fetch_response(cls.purl) - assert_equal 200, res.status - assert_equal 'https://bioportal.bioontology.org/ontologies/DOID'\ - '?p=classes&conceptid=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FDOID_4', - res.env[:url].to_s - end - - private - - def fetch_response(url) - conn = Faraday.new do |f| - f.response :follow_redirects - f.adapter Faraday.default_adapter - end - conn.get(url) - end end diff --git a/test/models/test_class_purl.rb b/test/models/test_class_purl.rb new file mode 100644 index 0000000..e9893f7 --- /dev/null +++ b/test/models/test_class_purl.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require_relative '../test_case' + +class ClassTest < LinkedData::Client::TestCase + + # Test PURL generation for a class in an OWL format ontology + def test_purl_owl + cls = LinkedData::Client::Models::Class.find( + 'http://bioontology.org/ontologies/Activity.owl#Activity', + 'https://data.bioontology.org/ontologies/BRO' + ) + refute_nil cls + + res = fetch_response(cls.purl) + assert_equal 302, res.status + assert_equal 'https://bioportal.bioontology.org/ontologies/BRO'\ + '/classes?conceptid=http%3A%2F%2Fbioontology.org%2Fontologies%2FActivity.owl%23Activity', + res.headers['location'] + end + + # Test PURL generation for a class in a UMLS format ontology + def test_purl_umls + cls = LinkedData::Client::Models::Class.find( + 'http://purl.bioontology.org/ontology/SNOMEDCT/64572001', + 'https://bioportal.bioontology.org/ontologies/SNOMEDCT' + ) + refute_nil cls + + res = fetch_response(cls.purl) + assert_equal 302, res.status + assert_equal 'https://bioportal.bioontology.org/ontologies/SNOMEDCT/classes/64572001', + res.headers['location'] + end + + # Test PURL generation for a class in an OBO format ontology + def test_purl_obo + cls = LinkedData::Client::Models::Class.find( + 'http://purl.obolibrary.org/obo/DOID_4', + 'https://bioportal.bioontology.org/ontologies/DOID' + ) + refute_nil cls + + res = fetch_response(cls.purl) + assert_equal 302, res.status + assert_equal 'https://bioportal.bioontology.org/ontologies/DOID'\ + '/classes?conceptid=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FDOID_4', + res.headers['location'] + end + + private + + def fetch_response(url) + conn = Faraday.new do |f| + f.adapter Faraday.default_adapter + end + conn.get(url) + end +end From 0523e4f36e5e980ff8ef00d1562f017315d9bc71 Mon Sep 17 00:00:00 2001 From: Alex Skrenchuk Date: Mon, 28 Jul 2025 18:31:59 -0700 Subject: [PATCH 2/3] Revert "Avoid following PURL redirects and split PURL tests into a separate file" This reverts commit c3be85bc434e5fc8d7f4f7968612c06c94153bfa. --- Gemfile.lock | 2 +- test/models/test_class.rb | 55 +++++++++++++++++++++++++++++++ test/models/test_class_purl.rb | 59 ---------------------------------- 3 files changed, 56 insertions(+), 60 deletions(-) delete mode 100644 test/models/test_class_purl.rb diff --git a/Gemfile.lock b/Gemfile.lock index 94cafd0..4a01ba6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -100,7 +100,7 @@ GEM unicode-display_width (3.1.4) unicode-emoji (~> 4.0, >= 4.0.4) unicode-emoji (4.0.4) - uri (1.0.3) + uri (1.0.2) PLATFORMS arm64-darwin-24 diff --git a/test/models/test_class.rb b/test/models/test_class.rb index b6a07e5..0229ffe 100644 --- a/test/models/test_class.rb +++ b/test/models/test_class.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require 'faraday/follow_redirects' require_relative '../test_case' class ClassTest < LinkedData::Client::TestCase @@ -15,4 +16,58 @@ def test_find assert_equal ontology, cls.links['ontology'] assert cls.hasChildren end + + # Test PURL generation for a class in an OWL format ontology + def test_purl_owl + cls = LinkedData::Client::Models::Class.find( + 'http://bioontology.org/ontologies/Activity.owl#Activity', + 'https://data.bioontology.org/ontologies/BRO' + ) + refute_nil cls + + res = fetch_response(cls.purl) + assert_equal 200, res.status + assert_equal 'https://bioportal.bioontology.org/ontologies/BRO'\ + '?p=classes&conceptid=http%3A%2F%2Fbioontology.org%2Fontologies%2FActivity.owl%23Activity', + res.env[:url].to_s + end + + # Test PURL generation for a class in a UMLS format ontology + def test_purl_umls + cls = LinkedData::Client::Models::Class.find( + 'http://purl.bioontology.org/ontology/SNOMEDCT/64572001', + 'https://bioportal.bioontology.org/ontologies/SNOMEDCT' + ) + refute_nil cls + + res = fetch_response(cls.purl) + assert_equal 200, res.status + assert_equal 'https://bioportal.bioontology.org/ontologies/SNOMEDCT?p=classes&conceptid=64572001', + res.env[:url].to_s + end + + # Test PURL generation for a class in an OBO format ontology + def test_purl_obo + cls = LinkedData::Client::Models::Class.find( + 'http://purl.obolibrary.org/obo/DOID_4', + 'https://bioportal.bioontology.org/ontologies/DOID' + ) + refute_nil cls + + res = fetch_response(cls.purl) + assert_equal 200, res.status + assert_equal 'https://bioportal.bioontology.org/ontologies/DOID'\ + '?p=classes&conceptid=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FDOID_4', + res.env[:url].to_s + end + + private + + def fetch_response(url) + conn = Faraday.new do |f| + f.response :follow_redirects + f.adapter Faraday.default_adapter + end + conn.get(url) + end end diff --git a/test/models/test_class_purl.rb b/test/models/test_class_purl.rb deleted file mode 100644 index e9893f7..0000000 --- a/test/models/test_class_purl.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -require_relative '../test_case' - -class ClassTest < LinkedData::Client::TestCase - - # Test PURL generation for a class in an OWL format ontology - def test_purl_owl - cls = LinkedData::Client::Models::Class.find( - 'http://bioontology.org/ontologies/Activity.owl#Activity', - 'https://data.bioontology.org/ontologies/BRO' - ) - refute_nil cls - - res = fetch_response(cls.purl) - assert_equal 302, res.status - assert_equal 'https://bioportal.bioontology.org/ontologies/BRO'\ - '/classes?conceptid=http%3A%2F%2Fbioontology.org%2Fontologies%2FActivity.owl%23Activity', - res.headers['location'] - end - - # Test PURL generation for a class in a UMLS format ontology - def test_purl_umls - cls = LinkedData::Client::Models::Class.find( - 'http://purl.bioontology.org/ontology/SNOMEDCT/64572001', - 'https://bioportal.bioontology.org/ontologies/SNOMEDCT' - ) - refute_nil cls - - res = fetch_response(cls.purl) - assert_equal 302, res.status - assert_equal 'https://bioportal.bioontology.org/ontologies/SNOMEDCT/classes/64572001', - res.headers['location'] - end - - # Test PURL generation for a class in an OBO format ontology - def test_purl_obo - cls = LinkedData::Client::Models::Class.find( - 'http://purl.obolibrary.org/obo/DOID_4', - 'https://bioportal.bioontology.org/ontologies/DOID' - ) - refute_nil cls - - res = fetch_response(cls.purl) - assert_equal 302, res.status - assert_equal 'https://bioportal.bioontology.org/ontologies/DOID'\ - '/classes?conceptid=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FDOID_4', - res.headers['location'] - end - - private - - def fetch_response(url) - conn = Faraday.new do |f| - f.adapter Faraday.default_adapter - end - conn.get(url) - end -end From 252954905aca1f433890e12ec8583ffc7898cc36 Mon Sep 17 00:00:00 2001 From: Alex Skrenchuk Date: Mon, 28 Jul 2025 20:40:09 -0700 Subject: [PATCH 3/3] test: assert PURL construction and redirect headers without following UI redirects Updated tests for the `.purl` method to: - Assert the constructed URL matches the expected output based on client config - Confirm the PURL resolves via HTTP 302 to the correct UI target - Avoid following the UI-level redirect to prevent Cloudflare issues in CI - Used `@@purl_prefix` from config.purl_prefix. --- Gemfile.lock | 2 +- test/models/test_class.rb | 37 +++++++++++++++++++++---------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4a01ba6..94cafd0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -100,7 +100,7 @@ GEM unicode-display_width (3.1.4) unicode-emoji (~> 4.0, >= 4.0.4) unicode-emoji (4.0.4) - uri (1.0.2) + uri (1.0.3) PLATFORMS arm64-darwin-24 diff --git a/test/models/test_class.rb b/test/models/test_class.rb index 0229ffe..c0d6942 100644 --- a/test/models/test_class.rb +++ b/test/models/test_class.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true -require 'faraday/follow_redirects' require_relative '../test_case' class ClassTest < LinkedData::Client::TestCase + @@purl_prefix = LinkedData::Client.settings.purl_prefix + def test_find id = 'http://bioontology.org/ontologies/Activity.owl#Activity' ontology = 'https://data.bioontology.org/ontologies/BRO' @@ -24,12 +25,13 @@ def test_purl_owl 'https://data.bioontology.org/ontologies/BRO' ) refute_nil cls + expected_purl = "#{@@purl_prefix}/BRO?conceptid=http%3A%2F%2Fbioontology.org%2Fontologies%2FActivity.owl%23Activity" + assert_equal expected_purl, cls.purl res = fetch_response(cls.purl) - assert_equal 200, res.status - assert_equal 'https://bioportal.bioontology.org/ontologies/BRO'\ - '?p=classes&conceptid=http%3A%2F%2Fbioontology.org%2Fontologies%2FActivity.owl%23Activity', - res.env[:url].to_s + assert_equal 302, res.status + assert_equal 'https://bioportal.bioontology.org/ontologies/BRO/classes?conceptid=http%3A%2F%2Fbioontology.org%2Fontologies%2FActivity.owl%23Activity', + res.headers['location'] end # Test PURL generation for a class in a UMLS format ontology @@ -40,10 +42,13 @@ def test_purl_umls ) refute_nil cls + # The ID already contains the PURL host, so .purl should return it as-is + assert_equal cls.id, cls.purl + res = fetch_response(cls.purl) - assert_equal 200, res.status - assert_equal 'https://bioportal.bioontology.org/ontologies/SNOMEDCT?p=classes&conceptid=64572001', - res.env[:url].to_s + assert_equal 302, res.status + assert_equal 'https://bioportal.bioontology.org/ontologies/SNOMEDCT/classes/64572001', + res.headers['location'] end # Test PURL generation for a class in an OBO format ontology @@ -54,20 +59,20 @@ def test_purl_obo ) refute_nil cls + expected_purl = "#{@@purl_prefix}/DOID?conceptid=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FDOID_4" + assert_equal expected_purl, cls.purl + res = fetch_response(cls.purl) - assert_equal 200, res.status - assert_equal 'https://bioportal.bioontology.org/ontologies/DOID'\ - '?p=classes&conceptid=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FDOID_4', - res.env[:url].to_s + assert_equal 302, res.status + assert_equal 'https://bioportal.bioontology.org/ontologies/DOID/classes?conceptid=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FDOID_4', + res.headers['location'] end private def fetch_response(url) - conn = Faraday.new do |f| - f.response :follow_redirects + Faraday.new do |f| f.adapter Faraday.default_adapter - end - conn.get(url) + end.get(url) end end