From 52c422fcca4449a053fde9a90c9291839106f79e Mon Sep 17 00:00:00 2001 From: shouan2212 Date: Thu, 22 Jan 2026 17:50:52 +0900 Subject: [PATCH] Refactor CI/CD configuration and add execution duration tracking - Add end_time and duration tracking to test execution - Remove ruby-json dependency - Remove cc-test-reporter from CI pipeline --- .circleci/config.yml | 22 +++++------- .circleci/deploy_to_rubygems.sh | 7 ++-- .circleci/setup_rubygems.sh | 5 ++- Dockerfile.dev | 1 - Dockerfile.system-test | 1 - lib/bucky/core/database/test_data_operator.rb | 35 ++++++++++++++----- lib/bucky/core/test_core/test_manager.rb | 18 +++++++--- spec/core/test_core/test_manager_spec.rb | 6 ++-- .../user_operation_helper_spec.rb | 26 ++++++++------ .../service_a/pc/scenarios/e2e/pc_e2e.yml | 3 +- 10 files changed, 80 insertions(+), 44 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5cb10408..c9d574ba 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -38,8 +38,6 @@ jobs: working_directory: ~/bucky-core docker: - image: cimg/ruby:3.2.0 - environment: - CC_TEST_REPORTER_ID: fd7bd9d517bdf8953c4d4803ca4ad7539d12d5c760048b8daf80cbc7d54fb262 steps: - checkout - type: cache-restore @@ -49,17 +47,15 @@ jobs: key: unit-test-{{ checksum "Gemfile.lock" }} paths: - vendor/bundle - # Download test-reporter + # Run rspec - run: - name: Setup Code Climate test-reporter - command: | - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter - # Run rspec and show on code climate - - run: | - ./cc-test-reporter before-build - bundle exec rspec - ./cc-test-reporter after-build --coverage-input-type simplecov --exit-code $? + name: Run RSpec tests + command: bundle exec rspec --format progress --format RspecJunitFormatter --out test-results/rspec/results.xml + # Store test results + - store_test_results: + path: test-results + - store_artifacts: + path: test-results static_code_analysis: docker: - image: cimg/ruby:3.2.0 @@ -83,7 +79,7 @@ jobs: - image: cimg/ruby:3.2.0 steps: - add_ssh_keys: - finerprints: + fingerprints: - "6a:f3:d3:b5:a5:da:ce:e0:9f:22:f8:4a:2f:51:67:2b" - checkout - run: diff --git a/.circleci/deploy_to_rubygems.sh b/.circleci/deploy_to_rubygems.sh index 23988257..f5b680f5 100644 --- a/.circleci/deploy_to_rubygems.sh +++ b/.circleci/deploy_to_rubygems.sh @@ -1,8 +1,11 @@ +#!/bin/bash +set -eu + VERSION=$(git describe --tags | grep -o -E "([0-9]+\.){1}[0-9]+(\.[0-9]+)?" | head -n1) git config user.email "bucky-operator@users.noreply.github.com" git config user.name "bucky-operator" # Update version.rb -sed -i '' -e "s/VERSION = '[0-9]\{1,\}.[0-9]\{1,\}.[0-9]\{1,\}'/VERSION = '$VERSION'/" lib/bucky/version.rb +sed -i -e "s/VERSION = '[0-9]\+\.[0-9]\+\.[0-9]\+'/VERSION = '$VERSION'/" lib/bucky/version.rb git diff git checkout master git add lib/bucky/version.rb @@ -11,4 +14,4 @@ git commit -m "Version $VERSION" gem build bucky-core.gemspec gem push "bucky-core-$VERSION.gem" # Push to master -git push origin master \ No newline at end of file +git push origin master diff --git a/.circleci/setup_rubygems.sh b/.circleci/setup_rubygems.sh index af7fa019..66870a38 100644 --- a/.circleci/setup_rubygems.sh +++ b/.circleci/setup_rubygems.sh @@ -1,3 +1,6 @@ +#!/bin/bash +set -eu + mkdir ~/.gem echo -e "---\r\n:rubygems_api_key: $RUBYGEMS_API_KEY" > ~/.gem/credentials -chmod 0600 /home/circleci/.gem/credentials \ No newline at end of file +chmod 0600 /home/circleci/.gem/credentials diff --git a/Dockerfile.dev b/Dockerfile.dev index a8ea7f21..3baf5377 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -16,7 +16,6 @@ RUN apk update && \ mysql-dev \ openssh \ ruby-dev \ - ruby-json \ tzdata \ yaml \ yaml-dev \ diff --git a/Dockerfile.system-test b/Dockerfile.system-test index 0bff879c..e6aca55f 100644 --- a/Dockerfile.system-test +++ b/Dockerfile.system-test @@ -16,7 +16,6 @@ RUN apk update && \ mysql-dev \ openssh \ ruby-dev \ - ruby-json \ tzdata \ yaml \ yaml-dev \ diff --git a/lib/bucky/core/database/test_data_operator.rb b/lib/bucky/core/database/test_data_operator.rb index 8cab581d..ea9b9581 100644 --- a/lib/bucky/core/database/test_data_operator.rb +++ b/lib/bucky/core/database/test_data_operator.rb @@ -21,7 +21,7 @@ def initialize def save_job_record_and_get_job_id(start_time, command_and_option, fqdn) return 0 if $debug - job_id = @connector.con[:jobs].insert(start_time: start_time, command_and_option: command_and_option, base_fqdn: fqdn) + job_id = @connector.con[:jobs].insert(start_time:, command_and_option:, base_fqdn: fqdn) @connector.disconnect job_id end @@ -95,7 +95,7 @@ def get_ng_test_cases_at_last_execution(cond) def get_test_case_id(test_suite_id, case_name) return nil if $debug - test_case = @connector.con[:test_cases].filter(test_suite_id: test_suite_id, case_name: case_name).first + test_case = @connector.con[:test_cases].filter(test_suite_id:, case_name:).first @connector.disconnect raise "Cannot get test_case id. test_suite_id: #{test_suite_id}, case_name: #{case_name}" if test_case.nil? @@ -106,11 +106,28 @@ def get_test_case_id(test_suite_id, case_name) # @param [Int] job_id # @return [Int] round def get_last_round_from_job_id(job_id) - round = @connector.con[:test_case_results].where(job_id: job_id).max(:round) + round = @connector.con[:test_case_results].where(job_id:).max(:round) @connector.disconnect round end + # Update job record with end_time and duration + # @param [Integer] job_id + # @param [Time] end_time + # @param [Float] duration + def update_job_record(job_id, end_time, duration) + rounded_duration = duration.round(2) + puts "DEBUG: Updating job #{job_id} with end_time #{end_time} and duration #{rounded_duration}" + return if $debug + + @connector.connect + @connector.con[:jobs].where(id: job_id).update( + end_time:, + duration: rounded_duration + ) + @connector.disconnect + end + private # Common method for getting suite @@ -131,7 +148,7 @@ def get_suite_id_from_saved_test_suite(saved_test_suite, test_data) test_suite_name: test_data[:test_suite_name], suite_description: test_data[:suite][:desc], github_url: @config[:test_code_repo], - file_path: file_path + file_path: ) saved_test_suite[:id] else # If there is no test_suite, save new record and return suite_id. @@ -143,7 +160,7 @@ def get_suite_id_from_saved_test_suite(saved_test_suite, test_data) test_suite_name: test_data[:test_suite_name], suite_description: test_data[:suite][:desc], github_url: @config[:test_code_repo], - file_path: file_path + file_path: ) end end @@ -159,11 +176,11 @@ def insert_and_return_label_ids(labels) return nil if labels.empty? labels.each do |label_name| - label = @connector.con[:labels].filter(label_name: label_name).first + label = @connector.con[:labels].filter(label_name:).first label_ids << if label label[:id] else - @connector.con[:labels].insert(label_name: label_name) + @connector.con[:labels].insert(label_name:) end end label_ids @@ -180,14 +197,14 @@ def update_test_case_and_test_case_label(suite_id, test_case, label_ids) # Create new connection # If there is no labels, return nil label_ids&.each do |label_id| - @connector.con[:test_case_labels].insert(test_case_id: saved_test_case[:id], label_id: label_id) + @connector.con[:test_case_labels].insert(test_case_id: saved_test_case[:id], label_id:) end else # Add case data test_case_id = @connector.con[:test_cases].insert(test_suite_id: suite_id, case_name: test_case[:case_name], case_description: test_case[:desc]) # If there is no labels, return nil label_ids&.each do |label_id| - @connector.con[:test_case_labels].insert(test_case_id: test_case_id, label_id: label_id) + @connector.con[:test_case_labels].insert(test_case_id:, label_id:) end end end diff --git a/lib/bucky/core/test_core/test_manager.rb b/lib/bucky/core/test_core/test_manager.rb index 5d7f48ce..ea13ba4e 100644 --- a/lib/bucky/core/test_core/test_manager.rb +++ b/lib/bucky/core/test_core/test_manager.rb @@ -55,7 +55,7 @@ def parallel_distribute_into_workers(data_set, max_processes, &block) data_set_grouped = data_set.group_by.with_index { |_elem, index| index % max_processes } r_pipe, w_pipe = IO.pipe # Use 'values' method to get only hash's key into an array - data_set_grouped.values.each do |data_for_pre_worker| + data_set_grouped.each_value do |data_for_pre_worker| # Number of child process is equal to max_processes (or equal to data_set length when data_set length is less than max_processes) fork do data_for_pre_worker.each { |data| block.call(data, w_pipe) } @@ -112,6 +112,11 @@ def initialize(test_cond) def run execute_test + + # Update job record with end_time and duration when test completes + @end_time = Time.now + @duration = @end_time - @start_time + @tdo.update_job_record($job_id, @end_time, @duration) end # Rerun by job id @@ -122,6 +127,11 @@ def rerun is_error: 1, job_id: rerun_job_id, round: $round ) execute_test + + # Update job record with end_time and duration when test completes + @end_time = Time.now + @duration = @end_time - @start_time + @tdo.update_job_record($job_id, @end_time, @duration) end private @@ -142,10 +152,10 @@ def do_test_suites(test_suite_data) linkstatus_parallel_num = Bucky::Utils::Config.instance[:linkstatus_parallel_num] tcg = Bucky::Core::TestCore::TestClassGenerator.new(@test_cond) case @test_cond[:test_category] - 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) } - when 'linkstatus' then + when 'e2e' then results_set = parallel_new_worker_each(test_suite_data, e2e_parallel_num) { |data, w_pipe| tcg.generate_test_class(data:, w_pipe:) } + when 'linkstatus' linkstatus_url_log = {} - 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) } + results_set = parallel_distribute_into_workers(test_suite_data, linkstatus_parallel_num) { |data, w_pipe| tcg.generate_test_class(data:, linkstatus_url_log:, w_pipe:) } end results_set diff --git a/spec/core/test_core/test_manager_spec.rb b/spec/core/test_core/test_manager_spec.rb index 11450f1c..fa6eae84 100644 --- a/spec/core/test_core/test_manager_spec.rb +++ b/spec/core/test_core/test_manager_spec.rb @@ -10,12 +10,13 @@ before do allow(Bucky::Core::Database::TestDataOperator).to receive(:new).and_return(tdo) allow(tdo).to receive(:save_job_record_and_get_job_id) + allow(tdo).to receive(:update_job_record) allow(tdo).to receive(:get_ng_test_cases_at_last_execution).and_return(ng_case_data) allow(tm).to receive(:do_test_suites).and_return({}) end describe '#run' do - let(:tm) { Bucky::Core::TestCore::TestManager.new(re_test_count: re_test_count) } + let(:tm) { Bucky::Core::TestCore::TestManager.new(re_test_count:) } describe '@re_test_count: run untill max round' do context '@re_test_count is 1' do @@ -50,9 +51,10 @@ end describe '#rerun' do - let(:tm) { Bucky::Core::TestCore::TestManager.new(re_test_count: re_test_count, job: rerun_job_id) } + let(:tm) { Bucky::Core::TestCore::TestManager.new(re_test_count:, job: rerun_job_id) } before do allow(tdo).to receive(:get_last_round_from_job_id) + allow(tdo).to receive(:update_job_record) end describe 'call execute_test on rerun method' do diff --git a/spec/test_equipment/user_operation/user_operation_helper_spec.rb b/spec/test_equipment/user_operation/user_operation_helper_spec.rb index ca9fadf1..e1af2bde 100644 --- a/spec/test_equipment/user_operation/user_operation_helper_spec.rb +++ b/spec/test_equipment/user_operation/user_operation_helper_spec.rb @@ -103,7 +103,8 @@ describe '#switch_to_the_window' do let(:operation) { :switch_to_the_window } let(:args) { { window_name: 'new' } } - let(:args_with_timeout) { { window_name: 'new', timeout: 5 } } + let(:timeout_sec) { 2 } + let(:args_with_timeout) { { window_name: 'new', timeout: timeout_sec } } it 'call driver.swich_to_window_by_name' do expect(driver_double).to receive_message_chain(:switch_to, :window) subject.send(operation, args) @@ -113,7 +114,7 @@ subject.send(operation, args) end it 'call wait_until_helper with timeout argument' do - expect(subject).to receive(:wait_until_helper) { |timeout, *| expect(timeout).to eq(5) } + expect(subject).to receive(:wait_until_helper) { |timeout, *| expect(timeout).to eq(timeout_sec) } subject.send(operation, args_with_timeout) end end @@ -151,7 +152,8 @@ describe '#input' do let(:operation) { :input } let(:args) { { page: 'top', part: 'form', word: 'hogehoge' } } - let(:args_with_timeout) { { page: 'top', part: 'form', word: 'hogehoge', timeout: 5 } } + let(:timeout_sec) { 2 } + let(:args_with_timeout) { args.merge(timeout: timeout_sec) } let(:elem_double) { double('elem double') } it 'call part#send_keys' do expect(pages_double).to receive_message_chain(:get_part, :send_keys) @@ -165,7 +167,7 @@ it 'call wait_until_helper with timeout argument' do allow(pages_double).to receive_message_chain(:get_part, :send_keys).and_return(elem_double) # Verify that some of the arguments match. - expect(subject).to receive(:wait_until_helper) { |timeout, *| expect(timeout).to eq(5) } + expect(subject).to receive(:wait_until_helper) { |timeout, *| expect(timeout).to eq(timeout_sec) } subject.send(operation, args_with_timeout) end end @@ -182,7 +184,8 @@ describe '#click' do let(:operation) { :click } let(:args) { { page: 'top', part: 'form' } } - let(:args_with_timeout) { { page: 'top', part: 'form', timeout: 5 } } + let(:timeout_sec) { 2 } + let(:args_with_timeout) { args.merge(timeout: timeout_sec) } let(:elem_double) { double('elem double') } it 'call part#click' do allow(pages_double).to receive(:get_part).and_return(elem_double) @@ -205,7 +208,7 @@ allow(pages_double).to receive(:get_part).and_return(elem_double) allow(elem_double).to receive(:click) # Verify that some of the arguments match. - expect(subject).to receive(:wait_until_helper) { |timeout, *| expect(timeout).to eq(5) } + expect(subject).to receive(:wait_until_helper) { |timeout, *| expect(timeout).to eq(timeout_sec) } subject.send(operation, args_with_timeout) end end @@ -216,7 +219,8 @@ let(:args_value) { { page: 'top', part: 'form', value: 1 } } let(:args_index) { { page: 'top', part: 'form', index: 1 } } let(:args_error) { { page: 'top', part: 'form', error: 1 } } - let(:args_text_with_timeout) { { page: 'top', part: 'form', text: 'foo', timeout: 5 } } + let(:timeout_sec) { 2 } + let(:args_text_with_timeout) { args_text.merge(timeout: timeout_sec) } let(:option_double) { double('option double') } let(:elem_double) { double('elem double') } before do @@ -246,7 +250,7 @@ it 'call wait_until_helper with timeout argument' do allow(option_double).to receive(:select_by).with(:text, 'foo') # Verify that some of the arguments match. - expect(subject).to receive(:wait_until_helper) { |timeout, *| expect(timeout).to eq(5) }.and_return(option_double) + expect(subject).to receive(:wait_until_helper) { |timeout, *| expect(timeout).to eq(timeout_sec) }.and_return(option_double) subject.send(operation, args_text_with_timeout) end end @@ -254,6 +258,8 @@ describe '#accept_alert' do let(:operation) { :accept_alert } let(:alert_double) { double('alert double') } + let(:timeout_sec) { 2 } + let(:args_timeout) { { timeout: timeout_sec } } it 'call driver.switch_to.alert.accept' do expect(driver_double).to receive_message_chain(:switch_to, :alert, :accept) subject.send(operation, nil) @@ -268,8 +274,8 @@ allow(driver_double).to receive_message_chain(:switch_to, :alert).and_return(alert_double) allow(alert_double).to receive(:accept) # Verify that some of the arguments match. - expect(subject).to receive(:wait_until_helper) { |timeout, *| expect(timeout).to eq(5) }.and_return(alert_double) - subject.send(operation, nil) + expect(subject).to receive(:wait_until_helper) { |timeout, *| expect(timeout).to eq(2) }.and_return(alert_double) + subject.send(operation, args_timeout) end end diff --git a/system_testing/test_bucky_project/services/service_a/pc/scenarios/e2e/pc_e2e.yml b/system_testing/test_bucky_project/services/service_a/pc/scenarios/e2e/pc_e2e.yml index eb30c74c..0995b526 100644 --- a/system_testing/test_bucky_project/services/service_a/pc/scenarios/e2e/pc_e2e.yml +++ b/system_testing/test_bucky_project/services/service_a/pc/scenarios/e2e/pc_e2e.yml @@ -17,6 +17,7 @@ cases: operate: click page: index part: link + timeout: 1 - proc: check title exec: verify: assert_title @@ -128,4 +129,4 @@ cases: - proc: index exec: verify: click_multiple_element - page: index \ No newline at end of file + page: index