bucky-core 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +66 -0
- data/.codeclimate.yml +48 -0
- data/.dockerignore +11 -0
- data/.gitignore +40 -0
- data/.rspec +3 -0
- data/.rubocop.yml +76 -0
- data/.rubocop_todo.yml +51 -0
- data/Dockerfile +38 -0
- data/Dockerfile.system-test +44 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +115 -0
- data/LICENSE +201 -0
- data/README.md +246 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/bucky-core.gemspec +47 -0
- data/docker-compose.dev-with-bm.yml +28 -0
- data/docker-compose.dev.yml +18 -0
- data/docker-compose.system-test.yml +21 -0
- data/docker/nginx/Dockerfile +7 -0
- data/docker/nginx/nginx.conf +22 -0
- data/docker/nginx/public/index.html +19 -0
- data/docker/nginx/public/test_page.html +12 -0
- data/exe/bucky +214 -0
- data/lib/bucky.rb +3 -0
- data/lib/bucky/core/database/db_connector.rb +29 -0
- data/lib/bucky/core/database/test_data_operator.rb +195 -0
- data/lib/bucky/core/exception/bucky_exception.rb +39 -0
- data/lib/bucky/core/report/screen_shot_generator.rb +24 -0
- data/lib/bucky/core/test_core/test_case_loader.rb +162 -0
- data/lib/bucky/core/test_core/test_class_generator.rb +129 -0
- data/lib/bucky/core/test_core/test_manager.rb +70 -0
- data/lib/bucky/core/test_core/test_result.rb +92 -0
- data/lib/bucky/test_equipment/evidence/evidence_generator.rb +36 -0
- data/lib/bucky/test_equipment/pageobject/base_pageobject.rb +55 -0
- data/lib/bucky/test_equipment/pageobject/pages.rb +61 -0
- data/lib/bucky/test_equipment/selenium_handler/webdriver_handler.rb +66 -0
- data/lib/bucky/test_equipment/test_case/abst_test_case.rb +49 -0
- data/lib/bucky/test_equipment/test_case/e2e_test_case.rb +70 -0
- data/lib/bucky/test_equipment/test_case/linkstatus_test_case.rb +28 -0
- data/lib/bucky/test_equipment/user_operation/user_operation_helper.rb +97 -0
- data/lib/bucky/test_equipment/user_operation/user_operation_logger.rb +15 -0
- data/lib/bucky/test_equipment/user_operation/user_operator.rb +61 -0
- data/lib/bucky/test_equipment/verifications/abst_verification.rb +13 -0
- data/lib/bucky/test_equipment/verifications/e2e_verification.rb +106 -0
- data/lib/bucky/test_equipment/verifications/js_error_checker.rb +23 -0
- data/lib/bucky/test_equipment/verifications/service_verifications.rb +62 -0
- data/lib/bucky/test_equipment/verifications/status_checker.rb +180 -0
- data/lib/bucky/tools/lint.rb +69 -0
- data/lib/bucky/utils/bucky_logger.rb +25 -0
- data/lib/bucky/utils/bucky_output.rb +23 -0
- data/lib/bucky/utils/config.rb +55 -0
- data/lib/bucky/utils/requests.rb +33 -0
- data/lib/bucky/utils/yaml_load.rb +24 -0
- data/lib/bucky/version.rb +7 -0
- data/system_testing/test_bucky_project/.bucky_home +2 -0
- data/system_testing/test_bucky_project/config/bucky_config.yml +6 -0
- data/system_testing/test_bucky_project/config/e2e_config.yml +15 -0
- data/system_testing/test_bucky_project/config/linkstatus_config.yml +3 -0
- data/system_testing/test_bucky_project/config/test_db_config.yml +8 -0
- data/system_testing/test_bucky_project/services/README.md +1 -0
- data/system_testing/test_bucky_project/services/service_a/pc/pageobject/index.rb +13 -0
- data/system_testing/test_bucky_project/services/service_a/pc/parts/index.yml +6 -0
- data/system_testing/test_bucky_project/services/service_a/pc/scenarios/e2e/pc_e2e.yml +68 -0
- data/system_testing/test_bucky_project/services/service_a/pc/scenarios/e2e/setup_each_pc_e2e.yml +20 -0
- data/system_testing/test_bucky_project/services/service_a/pc/scenarios/e2e/setup_teardown_each_pc_e2e.yml +35 -0
- data/system_testing/test_bucky_project/services/service_a/pc/scenarios/e2e/teardown_each_pc_e2e.yml +20 -0
- data/system_testing/test_bucky_project/services/service_a/pc/scenarios/linkstatus/pc_link.yml +10 -0
- data/system_testing/test_bucky_project/services/service_a/sp/pageobject/index.rb +14 -0
- data/system_testing/test_bucky_project/services/service_a/sp/parts/index.yml +6 -0
- data/system_testing/test_bucky_project/services/service_a/sp/scenarios/e2e/sp_e2e_test.yml +26 -0
- data/system_testing/test_bucky_project/services/service_a/sp/scenarios/linkstatus/sp_link.yml +10 -0
- data/system_testing/test_bucky_project/services/service_a/tablet/pageobject/index.rb +14 -0
- data/system_testing/test_bucky_project/services/service_a/tablet/parts/index.yml +6 -0
- data/system_testing/test_bucky_project/services/service_a/tablet/scenarios/e2e/tablet_e2e_test.yml +26 -0
- data/system_testing/test_bucky_project/system/evidences/README.md +1 -0
- data/system_testing/test_bucky_project/system/evidences/screen_shots/README.md +1 -0
- data/system_testing/test_bucky_project/system/logs/README.md +1 -0
- data/system_testing/test_specification.md +38 -0
- data/system_testing/testing_code/command.bats +42 -0
- data/system_testing/testing_code/e2e.bats +75 -0
- data/system_testing/testing_code/linkstatus.bats +24 -0
- data/template/make_page/pc/pageobject/sample_page.rb +23 -0
- data/template/make_page/pc/parts/sample_page.yml +9 -0
- data/template/make_page/sp/pageobject/sample_page.rb +24 -0
- data/template/make_page/sp/parts/sample_page.yml +9 -0
- data/template/make_page/tablet/pageobject/sample_page.rb +24 -0
- data/template/make_page/tablet/parts/sample_page.yml +9 -0
- data/template/new/.bucky_home +2 -0
- data/template/new/config/bucky_config.yml +6 -0
- data/template/new/config/e2e_config.yml +15 -0
- data/template/new/config/linkstatus_config.yml +3 -0
- data/template/new/config/test_db_config.yml +8 -0
- data/template/new/services/README.md +1 -0
- data/template/new/system/evidences/README.md +1 -0
- data/template/new/system/evidences/screen_shots/README.md +1 -0
- data/template/new/system/logs/README.md +1 -0
- metadata +415 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require_relative '../verifications/status_checker'
|
5
|
+
require_relative './abst_test_case'
|
6
|
+
|
7
|
+
module Bucky
|
8
|
+
module TestEquipment
|
9
|
+
module TestCase
|
10
|
+
class LinkstatusTestCase < Bucky::TestEquipment::TestCase::AbstTestCase
|
11
|
+
include Bucky::TestEquipment::Verifications::StatusChecker
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def startup; end
|
15
|
+
|
16
|
+
def shutdown; end
|
17
|
+
end
|
18
|
+
|
19
|
+
def setup; end
|
20
|
+
|
21
|
+
def teardown
|
22
|
+
# Call abst_test_case.teardown to get elappsed time of every test case
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bucky
|
4
|
+
module TestEquipment
|
5
|
+
module UserOperation
|
6
|
+
class UserOperationHelper
|
7
|
+
def initialize(args)
|
8
|
+
@app = args[:app]
|
9
|
+
@device = args[:device]
|
10
|
+
@driver = args[:driver]
|
11
|
+
@pages = args[:pages]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Open url
|
15
|
+
# @param [Hash]
|
16
|
+
def go(args)
|
17
|
+
@driver.navigate.to args[:url]
|
18
|
+
end
|
19
|
+
|
20
|
+
def back(_)
|
21
|
+
@driver.navigate.back
|
22
|
+
end
|
23
|
+
|
24
|
+
def input(args)
|
25
|
+
@pages.get_part(args).send_keys args[:word]
|
26
|
+
end
|
27
|
+
|
28
|
+
# Clear textbox
|
29
|
+
def clear(args)
|
30
|
+
@pages.get_part(args).clear
|
31
|
+
end
|
32
|
+
|
33
|
+
def click(args)
|
34
|
+
elem = @pages.get_part(args)
|
35
|
+
elem.location_once_scrolled_into_view
|
36
|
+
sleep 1
|
37
|
+
elem.click
|
38
|
+
end
|
39
|
+
|
40
|
+
def refresh(_)
|
41
|
+
@driver.navigate.refresh
|
42
|
+
end
|
43
|
+
|
44
|
+
def switch_next_window(_)
|
45
|
+
@driver.switch_to.window(@driver.window_handles.last)
|
46
|
+
end
|
47
|
+
|
48
|
+
def back_to_window(_)
|
49
|
+
@driver.switch_to.window(@driver.window_handles.first)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Close window
|
53
|
+
def close(_)
|
54
|
+
@driver.close
|
55
|
+
end
|
56
|
+
|
57
|
+
def stop(_)
|
58
|
+
puts 'stop. please enter to continue'
|
59
|
+
gets
|
60
|
+
end
|
61
|
+
|
62
|
+
def choose(args)
|
63
|
+
option = Selenium::WebDriver::Support::Select.new(@pages.get_part(args))
|
64
|
+
if args.key?(:text)
|
65
|
+
type = :text
|
66
|
+
selected = args[type].to_s
|
67
|
+
elsif args.key?(:value)
|
68
|
+
type = :value
|
69
|
+
selected = args[type].to_s
|
70
|
+
elsif args.key?(:index)
|
71
|
+
type = :index
|
72
|
+
selected = args[type].to_i
|
73
|
+
else
|
74
|
+
raise StandardError, "Included invalid key #{args.keys}"
|
75
|
+
end
|
76
|
+
option.select_by(type, selected)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Alert accept
|
80
|
+
def accept_alert(_)
|
81
|
+
a = @driver.switch_to.alert
|
82
|
+
a.accept
|
83
|
+
end
|
84
|
+
|
85
|
+
def wait(args)
|
86
|
+
# Indent
|
87
|
+
print ' ' * 6
|
88
|
+
args[:sec].times do |count|
|
89
|
+
print "#{count + 1} "
|
90
|
+
sleep 1
|
91
|
+
end
|
92
|
+
puts ''
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../core/exception/bucky_exception'
|
4
|
+
require_relative './user_operation_helper'
|
5
|
+
require_relative '../../utils/bucky_logger'
|
6
|
+
|
7
|
+
module Bucky
|
8
|
+
module TestEquipment
|
9
|
+
module UserOperation
|
10
|
+
class UserOperator
|
11
|
+
include Bucky::Utils::BuckyLogger
|
12
|
+
|
13
|
+
def initialize(args)
|
14
|
+
@operation_helper = Bucky::TestEquipment::UserOperation::UserOperationHelper.new(args)
|
15
|
+
@pages = args[:pages]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Call user operation by argument
|
19
|
+
# @param [String] operation
|
20
|
+
# @param [String] test_case_name
|
21
|
+
# @param [Hash] args
|
22
|
+
def method_missing(operation, test_case_name, **args)
|
23
|
+
@operation = operation
|
24
|
+
@test_case_name = test_case_name
|
25
|
+
Bucky::Utils::BuckyLogger.write(test_case_name, args)
|
26
|
+
|
27
|
+
# Call method of UserOperationHelper
|
28
|
+
return @operation_helper.send(@operation, args) if @operation_helper.methods.include?(@operation)
|
29
|
+
|
30
|
+
# Call method of page object
|
31
|
+
# e.g) {page: 'top', operation: 'input_freeword', word: 'testing word'}
|
32
|
+
return page_method(args) if args.key?(:page) && !args.key?(:part)
|
33
|
+
|
34
|
+
# Call method of part
|
35
|
+
part_mothod(args) if args.key?(:part)
|
36
|
+
rescue StandardError => e
|
37
|
+
Bucky::Core::Exception::WebdriverException.handle(e)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def page_method(args)
|
43
|
+
@pages.send(args[:page]).send(@operation, args)
|
44
|
+
end
|
45
|
+
|
46
|
+
def part_mothod(args)
|
47
|
+
# Multiple parts is saved as hash
|
48
|
+
# e.g){page: 'top', part: {locate: 'rosen_tokyo', num: 1}, operate: 'click'}
|
49
|
+
if args[:part].class == Hash
|
50
|
+
part_name = args[:part][:locate]
|
51
|
+
num = args[:part][:num]
|
52
|
+
@pages.send(args[:page]).send(part_name)[num].send(@operation)
|
53
|
+
# e.g.){page: 'top', part: 'rosen_tokyo', operate: 'click'}
|
54
|
+
else
|
55
|
+
@pages.send(args[:page]).send(args[:part]).send(@operation)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../utils/bucky_logger'
|
4
|
+
require_relative '../../utils/bucky_output'
|
5
|
+
require_relative './abst_verification'
|
6
|
+
require_relative '../evidence/evidence_generator'
|
7
|
+
|
8
|
+
module Bucky
|
9
|
+
module TestEquipment
|
10
|
+
module Verifications
|
11
|
+
class E2eVerification < Bucky::TestEquipment::Verifications::AbstVerification
|
12
|
+
include Bucky::Utils::BuckyLogger
|
13
|
+
include Bucky::Utils::BuckyOutput
|
14
|
+
using StringColorize
|
15
|
+
|
16
|
+
def initialize(driver, pages, test_case_name)
|
17
|
+
@driver = driver
|
18
|
+
@pages = pages
|
19
|
+
@evidence = Bucky::TestEquipment::Evidence::E2eEvidence.new(driver: driver, test_case: test_case_name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def pages_getter
|
23
|
+
@pages
|
24
|
+
end
|
25
|
+
|
26
|
+
# Check whether title of web page matches expected value
|
27
|
+
# @param [Hash]
|
28
|
+
def assert_title(**args)
|
29
|
+
Bucky::Utils::BuckyLogger.write('assert_title', args)
|
30
|
+
verify_rescue { assert_equal(args[:expect]&.to_s, @driver.title, 'Not Expected Title.') }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Check whether text of web element matches expected value
|
34
|
+
# @param [Hash]
|
35
|
+
def assert_text(**args)
|
36
|
+
Bucky::Utils::BuckyLogger.write('assert_text', args)
|
37
|
+
part = @pages.get_part(args)
|
38
|
+
verify_rescue { assert_equal(args[:expect]&.to_s, part.text, 'Not Expected Text.') }
|
39
|
+
end
|
40
|
+
|
41
|
+
# Check whether text of web element contains expected value
|
42
|
+
# @param [Hash]
|
43
|
+
def assert_contained_text(**args)
|
44
|
+
Bucky::Utils::BuckyLogger.write('assert_contained_text', args)
|
45
|
+
part = @pages.get_part(args)
|
46
|
+
verify_rescue { assert(part.text.include?(args[:expect]&.to_s), "Not Contain Expected Text.\nexpect: #{args[:expect].to_s.bg_green.black}\nactual: #{part.text.to_s.bg_red.black}") }
|
47
|
+
end
|
48
|
+
|
49
|
+
# Check whether url contains excepted value
|
50
|
+
# @param [Hash]
|
51
|
+
def assert_contained_url(**args)
|
52
|
+
Bucky::Utils::BuckyLogger.write('assert_contained_url', args)
|
53
|
+
verify_rescue { assert(@driver.current_url.include?(args[:expect]&.to_s), "Not Contain Expected URL.\nexpect: #{args[:expect].to_s.bg_green.black}\nactual: #{@driver.current_url.to_s.bg_red.black}") }
|
54
|
+
end
|
55
|
+
|
56
|
+
# Check whether attribute of web element contains excepted value.
|
57
|
+
# @param [Hash]
|
58
|
+
def assert_contained_attribute(**args)
|
59
|
+
Bucky::Utils::BuckyLogger.write('assert_contained_attribute', args)
|
60
|
+
part = @pages.get_part(args)
|
61
|
+
verify_rescue { assert(part[args[:attribute]].include?(args[:expect]&.to_s), "Not Contain Expected Attribute.\nexpect: #{args[:expect].to_s.bg_green.black}\nactual: #{part[args[:attribute]].to_s.bg_red.black}") }
|
62
|
+
end
|
63
|
+
|
64
|
+
# Check whether text of part is number
|
65
|
+
# @param [Hash]
|
66
|
+
def assert_is_number(**args)
|
67
|
+
Bucky::Utils::BuckyLogger.write('assert is number', args)
|
68
|
+
text = @pages.get_part(args).text.sub(',', '')
|
69
|
+
verify_rescue { assert(text.to_i.to_s == text.to_s, "Not number.\nactual: #{text.bg_red.black}") }
|
70
|
+
end
|
71
|
+
|
72
|
+
# Check whether style property includes display:block
|
73
|
+
# @param [Hash]
|
74
|
+
def assert_display(**args)
|
75
|
+
Bucky::Utils::BuckyLogger.write('assert display', args)
|
76
|
+
verify_rescue { assert_true(@pages.get_part(args).displayed?, "No display this parts.\nURL: #{@driver.current_url}\npage: #{args[:page]}\npart: #{args[:part]}") }
|
77
|
+
end
|
78
|
+
|
79
|
+
# Check whether web element exists
|
80
|
+
# @param [Hash]
|
81
|
+
def assert_exist_part(**args)
|
82
|
+
Bucky::Utils::BuckyLogger.write('assert_exist_part', args)
|
83
|
+
verify_rescue { assert_true(@pages.part_exist?(args), "This part is not exist.\nURL: #{@driver.current_url}\npage: #{args[:page]}\npart: #{args[:part]}") }
|
84
|
+
end
|
85
|
+
|
86
|
+
# Check whether web element don't exist
|
87
|
+
# @param [Hash]
|
88
|
+
def assert_not_exist_part(**args)
|
89
|
+
Bucky::Utils::BuckyLogger.write('assert_not_exist_part', args)
|
90
|
+
verify_rescue { assert_false(@pages.part_exist?(args), "This part is exist.\nURL: #{@driver.current_url}\npage: #{args[:page]}\npart: #{args[:part]}") }
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
# Common exception method
|
96
|
+
# @param [Method] &assert
|
97
|
+
def verify_rescue
|
98
|
+
yield
|
99
|
+
rescue StandardError => e
|
100
|
+
@evidence.save_evidence(e)
|
101
|
+
raise e
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
module Bucky
|
6
|
+
module TestEquipment
|
7
|
+
module Verifications
|
8
|
+
module JsErrorChecker
|
9
|
+
include Test::Unit::Assertions
|
10
|
+
|
11
|
+
# Check Javascript Error in page
|
12
|
+
# @param [Webdriver] driver
|
13
|
+
def assert_no_js_error(driver)
|
14
|
+
js_errors = driver.execute_script(
|
15
|
+
'return window.JSErrorCollector_errors ? window.JSErrorCollector_errors.pump() : []'
|
16
|
+
)
|
17
|
+
# Empty is ok
|
18
|
+
assert_empty(js_errors, '[JS Error]')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../verifications/e2e_verification'
|
4
|
+
|
5
|
+
module Bucky
|
6
|
+
module TestEquipment
|
7
|
+
module Verifications
|
8
|
+
class ServiceVerifications
|
9
|
+
attr_reader :e2e_verification
|
10
|
+
|
11
|
+
# @param [String] @service
|
12
|
+
# @param [String] @device (pc, sp)
|
13
|
+
# @param [Selenium::WebDriver::Remote::Driver] @driver
|
14
|
+
# @param [Bucky::TestEquipment::PageObject::Pages] @pages
|
15
|
+
# @param [String] @test_case_name
|
16
|
+
def initialize(args)
|
17
|
+
@service = args[:service]
|
18
|
+
@device = args[:device]
|
19
|
+
@driver = args[:driver]
|
20
|
+
@pages = args[:pages]
|
21
|
+
@test_case_name = args[:method_name]
|
22
|
+
collect_verifications
|
23
|
+
@e2e_verification = Bucky::TestEquipment::Verifications::E2eVerification.new(@driver, @pages, @test_case_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing(verification, **args)
|
27
|
+
if e2e_verification.respond_to? verification
|
28
|
+
puts " #{verification} is defined in E2eVerificationClass."
|
29
|
+
e2e_verification.send(verification, args)
|
30
|
+
elsif args.key?(:page)
|
31
|
+
send(args[:page]).send(verification, args)
|
32
|
+
else
|
33
|
+
raise StandardError, "Undefined verification method or invalid arguments. #{verification},#{args}"
|
34
|
+
end
|
35
|
+
rescue StandardError => e
|
36
|
+
raise e
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Load page and define page verification method
|
42
|
+
def collect_verifications
|
43
|
+
module_service_name = @service.split('_').map(&:capitalize).join
|
44
|
+
Dir.glob("#{$bucky_home_dir}/services/#{@service}/#{@device}/verifications/*.rb").each do |file|
|
45
|
+
require file
|
46
|
+
|
47
|
+
page_name = file.split('/')[-1].sub('.rb', '')
|
48
|
+
page_class_name = page_name.split('_').map(&:capitalize).join
|
49
|
+
|
50
|
+
# Get instance of page object
|
51
|
+
page_class = eval(format('Services::%<module_service_name>s::%<device>s::Verifications::%<page_class_name>s', module_service_name: module_service_name, device: @device.capitalize, page_class_name: page_class_name))
|
52
|
+
page_instance = page_class.new(@driver, @pages, @test_case_name)
|
53
|
+
|
54
|
+
self.class.class_eval do
|
55
|
+
define_method(page_name) { page_instance }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'parallel'
|
6
|
+
require_relative '../../utils/requests'
|
7
|
+
require_relative '../../utils/config'
|
8
|
+
|
9
|
+
REDIRECT_LIMIT = 5
|
10
|
+
|
11
|
+
# Check http status code from response
|
12
|
+
# 2xx -> OK
|
13
|
+
# 3xx -> request again
|
14
|
+
# 4xx~5xx -> NG
|
15
|
+
|
16
|
+
module Bucky
|
17
|
+
module TestEquipment
|
18
|
+
module Verifications
|
19
|
+
module StatusChecker
|
20
|
+
include Test::Unit::Assertions
|
21
|
+
include Bucky::Utils::Requests
|
22
|
+
|
23
|
+
# Check http status code
|
24
|
+
# @param [String] url
|
25
|
+
# @return [String] message
|
26
|
+
def http_status_check(args)
|
27
|
+
url = args[:url]
|
28
|
+
device = args[:device]
|
29
|
+
link_check_max_times = args[:link_check_max_times]
|
30
|
+
url_log = args[:url_log]
|
31
|
+
redirect_count = args[:redirect_count]
|
32
|
+
redirect_url_list = args[:redirect_url_list]
|
33
|
+
|
34
|
+
# If number of requests is over redirect limit
|
35
|
+
return { error_message: "\n[Redirect Error] #{url} is redirected more than #{REDIRECT_LIMIT}" } if redirect_count > REDIRECT_LIMIT
|
36
|
+
|
37
|
+
check_result = check_log_and_get_response(url, device, link_check_max_times, url_log)
|
38
|
+
# If result include response continue to check, else return result
|
39
|
+
!check_result.key?(:response) ? (return check_result) : response = check_result[:response]
|
40
|
+
|
41
|
+
# Store original url
|
42
|
+
redirect_url_list << url
|
43
|
+
case response.code
|
44
|
+
when /2[0-9]{2}/
|
45
|
+
url_log[url][:entity] = response.entity
|
46
|
+
puts " #{url} ... [#{response.code}:OK]"
|
47
|
+
{ entity: response.entity }
|
48
|
+
when /3[0-9]{2}/
|
49
|
+
fqdn = url[%r{^(https?:\/\/([a-zA-Z0-9\-_.]+))}]
|
50
|
+
redirect_url = response['location']
|
51
|
+
# Add fqdn if location doesn't include fqdn
|
52
|
+
redirect_url = fqdn << redirect_url unless redirect_url.include?('http')
|
53
|
+
puts " #{url} ... redirect to #{redirect_url} [#{response.code}:RD]"
|
54
|
+
http_status_check_args = { url: redirect_url, device: device, link_check_max_times: link_check_max_times, url_log: url_log, redirect_count: redirect_count + 1, redirect_url_list: redirect_url_list }
|
55
|
+
http_status_check(http_status_check_args)
|
56
|
+
when /(4|5)[0-9]{2}/
|
57
|
+
url_log[url][:error_message] = "[Status Error] http status returned #{response.code}.\ncheck this url: #{redirect_url_list.join(' -> ')}"
|
58
|
+
puts " #{url} ... [#{response.code}:NG]"
|
59
|
+
{ error_message: url_log[url][:error_message] }
|
60
|
+
else
|
61
|
+
url_log[url][:error_message] = "[Status Code Invalid Error] Status Code is Invalid. \n Status:#{response.code}"
|
62
|
+
{ error_message: url_log[url][:error_message] }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def link_status_check(args)
|
67
|
+
url = args[:url]
|
68
|
+
device = args[:device]
|
69
|
+
exclude_urls = args[:exclude_urls]
|
70
|
+
link_check_max_times = args[:link_check_max_times]
|
71
|
+
url_log = args[:url_log]
|
72
|
+
only_same_fqdn = args[:only_same_fqdn] ||= true
|
73
|
+
|
74
|
+
# Extract base url and check if it is valid
|
75
|
+
url_reg = %r{^(https?://([a-zA-Z0-9\-_.]+))}
|
76
|
+
url_obj = url.match(url_reg)
|
77
|
+
raise "Invalid URL #{url}" unless url_obj
|
78
|
+
|
79
|
+
base_url = url_obj[1]
|
80
|
+
base_fqdn = url_obj[2]
|
81
|
+
|
82
|
+
# Check base url
|
83
|
+
http_status_check_args = { url: url, device: device, link_check_max_times: link_check_max_times, url_log: url_log, redirect_count: 0, redirect_url_list: [] }
|
84
|
+
base_response = http_status_check(http_status_check_args)
|
85
|
+
assert_nil(base_response[:error_message], "Response of base URL is incorrect.\n#{base_response[:error_message]}")
|
86
|
+
|
87
|
+
# Collect links
|
88
|
+
links_args = { base_url: base_url, base_fqdn: base_fqdn, url_reg: url_reg, only_same_fqdn: only_same_fqdn, entity: base_response[:entity] }
|
89
|
+
links = make_target_links(links_args)
|
90
|
+
links = exclude(links, exclude_urls) unless exclude_urls.nil?
|
91
|
+
|
92
|
+
errors = []
|
93
|
+
Parallel.each(links.uniq, in_threads: Bucky::Utils::Config.instance[:linkstatus_parallel_num]) do |link|
|
94
|
+
http_status_check_args[:url] = link
|
95
|
+
http_status_check_args[:redirect_url_list] = []
|
96
|
+
link_response = http_status_check(http_status_check_args)
|
97
|
+
errors << link_response[:error_message] if link_response[:error_message]
|
98
|
+
end
|
99
|
+
assert_empty(errors, errors.join("\n"))
|
100
|
+
end
|
101
|
+
|
102
|
+
def make_target_links(args)
|
103
|
+
base_url = args[:base_url]
|
104
|
+
base_fqdn = args[:base_fqdn]
|
105
|
+
url_reg = args[:url_reg]
|
106
|
+
only_same_fqdn = args[:only_same_fqdn]
|
107
|
+
entity = args[:entity]
|
108
|
+
doc = Nokogiri::HTML.parse(entity)
|
109
|
+
links = []
|
110
|
+
doc.xpath('//a').each do |node|
|
111
|
+
href = node.attr('href')
|
112
|
+
next if exclude_href?(href)
|
113
|
+
|
114
|
+
# Add fqdn if href doesn't include fqdn
|
115
|
+
unless url_reg.match?(href)
|
116
|
+
links << base_url + href
|
117
|
+
next
|
118
|
+
end
|
119
|
+
|
120
|
+
href_fqdn = href.match(url_reg)[2]
|
121
|
+
if only_same_fqdn == false
|
122
|
+
links << href
|
123
|
+
elsif base_fqdn == href_fqdn
|
124
|
+
links << href
|
125
|
+
end
|
126
|
+
end
|
127
|
+
links
|
128
|
+
end
|
129
|
+
|
130
|
+
# Exclude non test target url
|
131
|
+
def exclude(links, exclude_urls)
|
132
|
+
excluded_links = links - exclude_urls
|
133
|
+
|
134
|
+
# Exclude url if it has "*" in the last of it
|
135
|
+
exclude_urls.each do |ex_url|
|
136
|
+
next unless ex_url.end_with?('*')
|
137
|
+
|
138
|
+
excluded_links.delete_if { |l| l.start_with?(ex_url.delete('*')) }
|
139
|
+
end
|
140
|
+
|
141
|
+
excluded_links
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def exclude_href?(href)
|
147
|
+
return true if href.nil?
|
148
|
+
|
149
|
+
exclude_regexps = [/^javascript.+/, /^tel:\d.+/, /^mailto:.+/]
|
150
|
+
exclude_regexps.keep_if { |reg| reg.match?(href) }
|
151
|
+
return true unless exclude_regexps.empty?
|
152
|
+
|
153
|
+
false
|
154
|
+
end
|
155
|
+
|
156
|
+
# Check result hash and submit request or return result.
|
157
|
+
# Return: 1.(if request submitted) respons 2. (code 2xx)entity 3. (reach max check times)error message
|
158
|
+
def check_log_and_get_response(url, device, link_check_max_times, url_log)
|
159
|
+
unless url_log.key?(url)
|
160
|
+
response = get_response(url, device, Bucky::Utils::Config.instance[:linkstatus_open_timeout], Bucky::Utils::Config.instance[:linkstatus_read_timeout])
|
161
|
+
url_log[url] = { code: response.code, entity: nil, error_message: nil, count: 1 }
|
162
|
+
return { response: response }
|
163
|
+
end
|
164
|
+
|
165
|
+
if url_log[url][:code].match?(/2[0-9]{2}/)
|
166
|
+
puts " #{url} is already [#{url_log[url][:code]}:OK]"
|
167
|
+
return { entity: url_log[url][:entity] }
|
168
|
+
elsif url_log[url][:count] >= link_check_max_times
|
169
|
+
puts " #{url} reach maximum check times [#{url_log[url][:code]}:NG]"
|
170
|
+
return { error_message: url_log[url][:error_message] }
|
171
|
+
else
|
172
|
+
response = get_response(url, device, Bucky::Utils::Config.instance[:linkstatus_open_timeout], Bucky::Utils::Config.instance[:linkstatus_read_timeout])
|
173
|
+
url_log[url][:count] += 1
|
174
|
+
return { response: response }
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|