From e401af2552c542a44f2eaf8352933ee9f8973adb Mon Sep 17 00:00:00 2001 From: Alex Skrenchuk Date: Wed, 22 Apr 2026 23:04:56 -0700 Subject: [PATCH] Fix nil @submission in OntologyProcessor when metadata extraction bails SubmissionMetadataExtractor#extract_metadata used a bare `return` when the submission failed validation, returning nil. OntologyProcessor assigned that nil back over its own @submission, so the ensure-block call to notify_submission_processed raised NoMethodError on nil.archived? -- which its inner rescue logged as the misleading "Email sending failed: undefined method `archived?' for nil:NilClass". - submission_extract_metadata.rb: return @submission on the invalid path so the method has a consistent return value. - submission_processor.rb: stop reassigning @submission from the extract_metadata return value; the extractor mutates the shared instance in place via @submission.save. - submission_processor.rb: guard notify_submission_processed against a nil @submission so a missing submission can't surface as the misleading "Email sending failed" log line. - Add regression test reproducing the full path. --- .../operations/submission_extract_metadata.rb | 2 +- .../submission_processor.rb | 4 +- test/services/test_submission_processor.rb | 56 +++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 test/services/test_submission_processor.rb diff --git a/lib/ontologies_linked_data/services/submission_process/operations/submission_extract_metadata.rb b/lib/ontologies_linked_data/services/submission_process/operations/submission_extract_metadata.rb index c7c57590..a029db5d 100644 --- a/lib/ontologies_linked_data/services/submission_process/operations/submission_extract_metadata.rb +++ b/lib/ontologies_linked_data/services/submission_process/operations/submission_extract_metadata.rb @@ -14,7 +14,7 @@ def extract_metadata(logger = nil, user_params, heavy_extraction: true) unless @submission.valid? logger.error("Cannot extract metadata from #{@submission.id} because the submission is invalid") - return + return @submission end ontology_iri = extract_ontology_iri diff --git a/lib/ontologies_linked_data/services/submission_process/submission_processor.rb b/lib/ontologies_linked_data/services/submission_process/submission_processor.rb index 1045aada..9edeb698 100644 --- a/lib/ontologies_linked_data/services/submission_process/submission_processor.rb +++ b/lib/ontologies_linked_data/services/submission_process/submission_processor.rb @@ -38,7 +38,7 @@ def process_submission(logger, options = {}) parsed = @submission.ready?(status: %i[rdf]) - @submission = @submission.extract_metadata(logger, user_params: options[:params], heavy_extraction: extract_metadata?(options)) + @submission.extract_metadata(logger, user_params: options[:params], heavy_extraction: extract_metadata?(options)) @submission.generate_missing_labels(logger) if generate_missing_labels?(options) @@ -70,6 +70,8 @@ def process_submission(logger, options = {}) end def notify_submission_processed(logger) + return if @submission.nil? + LinkedData::Utils::Notifications.submission_processed(@submission) unless @submission.archived? rescue StandardError => e logger.error("Email sending failed: #{e.message}\n#{e.backtrace.join("\n\t")}"); logger.flush diff --git a/test/services/test_submission_processor.rb b/test/services/test_submission_processor.rb new file mode 100644 index 00000000..5a013aa5 --- /dev/null +++ b/test/services/test_submission_processor.rb @@ -0,0 +1,56 @@ +require_relative '../test_case' + +require 'logger' +require 'mocha/minitest' +require 'stringio' + +class TestSubmissionProcessor < LinkedData::TestCase + + def self.before_suite + LinkedData::TestCase.backend_4s_delete + _count, _acronyms, onts = LinkedData::SampleData::Ontology.create_ontologies_and_submissions( + ont_count: 1, submission_count: 1, acronym: 'PROCTEST', process_submission: false + ) + @@ont = onts.first + end + + def self.after_suite + @@ont&.delete + LinkedData::TestCase.backend_4s_delete + end + + # Regression test for: + # "Email sending failed: undefined method `archived?' for nil:NilClass" + # + # When SubmissionMetadataExtractor#extract_metadata hit the `unless @submission.valid?` + # branch it used a bare `return` (returns nil). OntologyProcessor#process_submission + # reassigned @submission to that nil, and the ensure-block call to + # notify_submission_processed then raised NoMethodError on nil.archived?, which its + # inner rescue logged as the misleading "Email sending failed" line above. + def test_processor_survives_extract_metadata_returning_nil + log_io = StringIO.new + logger = Logger.new(log_io) + + submission = @@ont.latest_submission(status: :any) + submission.bring_remaining + + # Simulate the pre-fix extractor behavior on an invalid submission. + submission.stubs(:extract_metadata).returns(nil) + + # Disable every other step so the test isolates the extract_metadata → notify path. + options = { + process_rdf: false, generate_missing_labels: false, generate_obsolete_classes: false, + index_search: false, index_properties: false, index_all_data: false, + run_metrics: false, diff: false, archive: false + } + + begin + submission.process_submission(logger, options) + rescue NoMethodError => e + flunk "processor raised NoMethodError because @submission was overwritten with nil: #{e.message}" + end + + refute_match(/Email sending failed/, log_io.string, + 'notify_submission_processed logged a misleading "Email sending failed" on a nil submission') + end +end