Skip to content

Commit 3b77975

Browse files
authored
Merge pull request #98 from naotospace/feature/json_format_report
Feature/json format report
2 parents 397f263 + defbccb commit 3b77975

File tree

12 files changed

+106
-55
lines changed

12 files changed

+106
-55
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
command: docker load -q -i ~/caches/images.tar
2828
- run:
2929
name: docker up
30-
command: docker-compose -f docker-compose.system-test.yml up --no-build -d
30+
command: docker-compose -f docker-compose.system-test.yml up -d
3131
- run:
3232
name: execute system testing
3333
command: 'circleci tests glob system_testing/testing_code/*.bats | xargs -n 1 -I {} docker exec bucky-core bats "/bucky-core/"{} | circleci tests split'

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ ENV_FOO=foo bucky run -t e2e -d
9898
-r, --re_test_count RE_TEST_COUNT # How many round you run tests
9999
-l, --label LABEL_NAME
100100
-m, --link_check_max_times MAX_TIMES # Works only with which category is linkstatus
101+
-o, --out JSON_OUTPUT_FILE_PATH # Output summary report by json
101102
```
102103

103104
### Rerun test

exe/bucky

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ end
8989
opts.on('-m', '--link_check_max_times') do |v|
9090
test_cond[:link_check_max_times] = v.to_i
9191
end
92-
92+
opts.on('-o', '--out JSON_OUTPUT_FILE_PATH') do |v|
93+
test_cond[:out] = v
94+
end
9395
lint_cond = {}
9496
opts.on('-C', '--category CATEGORY_NAME') do |v|
9597
lint_cond[:lint_category] = v
@@ -124,42 +126,34 @@ def bucky_home?
124126
File.exist?('.bucky_home')
125127
end
126128

127-
current_dir = Dir.pwd
128-
gem_script_dir = __dir__
129-
130-
if ARGV == RUN_COMMAND
131-
error_and_exit('Not bucky project dirctory here.') unless bucky_home?
132-
133-
$bucky_home_dir = Dir.pwd
129+
def setup_test_cond(test_cond)
134130
# Default conditions setting conditions setting
135131
test_cond[:test_category] ||= 'e2e'
136132
test_cond[:re_test_count] = test_cond[:re_test_count] ? test_cond[:re_test_count].to_i : 1
137133
test_cond[:link_check_max_times] ||= 3
134+
test_cond[:out] ||= 'report.json'
138135
# Change to array e.g.--suite_id 1,2,3 -> :suite_id=>[1,2,3]
139-
test_cond.each { |k, v| test_cond[k] = v.split(',') if v.instance_of?(String) }
140-
require_relative '../lib/bucky/core/test_core/test_manager'
141-
Bucky::Core::TestCore::TestManager.new(test_cond).run
142-
Bucky::Core::TestCore::ExitHandler.instance.bucky_exit
136+
%i[suite_name case label xlabel device].each do |k|
137+
test_cond[k] = test_cond[k].split(',') unless test_cond[k].nil?
138+
end
139+
test_cond
140+
end
143141

144-
elsif ARGV == RERUN_COMMAND
142+
current_dir = Dir.pwd
143+
gem_script_dir = __dir__
144+
145+
if ARGV[0].end_with? 'run'
146+
error_and_exit('Not bucky project dirctory here.') unless bucky_home?
145147
$bucky_home_dir = Dir.pwd
146-
# Default conditions setting conditions setting
147-
test_cond[:test_category] ||= 'e2e'
148-
test_cond[:link_check_max_times] ||= 3
149-
test_cond[:re_test_count] = test_cond[:re_test_count] ? test_cond[:re_test_count].to_i : 1
150-
# Change to array e.g.--suite_id 1,2,3 -> :suite_id=>[1,2,3]
151-
test_cond.each { |k, v| test_cond[k] = v.split(',') if v.instance_of?(String) }
152148
require_relative '../lib/bucky/core/test_core/test_manager'
153-
Bucky::Core::TestCore::TestManager.new(test_cond).rerun
149+
Bucky::Core::TestCore::TestManager.new(setup_test_cond(test_cond)).send(ARGV[0])
154150
Bucky::Core::TestCore::ExitHandler.instance.bucky_exit
155-
156151
elsif ARGV == LINT_COMMAND
157152
$bucky_home_dir = Dir.pwd
158153
# Default conditions setting
159154
lint_cond[:lint_category] ||= 'config'
160155
require_relative '../lib/bucky/tools/lint'
161156
Bucky::Tools::Lint.check(lint_cond[:lint_category])
162-
163157
elsif ARGV[0..0] == NEW_COMMAND
164158
error_and_exit('No test app name.') if ARGV.length < 2
165159

lib/bucky/core/test_core/test_case_loader.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,8 @@ def load_testcode(test_cond)
3434
testcodes = []
3535
service = (test_cond[:service] || ['*']).first
3636
device = (test_cond[:device] || ['*']).first
37-
category = (test_cond[:test_category] || ['*']).first
3837

39-
Dir.glob("#{$bucky_home_dir}/services/#{service}/#{device}/scenarios/#{category}/*.yml").each do |testcode_file|
38+
Dir.glob("#{$bucky_home_dir}/services/#{service}/#{device}/scenarios/#{test_cond[:test_category]}/*.yml").each do |testcode_file|
4039
testcodes << load_testcode_in_file(testcode_file, test_cond)
4140
end
4241
# Delete nil element

lib/bucky/core/test_core/test_class_generator.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def initialize(test_cond)
4646
end
4747

4848
# Genrate test class by test suite and test case data
49-
def generate_test_class(data, link_status_url_log = {})
49+
def generate_test_class(data: [], linkstatus_url_log: {}, w_pipe: {})
5050
test_cond = @test_cond
5151
# Common proccessing
5252
# e.g.) TestSampleAppPcE2e1, TestSampleAppPcHttpstatus1
@@ -63,6 +63,7 @@ def generate_test_class(data, link_status_url_log = {})
6363
match_obj = /\Atest_(.+)\(.+::(Test.+)\)\z/.match(original_name)
6464
"#{match_obj[1]}(#{match_obj[2]})"
6565
end
66+
define_method(:w_pipe, proc { w_pipe })
6667

6768
# Class structure is different for each test category
6869
case data[:test_category]
@@ -74,8 +75,8 @@ def generate_test_class(data, link_status_url_log = {})
7475
define_method(method_name) do
7576
puts "\n#{simple_test_class_name(name)}"
7677
t_case[:urls].each do |url|
77-
link_status_check_args = { url: url, device: data[:suite][:device], exclude_urls: data[:suite][:exclude_urls], link_check_max_times: test_cond[:link_check_max_times], url_log: link_status_url_log }
78-
link_status_check(link_status_check_args)
78+
linkstatus_check_args = { url: url, device: data[:suite][:device], exclude_urls: data[:suite][:exclude_urls], link_check_max_times: test_cond[:link_check_max_times], url_log: linkstatus_url_log }
79+
linkstatus_check(linkstatus_check_args)
7980
end
8081
end
8182
)

lib/bucky/core/test_core/test_manager.rb

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
require 'parallel'
3+
require 'json'
44
require_relative '../test_core/test_case_loader'
55
require_relative '../../utils/config'
66
require_relative './test_class_generator'
@@ -26,6 +26,8 @@ def parallel_new_worker_each(data_set, max_processes, &block)
2626
# If child process dead, available workers increase
2727
Signal.trap('CLD') { available_workers += 1 }
2828

29+
r_pipe, w_pipe = IO.pipe
30+
2931
data_set.each do |data|
3032
# Wait until worker is available and handle exit code from previous process
3133
unless available_workers.positive?
@@ -34,28 +36,51 @@ def parallel_new_worker_each(data_set, max_processes, &block)
3436
end
3537
# Workers decrease when start working
3638
available_workers -= 1
37-
fork { block.call(data) }
39+
fork { block.call(data, w_pipe) }
3840
end
3941
# Handle all exit code in waitall
4042
Process.waitall.each do |child|
4143
Bucky::Core::TestCore::ExitHandler.instance.raise unless child[1].exitstatus.zero?
4244
end
45+
46+
w_pipe.close
47+
results_set = collect_results_set(r_pipe)
48+
r_pipe.close
49+
50+
results_set
4351
end
4452

4553
def parallel_distribute_into_workers(data_set, max_processes, &block)
4654
# Group the data by remainder of index
4755
data_set_grouped = data_set.group_by.with_index { |_elem, index| index % max_processes }
56+
r_pipe, w_pipe = IO.pipe
4857
# Use 'values' method to get only hash's key into an array
4958
data_set_grouped.values.each do |data_for_pre_worker|
5059
# Number of child process is equal to max_processes (or equal to data_set length when data_set length is less than max_processes)
5160
fork do
52-
data_for_pre_worker.each { |data| block.call(data) }
61+
data_for_pre_worker.each { |data| block.call(data, w_pipe) }
5362
end
5463
end
5564
# Handle all exit code in waitall
5665
Process.waitall.each do |child|
5766
Bucky::Core::TestCore::ExitHandler.instance.raise unless child[1].exitstatus.zero?
5867
end
68+
69+
w_pipe.close
70+
results_set = collect_results_set(r_pipe)
71+
r_pipe.close
72+
73+
results_set
74+
end
75+
76+
def collect_results_set(r_pipe)
77+
results_set = {}
78+
r_pipe.each_line do |line|
79+
r = JSON.parse(line)
80+
results_set[r['test_class_name']] = r
81+
end
82+
83+
results_set
5984
end
6085
end
6186

@@ -69,6 +94,20 @@ def initialize(test_cond)
6994
@tdo = Bucky::Core::Database::TestDataOperator.new
7095
@start_time = Time.now
7196
$job_id = @tdo.save_job_record_and_get_job_id(@start_time, @test_cond[:command_and_option])
97+
@json_report = {
98+
summary: {
99+
cases_count: 0,
100+
success_count: 0,
101+
failure_count: 0,
102+
job_id: $job_id,
103+
test_category: test_cond[:test_category],
104+
device: test_cond[:device],
105+
labels: test_cond[:label],
106+
exclude_labels: test_cond[:xlabel],
107+
rerun_job_id: test_cond[:job],
108+
round_count: 0
109+
}
110+
}
72111
end
73112

74113
def run
@@ -102,25 +141,42 @@ def do_test_suites(test_suite_data)
102141
e2e_parallel_num = Bucky::Utils::Config.instance[:e2e_parallel_num]
103142
linkstatus_parallel_num = Bucky::Utils::Config.instance[:linkstatus_parallel_num]
104143
tcg = Bucky::Core::TestCore::TestClassGenerator.new(@test_cond)
105-
case @test_cond[:test_category][0]
106-
when 'e2e' then parallel_new_worker_each(test_suite_data, e2e_parallel_num) { |data| tcg.generate_test_class(data) }
144+
case @test_cond[:test_category]
145+
when 'e2e' then results_set = parallel_new_worker_each(test_suite_data, e2e_parallel_num) { |data, w_pipe| tcg.generate_test_class(data: data, w_pipe: w_pipe) }
107146
when 'linkstatus' then
108-
link_status_url_log = {}
109-
parallel_distribute_into_workers(test_suite_data, linkstatus_parallel_num) { |data| tcg.generate_test_class(data, link_status_url_log) }
147+
linkstatus_url_log = {}
148+
results_set = parallel_distribute_into_workers(test_suite_data, linkstatus_parallel_num) { |data, w_pipe| tcg.generate_test_class(data: data, linkstatus_url_log: linkstatus_url_log, w_pipe: w_pipe) }
110149
end
150+
151+
results_set
111152
end
112153

113154
def execute_test
155+
results_set = {}
114156
@re_test_count.times do |i|
115157
Bucky::Core::TestCore::ExitHandler.instance.reset
116158
$round = i + 1
159+
@json_report[:summary][:round_count] = $round
117160
test_suite_data = load_test_suites
118-
do_test_suites(test_suite_data)
161+
results_set = do_test_suites(test_suite_data)
119162
@test_cond[:re_test_cond] = @tdo.get_ng_test_cases_at_last_execution(
120163
is_error: 1, job_id: $job_id, round: $round
121164
)
122165
break if @test_cond[:re_test_cond].empty?
123166
end
167+
168+
return unless @test_cond[:out]
169+
170+
results_set.each do |_class_name, res|
171+
@json_report[:summary][:cases_count] += res['cases_count']
172+
@json_report[:summary][:success_count] += res['success_count']
173+
@json_report[:summary][:failure_count] += res['failure_count']
174+
end
175+
176+
File.open(@test_cond[:out], 'w') do |f|
177+
f.puts(@json_report.to_json)
178+
puts "\nSave report : #{@test_cond[:out]}\n"
179+
end
124180
end
125181
end
126182
end

lib/bucky/test_equipment/test_case/abst_test_case.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

33
require 'test/unit'
4+
require 'json'
45
require_relative '../../core/test_core/test_result'
56

67
module Bucky
@@ -25,6 +26,12 @@ def shutdown
2526
def run(result)
2627
super
2728
@@this_result.result = result unless $debug
29+
w_pipe.puts({
30+
test_class_name: self.class.name,
31+
cases_count: result.run_count,
32+
success_count: result.pass_count,
33+
failure_count: result.run_count - result.pass_count
34+
}.to_json)
2835
end
2936

3037
def setup

lib/bucky/test_equipment/verifications/status_checker.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def http_status_check(args)
6262
end
6363
end
6464

65-
def link_status_check(args)
65+
def linkstatus_check(args)
6666
url = args[:url]
6767
device = args[:device]
6868
exclude_urls = args[:exclude_urls]

spec/core/test_core/test_case_loader_spec.rb

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,9 @@
1111
$bucky_home_dir = bucky_home
1212
end
1313

14-
context 'In case there is no arguments' do
15-
let(:test_cond) { {} }
16-
it 'return test code object' do
17-
expect(subject).not_to be_empty
18-
end
19-
end
20-
2114
context 'In case there are some arguments' do
2215
context 'when give args of test suite' do
23-
let(:test_cond) { { suite_name: [expect_scenario] } }
16+
let(:test_cond) { { suite_name: [expect_scenario], test_category: 'e2e' } }
2417
let(:expect_scenario) { 'scenario_a' }
2518
it 'return test code object' do
2619
expect(subject).not_to be_empty
@@ -32,8 +25,8 @@
3225
end
3326
end
3427

35-
context 'when give args of priority' do
36-
let(:test_cond) { { priority: [expect_priority] } }
28+
context 'When give args of priority' do
29+
let(:test_cond) { { priority: [expect_priority], test_category: 'e2e' } }
3730
let(:expect_priority) { 'middle' }
3831
it 'return test code object' do
3932
expect(subject).not_to be_empty

spec/core/test_core/test_class_generator_spec.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
allow(Bucky::Utils::Config).to receive(:instance).and_return(linkstatus_open_timeout: 60)
1111
allow(Bucky::Utils::Config).to receive(:instance).and_return(linkstatus_read_timeout: 60)
1212
end
13-
let(:link_status_url_log) { { url: { code: 200, count: 1 } } }
14-
let(:link_status_data) do
13+
let(:linkstatus_url_log) { { url: { code: 200, count: 1 } } }
14+
let(:linkstatus_data) do
1515
{
1616
test_class_name: 'SearchflowAreaTop',
1717
test_suite_name: 'searchflow_area_top',
@@ -65,7 +65,7 @@
6565
describe 'generate class' do
6666
let(:device) { 'pc' }
6767
it 'generate test class according to test suite data' do
68-
subject.generate_test_class(link_status_data, link_status_url_log)
68+
subject.generate_test_class(data: linkstatus_data, linkstatus_url_log: linkstatus_url_log)
6969
expect(subject.instance_variable_get(:@test_classes).const_get(:TestFooPcLinkstatusSearchflowAreaTop).name).to eq('Bucky::Core::TestCore::TestClasses::TestFooPcLinkstatusSearchflowAreaTop')
7070
end
7171
end
@@ -74,14 +74,14 @@
7474
let(:device) { 'sp' }
7575
context 'in case of linkstatus' do
7676
it 'generate test method according to test suite data' do
77-
subject.generate_test_class(link_status_data, link_status_url_log)
77+
subject.generate_test_class(data: linkstatus_data, linkstatus_url_log: linkstatus_url_log)
7878
expect(subject.instance_variable_get(:@test_classes).const_get(:TestFooSpLinkstatusSearchflowAreaTop).instance_methods).to include :test_foo_sp_linkstatus_searchflow_area_top_0
7979
end
8080
end
8181

8282
context 'in case of e2e' do
8383
it 'generate test method according to test suite data' do
84-
subject.generate_test_class(e2e_data, link_status_url_log)
84+
subject.generate_test_class(data: e2e_data)
8585
expect(subject.instance_variable_get(:@test_classes).const_get(:TestFooPcE2eSearchflowAreaTop).instance_methods).to include :test_foo_pc_e2e_searchflow_area_top_0
8686
end
8787
end

spec/core/test_core/test_manager_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
allow(Bucky::Core::Database::TestDataOperator).to receive(:new).and_return(tdo)
1212
allow(tdo).to receive(:save_job_record_and_get_job_id)
1313
allow(tdo).to receive(:get_ng_test_cases_at_last_execution).and_return(ng_case_data)
14-
allow(tm).to receive(:do_test_suites)
14+
allow(tm).to receive(:do_test_suites).and_return({})
1515
end
1616

1717
describe '#run' do

spec/test_equipment/verifications/status_checker_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@
106106
end
107107
end
108108
end
109-
describe 'link_status_check' do
109+
describe 'linkstatus_check' do
110110
subject { test_class.new }
111111
let(:url) { 'https://example.com/' }
112112
let(:links) { ['https://example.com/hoge', 'https://example.com/fuga'] }
@@ -122,7 +122,7 @@
122122
end
123123
context 'no error base url, link url' do
124124
it 'not raise exception' do
125-
expect { subject.link_status_check(args) }.not_to raise_error
125+
expect { subject.linkstatus_check(args) }.not_to raise_error
126126
end
127127
end
128128
end

0 commit comments

Comments
 (0)