Skip to content

Commit

Permalink
WIP: more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ewlarson committed Sep 25, 2024
1 parent 6c4e868 commit b399feb
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 88 deletions.
196 changes: 109 additions & 87 deletions app/services/uri_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,59 +3,15 @@
require "net/http"
require "net/ftp"

# Abstract base class for representing the results of checking one URI.
class Result
attr_accessor :uri_string

# A new Result object instance.
#
# @param params [Hash] A hash of parameters. Expects :uri_string.
def initialize(params)
@uri_string = params[:uri_string]
end
end

# A Good Result. The URL is valid.
class Good < Result
end

# A Redirect to another URL.
class Redirect < Result
attr_reader :good
attr_reader :final_destination_uri_string

# A new LinkChecker::Redirect object.
#
# @param params [Hash] A hash of parameters. Expects :final_destination_uri_string,
# which is the URL that the original :uri_string redirected to.
def initialize(params)
@final_destination_uri_string = params[:final_destination_uri_string]
@good = params[:good]
super(params)
end
end

# A Error result. The URL is not valid for some reason. Any reason, other than a 200
# HTTP response.
#
# @param params [Hash] A hash of parameters. Expects :error, which is a string
# representing the error.
class Error < Result
attr_reader :error
def initialize(params)
@error = params[:error]
super(params)
end
end

class UriService
def initialize(solr_document_uri)
@uri = solr_document_uri
@metadata = Hash.new
@metadata['solr_doc_id'] = @uri.document_id
@metadata['uri_key'] = @uri.uri_key
@metadata['uri_value'] = @uri.uri_value
@metadata['solr_version'] = @uri.version
@metadata = {
'solr_doc_id' => @uri.document_id,
'uri_key' => @uri.uri_key,
'uri_value' => @uri.uri_value,
'solr_version' => @uri.version
}

@uri.state_machine.transition_to!(:processing, @metadata)

Expand All @@ -68,60 +24,74 @@ def initialize(solr_document_uri)
)
end

# Captures the uri's validity in SolrDocumentUri
# @return [Boolean]
#
# @TODO: EWL
def process
# Gentle hands.
sleep(1)

uri = normalize_uri(@uri.uri_value)

if uri.scheme.start_with?('http')
result = check_uri(uri)
process_http_uri(uri)
elsif uri.scheme.start_with?('ftp')
process_ftp_uri(uri)
else
@uri.state_machine.transition_to!(:failed, @metadata.merge('error' => 'Unsupported URI scheme'))
end

if result.instance_of?(Good)
@uri.state_machine.transition_to!(:succeeded, @metadata)
elsif result.instance_of?(Redirect)
@metadata["final_destination_uri_string"] = result.final_destination_uri_string
@uri.state_machine.transition_to!(:succeeded, @metadata)
else
@uri.state_machine.transition_to!(:failed, @metadata)
end
log_output
rescue => e
@metadata['exception'] = e.inspect
@uri.state_machine.transition_to!(:failed, @metadata)
log_output
end

elsif uri.scheme.start_with?('ftp')
private

Net::FTP.open(uri.host) do |ftp|
ftp.passive = true
ftp.login 'anonymous', 'anonymous@google.com'
def process_http_uri(uri)
result = check_uri(uri)

# Check for file extension
if File.extname(uri.path).size > 0
size = ftp.size(uri.path)
if result.instance_of?(Good) || result.instance_of?(Redirect)
@uri.state_machine.transition_to!(:succeeded, @metadata)
else
@uri.state_machine.transition_to!(:failed, @metadata)
end
end

def process_ftp_uri(uri)
Net::FTP.open(uri.host) do |ftp|
ftp.passive = true
ftp.login 'anonymous', 'anonymous@google.com'

path = uri.path.sub(/^\//, '') # Remove leading slash if present
if File.extname(path).size > 0
begin
size = ftp.size(path)
if size > 0
@uri.state_machine.transition_to!(:succeeded, @metadata)
else
@uri.state_machine.transition_to!(:failed, @metadata.merge('error' => 'File size is 0'))
end
elsif check_ftp_path(ftp, uri.path)
@uri.state_machine.transition_to!(:succeeded, @metadata)
else
@uri.state_machine.transition_to!(:failed, @metadata)
rescue Net::FTPPermError
@uri.state_machine.transition_to!(:failed, @metadata.merge('error' => 'File not found'))
end
else
begin
if check_ftp_path(ftp, path)
@uri.state_machine.transition_to!(:succeeded, @metadata)
else
@uri.state_machine.transition_to!(:failed, @metadata.merge('error' => 'Directory not found'))
end
rescue Net::FTPPermError
@uri.state_machine.transition_to!(:failed, @metadata.merge('error' => 'Directory not found'))
end
end
end
log_output

rescue Exception => invalid
@metadata['exception'] = invalid.inspect
@uri.state_machine.transition_to!(:failed,@metadata)
log_output
rescue Net::FTPPermError, Net::FTPReplyError => e
@uri.state_machine.transition_to!(:failed, @metadata.merge('error' => e.message))
end

def log_output
@metadata["state"] = @uri.state_machine.current_state
@metadata.each do |key,value|
@logger.tagged(@uri.id, key.to_s) { @logger.info value }
end

def check_ftp_path(ftp, path)
ftp.chdir(path)
ftp.pwd == "/#{path}"
end

def check_uri(uri, redirected=false)
Expand Down Expand Up @@ -179,4 +149,56 @@ def check_ftp_path(ftp, path)
def normalize_uri(uri_string)
URI.parse(Addressable::URI.parse(uri_string).normalize.to_s)
end

def log_output
@metadata["state"] = @uri.state_machine.current_state
@metadata.each do |key,value|
@logger.tagged(@uri.id, key.to_s) { @logger.info value }
end
end
end

# Abstract base class for representing the results of checking one URI.
class Result
attr_accessor :uri_string

# A new Result object instance.
#
# @param params [Hash] A hash of parameters. Expects :uri_string.
def initialize(params)
@uri_string = params[:uri_string]
end
end

# A Good Result. The URL is valid.
class Good < Result
end

# A Redirect to another URL.
class Redirect < Result
attr_reader :good
attr_reader :final_destination_uri_string

# A new LinkChecker::Redirect object.
#
# @param params [Hash] A hash of parameters. Expects :final_destination_uri_string,
# which is the URL that the original :uri_string redirected to.
def initialize(params)
@final_destination_uri_string = params[:final_destination_uri_string]
@good = params[:good]
super(params)
end
end

# A Error result. The URL is not valid for some reason. Any reason, other than a 200
# HTTP response.
#
# @param params [Hash] A hash of parameters. Expects :error, which is a string
# representing the error.
class Error < Result
attr_reader :error
def initialize(params)
@error = params[:error]
super(params)
end
end
14 changes: 13 additions & 1 deletion test/fixtures/users.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,16 @@ user_001:
id: 1
email: test@sample.com
encrypted_password: <%= User.new.send(:password_digest, '123456') %>
admin: true
admin: true

unapproved_user:
email: unapproved@example.com
encrypted_password: <%= BCrypt::Password.create('password') %>

approved_user:
email: approved@example.com
encrypted_password: <%= BCrypt::Password.create('password') %>

regular_user:
email: regular@example.com
encrypted_password: <%= BCrypt::Password.create('password') %>
45 changes: 45 additions & 0 deletions test/mailers/admin_mailer_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require 'test_helper'

class AdminMailerTest < ActionMailer::TestCase
def setup
ActionMailer::Base.default_options = { from: 'noreply@example.com' }
end

test "image_states" do
rake_results = {
"Institution A" => { success: 10, failure: 2 },
"Institution B" => { success: 15, failure: 0 }
}

email = AdminMailer.image_states(rake_results)

assert_emails 1 do
email.deliver_now
end

assert_equal ['geoportal@btaa.org', 'majew030@umn.edu', 'ewlarson@gmail.com', 'mjb@umn.edu'], email.to
assert_equal 'noreply@example.com', email.from[0]
assert_equal 'B1G GeoBOT - Image Harvest States', email.subject
assert_match 'Institution A', email.body.to_s
assert_match 'Institution B', email.body.to_s
assert_match ':success=&gt;10', email.body.to_s
assert_match ':failure=&gt;2', email.body.to_s
assert_match ':success=&gt;15', email.body.to_s
assert_match ':failure=&gt;0', email.body.to_s
end

test "uri_analysis" do
report_file_path = '/path/to/uri_analysis_report.csv'

email = AdminMailer.uri_analysis(report_file_path)

assert_emails 1 do
email.deliver_now
end

assert_equal ['geoportal@btaa.org', 'majew030@umn.edu', 'ewlarson@gmail.com', 'mjb@umn.edu'], email.to
assert_equal 'noreply@example.com', email.from[0]
assert_equal 'B1G GeoBOT - URI Analysis Report', email.subject
assert_match report_file_path, email.body.to_s
end
end
60 changes: 60 additions & 0 deletions test/services/export_tableau_service_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require 'test_helper'

class ExportTableauServiceTest < ActiveSupport::TestCase
setup do
@document1 = Struct.new(:title, :geomg_id_s).new(
title: "Document 1",
geomg_id_s: "doc1"
)

@document2 = Struct.new(:title, :geomg_id_s).new(
title: "Document 2",
geomg_id_s: "doc2"
)
end

test "call method returns correct CSV data" do
result = ExportTableauService.call

expected_header = [
"Title",
"Provider",
"Resource Class",
"Resource Type",
"Index Year",
"Spatial Coverage",
"B1G Image",
"ID",
"Download",
"Language"
]

assert_equal expected_header, result[0]
assert_includes result, ["Document 1", nil, nil, nil, nil, nil, nil, "doc1", nil, nil]
assert_includes result, ["Document 2", nil, nil, nil, nil, nil, nil, "doc2", nil, nil]
end

test "call method broadcasts progress" do
broadcasts = []

ActionCable.server.define_singleton_method(:broadcast) do |channel, message|
broadcasts << [channel, message]
end

debugger

# 1
ExportTableauService.call
# 2
ExportTableauService.call
# 3
ExportTableauService.call

debugger

assert_equal 3, broadcasts.size
assert_equal ["export_channel", {progress: 0}], broadcasts.first
ensure
ActionCable.server.singleton_class.remove_method(:broadcast) if ActionCable.server.singleton_class.method_defined?(:broadcast)
end
end
Loading

0 comments on commit b399feb

Please sign in to comment.