From 1ab798ec1b7ddbdeeb9e8b502e774a59231fc73c Mon Sep 17 00:00:00 2001 From: Renee LeBeau Date: Thu, 31 Jul 2025 11:26:52 -0400 Subject: [PATCH] IUS-2613 Deepblue services additional unit tests --- .../deleted_works_log_reporter_spec.rb | 127 ++++++++ .../ingest_fixity_log_reporter_spec.rb | 119 +++++++ spec/services/deepblue/log_exporter_spec.rb | 90 +++++- spec/services/deepblue/log_extracter_spec.rb | 52 +++ spec/services/deepblue/log_reader_spec.rb | 296 +++++++++++++++++- spec/services/deepblue/log_reporter_spec.rb | 32 +- .../deepblue/provenance_log_service_spec.rb | 199 ++++++++++++ .../services/deepblue/provenance_path_spec.rb | 100 ++++++ .../deepblue/publication_log_reporter_spec.rb | 134 ++++++++ 9 files changed, 1122 insertions(+), 27 deletions(-) create mode 100644 spec/services/deepblue/deleted_works_log_reporter_spec.rb create mode 100644 spec/services/deepblue/ingest_fixity_log_reporter_spec.rb create mode 100644 spec/services/deepblue/log_extracter_spec.rb create mode 100644 spec/services/deepblue/provenance_log_service_spec.rb create mode 100644 spec/services/deepblue/provenance_path_spec.rb create mode 100644 spec/services/deepblue/publication_log_reporter_spec.rb diff --git a/spec/services/deepblue/deleted_works_log_reporter_spec.rb b/spec/services/deepblue/deleted_works_log_reporter_spec.rb new file mode 100644 index 00000000..506ba69f --- /dev/null +++ b/spec/services/deepblue/deleted_works_log_reporter_spec.rb @@ -0,0 +1,127 @@ +require 'rails_helper' + + +describe Deepblue::DeletedWorksLogReporter do + + subject { described_class.new( input: "input" ) } + + + describe "#initialize" do + it "calls super" do + expect(Deepblue::EventLogFilter).to receive(:new) + Deepblue::DeletedWorksLogReporter::DeletedLogFilter.new options: {"optional" => "true"} + end + + skip "Add a test that includes initialize parameters" + end + + + describe "#initialize" do + context "when DeletedLogFilter is blank and DataSetLogFilter is blank" do + it "calls super, calls new on DeletedLogFilter and DataSetLogFilter" do + expect(Deepblue::LogReporter).to receive(:new).with(filter: "filter", input: "stuff", options: {}) + Deepblue::DeletedWorksLogReporter.new(filter: "filter", input: "stuff", options: {}) + end + end + + skip "Add a test where DeletedLogFilter and DataSetLogFilter are not blank" + end + + + describe "#report" do + + before { + allow(subject).to receive(:run) + allow(subject).to receive(:deleted_ids).and_return ["alpha"] + allow(subject).to receive(:deleted_id_to_key_values_map).and_return( + {"alpha" => {"timestamp" => "stamping time", "authoremail" => "auteur email", "event_note" => "eventful", "creator" => ["artisan", "artiste"]}}) + allow(subject).to receive(:puts).with("id,deleted,event_note,url,authoremail,creator") + allow(subject).to receive(:puts).with("\"alpha\",stamping time,eventful,https://deepbluedata.lib.umich.edu/provenance_log/alpha,auteur email,\"artisan;artiste\"") + } + + context "when verbose" do + before { + allow(subject).to receive(:verbose).and_return true + allow(subject).to receive(:timestamp_first).and_return "first time" + allow(subject).to receive(:timestamp_last).and_return "last time" + allow(subject).to receive(:puts).with("timestamp_first = first time") + allow(subject).to receive(:puts).with("timestamp_last = last time") + + allow(subject).to receive(:puts).with("deleted_ids.size = 1") + } + it "calls run and calls puts five times" do + expect(subject).to receive(:run) + expect(subject).to receive(:puts).with("timestamp_first = first time") + expect(subject).to receive(:puts).with("timestamp_last = last time") + expect(subject).to receive(:puts).with("deleted_ids.size = 1") + expect(subject).to receive(:puts).with("id,deleted,event_note,url,authoremail,creator") + expect(subject).to receive(:puts).with("\"alpha\",stamping time,eventful,https://deepbluedata.lib.umich.edu/provenance_log/alpha,auteur email,\"artisan;artiste\"") + + subject.report + end + end + + context "when not verbose" do + before { + allow(subject).to receive(:verbose).and_return false + } + it "calls run and calls puts twice" do + expect(subject).to receive(:run) + expect(subject).to receive(:puts).with("id,deleted,event_note,url,authoremail,creator") + expect(subject).to receive(:puts).with("\"alpha\",stamping time,eventful,https://deepbluedata.lib.umich.edu/provenance_log/alpha,auteur email,\"artisan;artiste\"") + + subject.report + end + end + end + + + # protected methods + + describe "#initialize_report_values" do + it "sets instance variables" do + subject.send(:initialize_report_values) + + #testing super method + subject.instance_variable_get(:@lines_reported) == 0 + subject.instance_variable_get(:@timestamp_first).blank? + subject.instance_variable_get(:@timestamp_last).blank? + subject.instance_variable_get(:@events).empty? + subject.instance_variable_get(:@class_events).empty? + subject.instance_variable_get(:@ids).empty? + + subject.instance_variable_get(:@deleted_ids).empty? + subject.instance_variable_get(:@deleted_id_to_key_values_map).empty? + end + end + + + describe "#line_read" do + before { + subject.instance_variable_set(:@lines_reported, 0) + subject.instance_variable_set(:@ids, {}) + subject.instance_variable_set(:@events, {"event" => 3}) + subject.instance_variable_set(:@class_events, {"class event key" => 7}) + allow(subject).to receive(:class_event_key).with(class_name: "classy name", event: "event").and_return "class event key" + + subject.instance_variable_set(:@deleted_ids, ["previous ID"]) + subject.instance_variable_set(:@deleted_id_to_key_values_map, {}) + allow(Deepblue::ProvenanceHelper).to receive(:parse_log_line_key_values).with("raw key values").and_return "key values" + } + it "sets and updates instance variables" do + #testing super method + subject.instance_variable_get(:@lines_reported) == 1 + subject.instance_variable_get(:@timestamp_first) == "time to stamp" + subject.instance_variable_get(:@timestamp_last) == "time to stamp" + subject.instance_variable_get(:@ids)["ID"] == true + subject.instance_variable_get(:@events)["event"] == 4 + subject.instance_variable_get(:@class_events)["class event key"] == 8 + + subject.instance_variable_get(:@deleted_ids) == ["previous ID","ID"] + subject.instance_variable_get(:@deleted_id_to_key_values_map)["ID"] == "key values" + + subject.send(:line_read, "line", "time to stamp", "event", "event note", "classy name", "ID", "raw key values") + end + end + +end diff --git a/spec/services/deepblue/ingest_fixity_log_reporter_spec.rb b/spec/services/deepblue/ingest_fixity_log_reporter_spec.rb new file mode 100644 index 00000000..ea502450 --- /dev/null +++ b/spec/services/deepblue/ingest_fixity_log_reporter_spec.rb @@ -0,0 +1,119 @@ +require 'rails_helper' + + +describe Deepblue::IngestFixityLogReporter do + + subject { described_class.new( input: "stuff" ) } + + describe "#initialize" do + context "when filter is not present" do + before { + allow(Deepblue::LogReporter).to receive(:new).with(filter: "filtration", input: "input", options: {}) + } + it "calls super" do + expect(Deepblue::LogReporter).to receive(:new).with(filter: "filtration", input: "input", options: {}) + + Deepblue::IngestFixityLogReporter.new(filter: "filtration", input: "input", options: {}) + end + + skip "test with Deepblue::FixityCheckLogFilter" + end + + context "when filter is present" do + it "calls super and filter_and" do + skip "Add a test" + end + end + end + + + describe "#report" do + before { + allow(subject).to receive(:run) + + allow(subject).to receive(:timestamp_first).and_return "first time" + allow(subject).to receive(:timestamp_last).and_return "last time" + allow(subject).to receive(:fixity_check_passed_id).and_return ["crocus", "daffodil", "snowdrop"] + allow(subject).to receive(:fixity_check_failed_id).and_return ["maple", "butterscotch", "caramel", "molasses"] + + allow(subject).to receive(:puts).with("timestamp_first = first time") + allow(subject).to receive(:puts).with("timestamp_last = last time") + allow(subject).to receive(:puts).with("fixity_check_passed_count = 3") + allow(subject).to receive(:puts).with("fixity_check_failed_count = 4") + } + it "calls run and calls puts four times" do + expect(subject).to receive(:run) + expect(subject).to receive(:puts).with("timestamp_first = first time") + expect(subject).to receive(:puts).with("timestamp_last = last time") + expect(subject).to receive(:puts).with("fixity_check_passed_count = 3") + expect(subject).to receive(:puts).with("fixity_check_failed_count = 4") + subject.report + end + end + + + # protected methods + + describe "#initialize_report_values" do + it "calls super and sets instance variables" do + subject.send(:initialize_report_values) + + #testing super method + subject.instance_variable_get(:@lines_reported) == 0 + subject.instance_variable_get(:@timestamp_first).blank? + subject.instance_variable_get(:@timestamp_last).blank? + subject.instance_variable_get(:@events).empty? + subject.instance_variable_get(:@class_events).empty? + subject.instance_variable_get(:@ids).empty? + + subject.instance_variable_get(:@fixity_check_failed_id).empty? + subject.instance_variable_get(:@fixity_check_passed_id).empty? + end + end + + + describe "#line_read" do + before { + subject.instance_variable_set(:@lines_reported, 13) + subject.instance_variable_set(:@timestamp_first, "earlier stamp time") + subject.instance_variable_set(:@ids, {}) + subject.instance_variable_set(:@events, {"event" => 3}) + subject.instance_variable_set(:@class_events, {"class event key" => 7}) + allow(subject).to receive(:class_event_key).with(class_name: "classy name", event: "event").and_return "class event key" + subject.instance_variable_set(:@fixity_check_failed_id, ["once ID"]) + subject.instance_variable_set(:@fixity_check_passed_id, ["old ID"]) + } + + context "on success" do + it "sets and updates instance variables including @fixity_check_passed_id" do + #testing super method + subject.instance_variable_get(:@lines_reported) == 14 + subject.instance_variable_get(:@timestamp_first) == "earlier stamp time" + subject.instance_variable_get(:@timestamp_last) == "time to stamp" + subject.instance_variable_get(:@ids)["ID"] == true + subject.instance_variable_get(:@events)["event"] == 4 + subject.instance_variable_get(:@class_events)["class event key"] == 8 + + subject.instance_variable_get(:@fixity_check_passed_id) == ["old ID","ID"] + + subject.send(:line_read, "line", "time to stamp", "event", "success", "classy name", "ID", "raw key values") + end + end + + context "when not success" do + it "sets and updates instance variables including @fixity_check_failed_id" do + #testing super method + subject.instance_variable_get(:@lines_reported) == 14 + subject.instance_variable_get(:@timestamp_first) == "earlier stamp time" + subject.instance_variable_get(:@timestamp_last) == "time to stamp" + subject.instance_variable_get(:@ids)["ID"] == true + subject.instance_variable_get(:@events)["event"] == 4 + subject.instance_variable_get(:@class_events)["class event key"] == 8 + + subject.instance_variable_get(:@fixity_check_failed_id) == ["once ID","ID"] + + subject.send(:line_read, "line", "time to stamp", "event", "event note", "classy name", "ID", "raw key values") + end + end + end +end \ No newline at end of file diff --git a/spec/services/deepblue/log_exporter_spec.rb b/spec/services/deepblue/log_exporter_spec.rb index 30e9ab3d..4fb466ca 100644 --- a/spec/services/deepblue/log_exporter_spec.rb +++ b/spec/services/deepblue/log_exporter_spec.rb @@ -5,6 +5,12 @@ class OutputMock def puts (text) text end + + def flush + end + + def close + end end RSpec.describe Deepblue::LogExporter do @@ -48,12 +54,14 @@ def puts (text) end context "when pp_export is equivalent to false" do + mockoutput = OutputMock.new before { allow(subject).to receive(:pp_export).and_return false + subject.instance_variable_set(:@output, mockoutput) } it "calls @output.puts" do - expect(subject.export_line"line", "timestamp", "event", "event_note", "class_name", "id", "raw") - .to eq "line" + expect(mockoutput).to receive(:puts).with "line" + subject.export_line "line", "timestamp", "event", "event_note", "class_name", "id", "raw" end end end @@ -149,4 +157,82 @@ def puts (text) end end + + # protected methods + + describe "#log_close_output" do + context "when @output_close is false" do + it "returns nil" do + expect(subject.send(:log_close_output)).to be_blank + end + end + + context "when @output_close is true" do + out_put = OutputMock.new + before { + subject.instance_variable_set(:@output_close, true) + } + + context "when @output is nil" do + before { + subject.instance_variable_set(:@output, nil) + } + it "nothing happens" do + expect(out_put).not_to receive(:flush) + expect(out_put).not_to receive(:close) + subject.send(:log_close_output) + end + end + context "when @output is not nil" do + before { + subject.instance_variable_set(:@output, out_put) + } + it "calls flush and close on @output" do + expect(out_put).to receive(:flush) + expect(out_put).to receive(:close) + subject.send(:log_close_output) + end + end + end + end + + + describe "#log_open_output" do + before { + allow(subject).to receive(:output_mode).and_return "output mode" + } + + context "when @output is a string" do + before { + subject.instance_variable_set(:@output, "things") + allow(Pathname).to receive(:new).with("things").and_return "string output pathname" + allow(subject).to receive(:open).with("string output pathname", "output mode").and_return "string output" + } + it "creates Pathname from string" do + subject.send(:log_open_output) + + expect(subject.instance_variable_get(:@output_pathname)).to eq "string output pathname" + expect(subject.instance_variable_get(:@output)).to eq "string output" + end + end + + context "when @output is a Pathname" do + path_name = Pathname.new("path name") + before { + subject.instance_variable_set(:@output, path_name) + allow(subject).to receive(:open).with(path_name, "output mode").and_return "pathname output" + } + it "uses Pathname" do + subject.send(:log_open_output) + + expect(subject.instance_variable_get(:@output_pathname)).to eq path_name + expect(subject.instance_variable_get(:@output)).to eq "pathname output" + end + end + + after { + expect(subject.instance_variable_get(:@output_close)).to eq true + } + end + end diff --git a/spec/services/deepblue/log_extracter_spec.rb b/spec/services/deepblue/log_extracter_spec.rb new file mode 100644 index 00000000..c58dbaa7 --- /dev/null +++ b/spec/services/deepblue/log_extracter_spec.rb @@ -0,0 +1,52 @@ +require 'rails_helper' + + +describe Deepblue::LogExtracter do + + subject { described_class.new( input: "some musings" ) } + + describe "#initialize" do + it "sets instance variables" do + log_extracter = Deepblue::LogExtracter.new(filter: "good filtration", input: "considerations", extract_parsed_tuple: true, options: { "omens" => "good" }) + + log_extracter.instance_variable_get(:@extract_parsed_tuple) == true + log_extracter.instance_variable_get(:@lines_extracted).empty? == true + end + + skip "Add a test for call to Deepblue::LogReader" + end + + + describe "#extract_line" do + context "when @extract_parsed_tuple is true" do + before { + subject.instance_variable_set(:@extract_parsed_tuple, true) + } + it "appends parameters to @lines_extracted" do + subject.extract_line "extract line", "time stamp", "eventful", "noted!", "classical", "ID_", "raw values" + subject.instance_variable_get(:@lines_extracted) == ["extract line", "time stamp", "eventful", "noted!", "classical", "ID_", "raw values"] + end + end + + context "when @extract_parsed_tuple is false" do + before { + subject.instance_variable_set(:@extract_parsed_tuple, false) + } + it "appends line parameter to @lines_extracted" do + subject.extract_line "e line!", "time stamp", "eventful", "noted!", "classical", "ID_", "raw values" + subject.instance_variable_get(:@lines_extracted) == "e line!" + end + end + end + + + describe "#run" do + it "calls readlines" do + expect(subject).to receive(:readlines) + subject.run + end + + skip "Add a test that includes extract_line and parameters" + end + +end \ No newline at end of file diff --git a/spec/services/deepblue/log_reader_spec.rb b/spec/services/deepblue/log_reader_spec.rb index d563eba6..f3491134 100644 --- a/spec/services/deepblue/log_reader_spec.rb +++ b/spec/services/deepblue/log_reader_spec.rb @@ -22,6 +22,40 @@ def or (new_filters: ) end end +class MockInputFile + + def initialize() + @eof = true + end + def eof? + @eof = !@eof + end + + def readline + "Read this line here!?" + end + + def close + end +end + + +class MockInputFilter + + def initialize(next_line) + @next_line = next_line + end + + def filter_in(parsed_timestamp, + parsed_event, + parsed_event_note, + parsed_class_name, + parsed_id, + parsed_raw_key_values) + @next_line + end +end + RSpec.describe Deepblue::LogReader do let( :initial_filter ) { MockLogFilter.new all_log_filter: true} @@ -54,12 +88,12 @@ def or (new_filters: ) describe "#initialize_filter" do context "when filter is blank" do before { - allow(Deepblue::AllLogFilter).to receive(:new) + allow(Deepblue::AllLogFilter).to receive(:new).and_return "all log filter" } it "calls AllLogFilter.new" do expect(Deepblue::AllLogFilter).to receive(:new) - expect(subject.initialize_filter nil).to be_blank + expect(subject.initialize_filter nil).to eq "all log filter" end end @@ -75,7 +109,7 @@ def or (new_filters: ) end context "when filter is not an array and not blank" do - it "returns filter" do + it "returns filter argument" do expect(subject.initialize_filter "condensation").to eq "condensation" end end @@ -239,17 +273,32 @@ def or (new_filters: ) end end - describe "#input_mode" do + + describe "#input mode" do before { - allow(subject).to receive(:option).with(key: 'input_mode', default_value: 'r').and_return ("trail mix") + allow(subject).to receive(:option).with(key: 'input_mode', default_value: "r").and_return "substantial" } - it "calls option function" do - expect(subject).to receive(:option).with(key: 'input_mode', default_value: 'r') + context "when instance variable has a value" do + before { + subject.instance_variable_set(:@input_mode, "optionally") + } + it "returns instance variable" do + expect(subject).not_to receive(:option) + expect(subject.input_mode).to eq "optionally" + subject.instance_variable_get(:@input_mode) == "optionally" + end + end - expect(subject.input_mode).to eq "trail mix" + context "when instance variable does not have a value" do + it "calls option function" do + expect(subject).to receive(:option) + expect(subject.input_mode).to eq "substantial" + subject.instance_variable_get(:@input_mode) == "substantial" + end end end + describe "#parse_line" do context "when @current_line is blank" do @@ -309,6 +358,235 @@ def or (new_filters: ) end end - pending "#readlines" + + describe "#readlines" do + before { + subject.instance_variable_set(:@lines_parsed, "default") + subject.instance_variable_set(:@current_line, "default") + + subject.instance_variable_set(:@parsed_timestamp, "Time Stamp") + subject.instance_variable_set(:@parsed_event, "Event Name") + subject.instance_variable_set(:@parsed_event_note, "Event Note") + subject.instance_variable_set(:@parsed_class_name, "Class Name") + subject.instance_variable_set(:@parsed_id, "ID#") + subject.instance_variable_set(:@parsed_raw_key_values, "raw key values...") + + allow(subject).to receive(:log_open_input) + allow(subject).to receive(:log_close_input) + } + + context "when no block provided and input at end of file" do + before { + subject.instance_variable_set(:@lines_read, "default") + subject.instance_variable_set(:@input, OpenStruct.new(eof?: true)) + + allow(subject).to receive(:filter) + } + it "sets instance variables to zero or blank" do + subject.readlines + + subject.instance_variable_get(:@lines_parsed) == 0 + subject.instance_variable_get(:@lines_read) == 0 + subject.instance_variable_get(:@current_line).blank? == true + end + end + + context "when input provided" do + before { + subject.instance_variable_set(:@lines_read, 0) + allow(subject).to receive(:parse_line) + } + + context "when @parsed is false" do + before { + subject.instance_variable_set(:@parsed, false) + subject.instance_variable_set(:@input, MockInputFile.new) + allow(subject).to receive(:filter) + } + + it "calls parse_line" do + subject.readlines + end + end + + context "when @parsed is true" do + before { + subject.instance_variable_set(:@parsed, true) + subject.instance_variable_set(:@input, MockInputFile.new) + } + + context "when filter.filter_in returns false" do + mock_filter = MockInputFilter.new(false) + before { + allow(subject).to receive(:filter).and_return mock_filter + } + it "calls parse_line and filter_in" do + expect(mock_filter).to receive(:filter_in).with("Time Stamp", "Event Name", "Event Note", "Class Name", "ID#", "raw key values...") + + subject.readlines + end + + specify { expect { |b| subject.readlines(&b) }.not_to yield_control } # method does not reach block + end + + context "when filter.filter_in returns true" do + filter_mock = MockInputFilter.new(true) + before { + allow(subject).to receive(:filter).and_return filter_mock + } + it "calls parse_line and filter_in" do + expect(filter_mock).to receive(:filter_in).with("Time Stamp", "Event Name", "Event Note", "Class Name", "ID#", "raw key values...") + + subject.readlines + end + + specify { expect { |b| subject.readlines(&b) }.to yield_with_args } # method reaches block which yields with arguments + end + end + + after { + expect(subject).to have_received(:parse_line) + + subject.instance_variable_get(:@current_line) == "Read this line here!" + subject.instance_variable_get(:@lines_read) == 1 + } + end + + after { + expect(subject).to have_received(:log_open_input) + expect(subject).to have_received(:log_close_input) + } + end + + + # protected methods + + describe "#log_close_input" do + close_input = MockInputFile.new + before { + subject.instance_variable_set(:@input, close_input) + } + + context "when @input_close is false" do + before { + subject.instance_variable_set(:@input_close, false) + } + it "does not call close on @input" do + expect(close_input).not_to receive(:close) + subject.send(:log_close_input) + end + end + + context "when @input_close is true and @input has a value" do + before { + subject.instance_variable_set(:@input_close, true) + } + it "calls close on @input" do + expect(close_input).to receive(:close) + subject.send(:log_close_input) + end + end + end + + + describe "#log_open_input" do + path_name = Pathname.new("/tmp") + + context "when @input is a string file location that exists" do + before { + subject.instance_variable_set(:@input, "/tmp") + allow(subject).to receive(:open).with(path_name, 'r').and_return "string pathname" + } + it "creates Pathname with string and opens it, sets instance variables" do + expect(subject).to receive(:open).with(path_name, 'r') + subject.send(:log_open_input) + + subject.instance_variable_get(:@input) == "string pathname" + subject.instance_variable_get(:@input_close) == true + end + end + + context "when @input is a Pathname that exists" do + before { + subject.instance_variable_set(:@input, path_name) + allow(subject).to receive(:open).with(path_name, 'r').and_return "original pathname" + } + it "opens Pathname and sets instance variables" do + expect(subject).to receive(:open).with(path_name, 'r') + subject.send(:log_open_input) + + subject.instance_variable_get(:@input) == "original pathname" + subject.instance_variable_get(:@input_close) == true + end + end + + context "when @input Pathname does not exist" do + before { + subject.instance_variable_set(:@input, "message") + } + it "does not open pathname or set instance variables" do + expect(subject).not_to receive(:open) + subject.send(:log_open_input) + + subject.instance_variable_get(:@input).blank? == true + subject.instance_variable_get(:@input_close).blank? == true + end + end + end + + + describe "#option" do + context "when key is not an option" do + before { + allow(subject).to receive(:options_key?).with("platinum").and_return false + } + it "returns default value" do + expect(subject.send(:option, key: "platinum", default_value: "nickel")).to eq "nickel" + end + end + + context "when key is an option" do + before { + allow(subject).to receive(:options_key?).with("silver").and_return true + allow(subject).to receive(:options_key?).with(:silver).and_return true + allow(subject).to receive(:options_key?).with("gold").and_return true + allow(subject).to receive(:options_key?).with(["copper"]).and_return true + + subject.instance_variable_set(:@options, { "silver" => "treasure chest", :gold => "fort knox" }) + } + it "returns @options key value" do + expect(subject.send(:option, key: "silver", default_value: "tin")).to eq "treasure chest" + expect(subject.send(:option, key: :silver, default_value: "tin")).to eq "treasure chest" + expect(subject.send(:option, key: "gold", default_value: "brass")).to eq "fort knox" + end + + it "returns default value if key is not a string or a symbol" do + expect(subject.send(:option, key: ["copper"], default_value: "bronze")).to eq "bronze" + end + end + end + + + describe "#options_key?" do + before { + subject.instance_variable_set(:@options, { "apple" => "honeycrisp", :orange => "blood" }) + } + it "returns true if key is present" do + expect(subject.send(:options_key?, "apple")).to eq true + end + + it "returns true if key is present as a symbol but entered as a string" do + expect(subject.send(:options_key?, "orange")).to eq true + end + + it "returns true if key is present as a string but entered as a symbol" do + expect(subject.send(:options_key?, :apple)).to eq true + end + + it "returns false if key is absent" do + expect(subject.send(:options_key?, "pear")).to eq false + end + + end end diff --git a/spec/services/deepblue/log_reporter_spec.rb b/spec/services/deepblue/log_reporter_spec.rb index 817d199f..26952005 100644 --- a/spec/services/deepblue/log_reporter_spec.rb +++ b/spec/services/deepblue/log_reporter_spec.rb @@ -4,23 +4,13 @@ subject { described_class.new(filter: "filter", input: "input", options: {"blue" => "gold"} ) } describe "#initialize" do - it "initializes instance variables" do - # called by initialize in parent class - subject.instance_variable_get(:@filter) == "filter" - subject.instance_variable_get(:@input) == "input" - subject.instance_variable_get(:@options) == {"blue" => "gold"} - subject.instance_variable_get(:@verbose) == false - subject.instance_variable_get(:@verbose_filter) == false + it "calls super and instantiates variables" do + expect(Deepblue::LogReader).to receive(:new).with(filter: "", input: "stuff", options: {}) + log_reporter = Deepblue::LogReporter.new(filter: "", input: "stuff", options: {}) - subject.instance_variable_get(:@output_close) == false - subject.instance_variable_get(:@output_mode) == 'w' - subject.instance_variable_get(:@output_pathname).nil? == true - end - - it "super calls add_date_range_filter" do - allow(Deepblue::LogReader).to receive(:new) - Deepblue::LogReporter.new(filter: nil, input:"input", options: {}) - expect(Deepblue::LogReader).to have_received(:new) + log_reporter.instance_variable_get(:@output_close) == false + log_reporter.instance_variable_get(:@output_mode) == "w" + log_reporter.instance_variable_get(:@output_pathname).blank? end end @@ -65,4 +55,14 @@ end end + + # protected methods + + describe "class_event_keys" do + it "returns text" do + expect(subject.send(:class_event_key, class_name: "Classy", event: "Eventually")).to eq "Classy_Eventually" + end + end + + # initialize_report_values and line_read tested in deleted_works_log_reporter_spec.rb and ingest_fixity_log_reporter_spec.rb end \ No newline at end of file diff --git a/spec/services/deepblue/provenance_log_service_spec.rb b/spec/services/deepblue/provenance_log_service_spec.rb new file mode 100644 index 00000000..73538bba --- /dev/null +++ b/spec/services/deepblue/provenance_log_service_spec.rb @@ -0,0 +1,199 @@ +require 'rails_helper' + +class Mockline + + def initialize(eof, line) + @eof = eof + @line = line + end + + def readline + @line + end + + def eof? + @eof + end +end + + + + +describe Deepblue::ProvenanceLogService do + + pending "#self.provenance_log_name" + + pending "#self.provenance_log_path" + + describe "#self.entries" do + before { + allow(Deepblue::ProvenancePath).to receive(:path_for_reference).with("Q-3000").and_return "Q-3000.txt" + allow(Deepblue::ProvenanceLogService).to receive(:read_entries).with("Q-3000.txt").and_return ["read entries"] + allow(Deepblue::ProvenanceLogService).to receive(:filter_entries).with("Q-3000").and_return ["filter", "entries"] + allow(Deepblue::ProvenanceLogService).to receive(:write_entries).with("Q-3000.txt", ["filter", "entries"]) + } + + context "when refresh is false and File exists" do + before { + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with "ProvenanceLogService.entries( Q-3000, false )" + allow(File).to receive(:exist?).with("Q-3000.txt").and_return true + } + it "calls read_entries" do + expect(File).to receive(:exist?).with("Q-3000.txt").and_return true + expect(Deepblue::ProvenanceLogService).to receive(:read_entries).with("Q-3000.txt").and_return ["read entries"] + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with "ProvenanceLogService.entries( Q-3000 ) read 1 entries" + + expect(Deepblue::ProvenanceLogService.entries("Q-3000", refresh: false)).to eq ["read entries"] + end + end + + context "when refresh is true" do + before { + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with "ProvenanceLogService.entries( Q-3000, true )" + } + + it "calls filter_entries and write_entries (doesn't check if File exists)" do + expect(Deepblue::ProvenanceLogService).to receive(:filter_entries).with("Q-3000").and_return ["filter", "entries"] + expect(Deepblue::ProvenanceLogService).to receive(:write_entries).with("Q-3000.txt", ["filter", "entries"]) + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with "ProvenanceLogService.entries( Q-3000 ) read 2 entries" + + expect(Deepblue::ProvenanceLogService.entries("Q-3000", refresh: true)).to eq ["filter", "entries"] + end + end + + context "when refresh is false and File does not exist" do + before { + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with "ProvenanceLogService.entries( Q-3000, false )" + allow(File).to receive(:exist?).with("Q-3000.txt").and_return false + } + + it "calls filter_entries and write_entries" do + expect(File).to receive(:exist?).with("Q-3000.txt").and_return false + expect(Deepblue::ProvenanceLogService).to receive(:filter_entries).with("Q-3000").and_return ["filter", "entries"] + expect(Deepblue::ProvenanceLogService).to receive(:write_entries).with("Q-3000.txt", ["filter", "entries"]) + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with "ProvenanceLogService.entries( Q-3000 ) read 2 entries" + + expect(Deepblue::ProvenanceLogService.entries("Q-3000", refresh: false)).to eq ["filter", "entries"] + end + end + end + + + pending "#self.filter_entries" + + + describe "#self.parse_entry" do + context "function returns successfully" do + it "calls Deepblue::ProvenanceHelper.parse_log_line" do + skip "Add a test" + end + end + + context "when Deepblue::ProvenanceHelper.parse_log_line throws an error" do + before { + allow(Deepblue::ProvenanceHelper).to receive(:parse_log_line).with("data entry", line_number: 0, raw_key_values: true) + .and_raise(Deepblue::LogParseError) + + } + it "returns parameters and error message" do + expect(Deepblue::ProvenanceHelper).to receive(:parse_log_line).with("data entry", line_number: 0, raw_key_values: true) + + return_value = Deepblue::ProvenanceLogService.parse_entry("data entry") + expect(return_value[:entry]).to eq "data entry" + expect(return_value[:line_number]).to eq 0 + expect(return_value[:parse_error]).to be_an_instance_of Deepblue::LogParseError + end + end + end + + + describe "#self.pp_key_values" do + before { + allow(JSON).to receive(:parse).with("raw").and_return "JSON parse" + allow(JSON).to receive(:pretty_generate).with("JSON parse").and_return "JSON pretty generate" + } + it "calls JSON.parse and JSON.pretty_generate on parameter" do + expect(Deepblue::ProvenanceLogService.pp_key_values "raw").to eq "JSON pretty generate" + end + end + + + describe "#self.key_values_to_table" do + context "when parse parameter is true" do + before { + allow(JSON).to receive(:parse).with("values").and_return "parsed key values" + } + it "" do + expect(JSON).to receive(:parse).with("values") + expect(Deepblue::ProvenanceLogService.key_values_to_table "values", parse: true).to eq "parsed key values" + end + end + + context "when parse parameter is false" do + + context "when key_values parameter is an array of 0 values" do + it "returns empty html table code" do + expect(JSON).not_to receive(:parse) + expect(Deepblue::ProvenanceLogService.key_values_to_table [], parse: false).to eq "\n\n
 
\n" + end + end + + context "when key_values parameter is an array of 1 value" do + before { + allow(ERB::Util).to receive(:html_escape).with("key value").and_return "escaped key value" + } + it "returns html table of escaped key_value" do + expect(JSON).not_to receive(:parse) + + expect(Deepblue::ProvenanceLogService.key_values_to_table ["key value"], parse: false) + .to eq "\n\n
escaped key value
\n" + end + end + + context "when key_values parameter is an array of more than 1 value" do + before { + allow(ERB::Util).to receive(:html_escape).with("omega").and_return "escaped key value 1" + allow(ERB::Util).to receive(:html_escape).with("zeta").and_return "escaped key value 2" + } + it "returns html table of escaped array values" do + expect(JSON).not_to receive(:parse) + + expect(Deepblue::ProvenanceLogService.key_values_to_table ["omega", "zeta"], parse: false) + .to eq "\n\n\n
escaped key value 1
escaped key value 2
\n" + end + end + + context "when key_values parameter is a hash" do + before { + allow(ERB::Util).to receive(:html_escape).with("alpha").and_return "escaped key 1" + allow(ERB::Util).to receive(:html_escape).with("beta").and_return "escaped value 1" + } + it "returns html table of escaped hash values" do + expect(JSON).not_to receive(:parse) + + expect(Deepblue::ProvenanceLogService.key_values_to_table( {"alpha" => "beta"}, parse: false)) + .to eq "\n\n
escaped key 1escaped value 1
\n" + end + end + + context "when key_values parameter is not an array or a hash (could be a string)" do + before { + allow(ERB::Util).to receive(:html_escape).with("violin").and_return "string instrument" + } + it "returns escaped key_value(s)" do + expect(JSON).not_to receive(:parse) + + expect(Deepblue::ProvenanceLogService.key_values_to_table "violin", parse: false) + .to eq "string instrument" + end + end + end + end + + + pending "#self.read_entries" + + pending "#self.write_entries" + +end + diff --git a/spec/services/deepblue/provenance_path_spec.rb b/spec/services/deepblue/provenance_path_spec.rb new file mode 100644 index 00000000..1e8e0ff9 --- /dev/null +++ b/spec/services/deepblue/provenance_path_spec.rb @@ -0,0 +1,100 @@ +require 'rails_helper' + +describe Deepblue::ProvenancePath do + + subject { described_class.new( "path", "destination" ) } + + pending "#path_for_reference" + + + describe "#initialize" do + context "when object is a string" do + it "sets object and destination_name as instance variables" do + provenance_path = Deepblue::ProvenancePath.new("providence", "Rhode Island") + + expect(provenance_path.instance_variable_get(:@id)).to eq "providence" + expect(provenance_path.instance_variable_get(:@destination_name)).to eq "Rhode Island" + end + end + + context "when object is not a string" do + it "sets object.id and destination_name as instance variables" do + provenance = Deepblue::ProvenancePath.new(OpenStruct.new(id: "providencetown"), "Massachusetts") + + expect(provenance.instance_variable_get(:@id)).to eq "providencetown" + expect(provenance.instance_variable_get(:@destination_name)).to eq "Massachusetts" + end + end + end + + + describe "#provenance_path" do + before{ + allow(subject).to receive(:path_prefix).and_return "path prefix" + allow(subject).to receive(:file_name).and_return "file name" + } + it "returns string" do + expect(subject.provenance_path).to eq "path prefix-file name" + end + end + + + # private methods + + describe "#root_path" do + before { + allow(subject).to receive(:provenance_path).and_return "path" + allow(Pathname).to receive(:new).with("path").and_return OpenStruct.new(dirname: "path dirname") + } + it "returns Pathname dirname of provenance_path" do + expect(subject.send(:root_path)).to eq "path dirname" + end + end + + + describe "#path_prefix" do + before { + allow(Hyrax.config).to receive(:derivatives_path).and_return "derivatives path" + allow(subject).to receive(:pair_path).and_return "pair path" + allow(Pathname).to receive(:new).with("derivatives path").and_return ["derivatives ", " consequences"] + } + it "returns string" do + expect(subject.send(:path_prefix)).to eq "derivatives pair path consequences" + end + end + + + describe "#pair_path" do + it "returns string" do + expect(subject.send(:pair_path)).to eq "pa/th" + end + end + + + describe "#file_name" do + context "when destination_name has a value" do + before { + allow(subject).to receive(:extension).and_return(".mov") + } + it "returns string" do + expect(subject.send(:file_name)).to eq "destination.mov" + end + end + + context "when destination_name has no value or false" do + subject { described_class.new( "path") } + + it "returns blank" do + expect(subject.send(:file_name)).to be_blank + end + end + end + + + describe "#extension" do + it "returns string" do + expect(subject.send(:extension)).to eq ".log" + end + end + +end diff --git a/spec/services/deepblue/publication_log_reporter_spec.rb b/spec/services/deepblue/publication_log_reporter_spec.rb new file mode 100644 index 00000000..17e8c4ff --- /dev/null +++ b/spec/services/deepblue/publication_log_reporter_spec.rb @@ -0,0 +1,134 @@ +require 'rails_helper' + +RSpec.describe Deepblue::PublicationLogReporter do + + describe "#initialize" do + it "calls super" do + expect(Deepblue::EventLogFilter).to receive(:new) #.with(matching_events: ["publish"]) + Deepblue::PublicationLogReporter::PublishedLogFilter.new + end + + skip "Add a test that includes parameters" + end + + + + subject { described_class.new(input: "input") } + + describe "#initialize" do + context "when filter not present" do + it "calls super" do + expect(Deepblue::EventLogFilter).to receive(:new) + Deepblue::PublicationLogReporter.new( input: "word processed", options: { "radical" => "vernacular" }) + end + end + + skip "Add a test for super with parameters" + + context "when filter is present" do + it "calls super and filter_and" do + skip "Sdd a test" + end + end + end + + + describe "#report" do + before { + allow(subject).to receive(:run) + allow(subject).to receive(:timestamp_first).and_return "6/1/2025" + allow(subject).to receive(:timestamp_last).and_return "7/1/2025" + allow(subject).to receive(:published_id).and_return [456] + } + + context "when creator and subject_discipline are strings" do + before { + key_values = { "timestamp" => "6/2/2025", "authoremail" => "unknown@example.edu", "creator" => "the user", "subject_discipline" => "disciplinary subject" } + allow(subject).to receive(:published_id_to_key_values_map).and_return [].insert(456, key_values) + } + it "calls run" do + expect(subject).to receive(:puts).with "timestamp_first = 6/1/2025" + expect(subject).to receive(:puts).with "timestamp_last = 7/1/2025" + expect(subject).to receive(:puts).with "published_id.size = 1" + expect(subject).to receive(:puts).with "id,published,url,authoremail,creator,subject_discipline,primary filetype" + expect(subject).to receive(:puts).with "\"456\",6/2/2025,https://deepbluedata.lib.umich.edu/data/concern/data_sets/456,unknown@example.edu,\"the user\",\"disciplinary subject\"" + + subject.report + end + end + + context "when creator and subject_discipline are arrays" do + before { + key_values = { "timestamp" => "6/2/2025", "authoremail" => "unknown@example.edu", "creator" => ["first user", "last user"], "subject_discipline" => ["subject 1", "subject 2"] } + allow(subject).to receive(:published_id_to_key_values_map).and_return [].insert(456, key_values) + } + it "calls run" do + expect(subject).to receive(:puts).with "timestamp_first = 6/1/2025" + expect(subject).to receive(:puts).with "timestamp_last = 7/1/2025" + expect(subject).to receive(:puts).with "published_id.size = 1" + expect(subject).to receive(:puts).with "id,published,url,authoremail,creator,subject_discipline,primary filetype" + expect(subject).to receive(:puts).with "\"456\",6/2/2025,https://deepbluedata.lib.umich.edu/data/concern/data_sets/456,unknown@example.edu,\"first user;last user\",\"subject 1;subject 2\"" + + subject.report + end + end + + after { + expect(subject).to have_received(:run) + } + end + + + # protected methods + + describe "#initialize_report_values" do + before { + subject.instance_variable_set(:@published_id, [1,2,3]) + subject.instance_variable_set(:@published_id_to_key_values_map, [{ :id => 789, :published => true }]) + } + it "calls super and sets instance variables to empty" do + subject.send(:initialize_report_values) + + # called in super + expect(subject.instance_variable_get(:@lines_reported)).to eq 0 + expect(subject.instance_variable_get(:@timestamp_first)).blank? == true + expect(subject.instance_variable_get(:@timestamp_last)).blank? == true + expect(subject.instance_variable_get(:@events)).to be_empty + expect(subject.instance_variable_get(:@class_events)).to be_empty + expect(subject.instance_variable_get(:@ids)).to be_empty + + expect(subject.instance_variable_get(:@published_id)).to be_empty + expect(subject.instance_variable_get(:@published_id_to_key_values_map)).to be_empty + end + end + + + describe "#line_read" do + before { + subject.instance_variable_set(:@lines_reported, 0) + subject.instance_variable_set(:@events, { "event" => 0 }) + subject.instance_variable_set(:@ids, {}) + allow(subject).to receive(:class_event_key).with(class_name: "class name", event: "event").and_return "class event key" + subject.instance_variable_set(:@class_events, { "class event key" => 0}) + + subject.instance_variable_set(:@published_id, [1,2,3]) + subject.instance_variable_set(:@published_id_to_key_values_map, { }) + allow(Deepblue::ProvenanceHelper).to receive(:parse_log_line_key_values).with("raw").and_return "processed key values" + } + it "sets instance variables" do + subject.send(:line_read, "line", "timestamp", "event", "event note", "class name", 99, "raw") + + # called in super + expect(subject.instance_variable_get(:@lines_reported)).to eq 1 + expect(subject.instance_variable_get(:@timestamp_first)).to eq "timestamp" + expect(subject.instance_variable_get(:@timestamp_last)).to eq "timestamp" + expect(subject.instance_variable_get(:@ids)[99]).to eq true + expect(subject.instance_variable_get(:@events)["event"]).to eq 1 + expect(subject.instance_variable_get(:@class_events)["class event key"]) == 1 + + expect(subject.instance_variable_get(:@published_id)).to eq [1,2,3,99] + expect(subject.instance_variable_get(:@published_id_to_key_values_map)[99]).to eq "processed key values" + end + end + +end