Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/qa
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-06-15 06:09:27 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-06-15 06:09:27 +0300
commita7b6d465ae75b497ac34cb43361edd0c8ce45fbd (patch)
treed1cf9f860c07d082014a895a306a6eca8a8d2691 /qa
parentafd8f58f2d0d42d21496fe4652c1664add9b68b7 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'qa')
-rw-r--r--qa/qa/ce/strategy.rb5
-rw-r--r--qa/qa/runtime/browser.rb18
-rw-r--r--qa/qa/runtime/env.rb25
-rw-r--r--qa/qa/service/docker_run/video.rb123
-rw-r--r--qa/qa/specs/spec_helper.rb1
-rw-r--r--qa/spec/service/docker_run/video_spec.rb181
6 files changed, 334 insertions, 19 deletions
diff --git a/qa/qa/ce/strategy.rb b/qa/qa/ce/strategy.rb
index 2587da17739..0e12649a070 100644
--- a/qa/qa/ce/strategy.rb
+++ b/qa/qa/ce/strategy.rb
@@ -17,7 +17,10 @@ module QA
end
QA::Runtime::Logger.info("Browser: #{QA::Runtime::Env.browser}")
- QA::Runtime::Logger.info("Browser version: #{QA::Runtime::Env.browser_version}")
+
+ if QA::Runtime::Env.use_selenoid?
+ QA::Runtime::Logger.info("Browser version: #{QA::Runtime::Env.selenoid_browser_version}")
+ end
# The login page could take some time to load the first time it is visited.
# We visit the login page and wait for it to properly load only once before the tests.
diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb
index 4297c62e904..7bc4530287c 100644
--- a/qa/qa/runtime/browser.rb
+++ b/qa/qa/runtime/browser.rb
@@ -16,8 +16,6 @@ module QA
CAPYBARA_MAX_WAIT_TIME = Env.max_capybara_wait_time
DEFAULT_WINDOW_SIZE = '1480,2200'
- PHONE_VIDEO_SIZE = '500x900'
- TABLET_VIDEO_SIZE = '800x1100'
def self.blank_page?
['', 'about:blank', 'data:,'].include?(Capybara.current_session.driver.browser.current_url)
@@ -174,7 +172,7 @@ module QA
if QA::Runtime::Env.remote_grid
selenium_options[:browser] = :remote
selenium_options[:url] = QA::Runtime::Env.remote_grid
- webdriver_options.browser_version = QA::Runtime::Env.browser_version
+ webdriver_options.browser_version = QA::Runtime::Env.selenoid_browser_version
end
if QA::Runtime::Env.remote_tunnel_id
@@ -185,9 +183,7 @@ module QA
if QA::Runtime::Env.record_video?
webdriver_options.add_option('selenoid:options', {
- enableVideo: true,
- videoScreenSize: video_screen_size,
- videoName: "#{QA::Runtime::Env.browser}-#{QA::Runtime::Env.browser_version}-#{Time.now}.mp4"
+ enableVideo: true
})
end
@@ -242,16 +238,6 @@ module QA
::File.expand_path('../../tmp/qa-profile', __dir__)
end
- def self.video_screen_size
- if QA::Runtime::Env.phone_layout?
- PHONE_VIDEO_SIZE
- elsif QA::Runtime::Env.tablet_layout?
- TABLET_VIDEO_SIZE
- else
- ''
- end
- end
-
class Session
include Capybara::DSL
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index 9df33c4d8d3..54f9db65afb 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -207,8 +207,16 @@ module QA
ENV['QA_BROWSER'].nil? ? :chrome : ENV['QA_BROWSER'].to_sym
end
- def browser_version
- ENV['QA_BROWSER_VERSION'] || 'latest'
+ def selenoid_browser_version
+ ENV['QA_SELENOID_BROWSER_VERSION']
+ end
+
+ def selenoid_browser_image
+ ENV['QA_SELENOID_BROWSER_IMAGE']
+ end
+
+ def video_recorder_image
+ ENV['QA_VIDEO_RECORDER_IMAGE']
end
def remote_mobile_device_name
@@ -241,6 +249,19 @@ module QA
enabled?(ENV['QA_RECORD_VIDEO'], default: false)
end
+ def use_selenoid?
+ enabled?(ENV['USE_SELENOID'], default: false)
+ end
+
+ def require_video_variables!
+ docs_link = 'https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/running_against_remote_grid.md#testing-with-selenoid'
+ use_selenoid? || (raise ArgumentError, "USE_SELENOID is required! See docs: #{docs_link}")
+ remote_grid || (raise ArgumentError, "QA_REMOTE_GRID is required! See docs: #{docs_link}")
+ video_recorder_image || (raise ArgumentError, "QA_VIDEO_RECORDER_IMAGE is required! See docs: #{docs_link}")
+ selenoid_browser_image || (raise ArgumentError, "QA_SELENOID_BROWSER_IMAGE is required! See docs: #{docs_link}")
+ selenoid_browser_version || (raise ArgumentError, "QA_SELENOID_BROWSER_VERSION is required! See docs: #{docs_link}")
+ end
+
def user_username
ENV['GITLAB_USERNAME']
end
diff --git a/qa/qa/service/docker_run/video.rb b/qa/qa/service/docker_run/video.rb
new file mode 100644
index 00000000000..c75280b1282
--- /dev/null
+++ b/qa/qa/service/docker_run/video.rb
@@ -0,0 +1,123 @@
+# frozen_string_literal: true
+
+module QA
+ module Service
+ module DockerRun
+ class Video < Base
+ class << self
+ include Service::Shellout
+
+ PHONE_VIDEO_SIZE = '500x900'
+ TABLET_VIDEO_SIZE = '800x1100'
+ DESKTOP_VIDEO_SIZE = '1920x1080'
+
+ def configure!
+ return unless QA::Runtime::Env.record_video?
+
+ begin
+ QA::Runtime::Env.require_video_variables!
+ rescue ArgumentError => e
+ return QA::Runtime::Logger.warn("Aborting video recording setup! Missing variables: #{e}")
+ end
+
+ @recorder_container_name = get_container_name(QA::Runtime::Env.video_recorder_image)
+ @browser_image_version =
+ "#{QA::Runtime::Env.selenoid_browser_image}:#{QA::Runtime::Env.selenoid_browser_version}"
+ @recorder_container_cmd = "docker exec -d #{@recorder_container_name} sh -c".freeze
+ set_browser_container_hostname
+ set_video_screen_size
+
+ if @recorder_container_name.present? && @browser_container_hostname
+ configure_rspec
+
+ QA::Runtime::Logger.info("Test failure video recording setup complete!")
+ else
+ QA::Runtime::Logger.warn("Test failure video recording setup failed!")
+ end
+ end
+
+ def start_recording(example)
+ @current_recording_name = create_recording_name(example)
+
+ ffmpeg_cmd = <<~CMD.tr("\n", ' ')
+ ffmpeg -y
+ -f x11grab
+ -video_size #{@video_size}
+ -r 15
+ -i #{@browser_container_hostname}:99
+ -vcodec 'libx264'
+ -pix_fmt 'yuv420p'
+ "/data/#{@current_recording_name}.mp4"
+ CMD
+
+ begin
+ shell("#{@recorder_container_cmd} '#{ffmpeg_cmd}'")
+ rescue StandardError => e
+ QA::Runtime::Logger.warn("Video recording start error: #{e}")
+ end
+ end
+
+ def stop_recording
+ shell("#{@recorder_container_cmd} 'pkill -INT -f ffmpeg'")
+ rescue StandardError => e
+ QA::Runtime::Logger.warn("Video recording stop error: #{e}")
+ end
+
+ def delete_video
+ shell("#{@recorder_container_cmd} 'rm /data/#{@current_recording_name}.mp4'")
+ rescue StandardError => e
+ QA::Runtime::Logger.warn("Video deletion error: #{e}")
+ end
+
+ private
+
+ def configure_rspec
+ RSpec.configure do |config|
+ config.prepend_before do |example|
+ QA::Service::DockerRun::Video.start_recording(example)
+ end
+
+ config.append_after do |example|
+ QA::Service::DockerRun::Video.stop_recording
+ QA::Service::DockerRun::Video.delete_video unless example.exception
+ end
+ end
+ end
+
+ def create_recording_name(example)
+ test_name = example.full_description.downcase.parameterize(separator: "_")[0..56]
+ test_time = Time.now.strftime "%Y-%m-%d-%H-%M-%S-%L"
+
+ "#{test_name}-#{test_time}"
+ end
+
+ def get_container_name(image)
+ name = shell("docker ps -f ancestor='#{image}' --format '{{.Names}}'")
+
+ QA::Runtime::Logger.warn("Getting container name for #{image} failed!") if name.empty?
+
+ name
+ end
+
+ def set_browser_container_hostname
+ container_name = get_container_name(@browser_image_version)
+ @browser_container_hostname = shell("docker inspect #{container_name} --format '{{.Config.Hostname}}'")
+ rescue StandardError => e
+ QA::Runtime::Logger.warn("Video recording browser container setup error: #{e}")
+ end
+
+ def set_video_screen_size
+ @video_size =
+ if QA::Runtime::Env.phone_layout?
+ PHONE_VIDEO_SIZE
+ elsif QA::Runtime::Env.tablet_layout?
+ TABLET_VIDEO_SIZE
+ else
+ DESKTOP_VIDEO_SIZE
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/spec_helper.rb b/qa/qa/specs/spec_helper.rb
index aa274a4e101..1601dd46c62 100644
--- a/qa/qa/specs/spec_helper.rb
+++ b/qa/qa/specs/spec_helper.rb
@@ -12,6 +12,7 @@ QA::Runtime::Browser.configure! unless QA::Runtime::Env.dry_run
QA::Runtime::AllureReport.configure!
QA::Runtime::Scenario.from_env(QA::Runtime::Env.runtime_scenario_attributes)
QA::Support::KnapsackReport.configure!
+QA::Service::DockerRun::Video.configure!
# Enable zero monkey patching mode before loading any other RSpec code.
RSpec.configure(&:disable_monkey_patching!)
diff --git a/qa/spec/service/docker_run/video_spec.rb b/qa/spec/service/docker_run/video_spec.rb
new file mode 100644
index 00000000000..81be5ccffae
--- /dev/null
+++ b/qa/spec/service/docker_run/video_spec.rb
@@ -0,0 +1,181 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe Service::DockerRun::Video do
+ include QA::Support::Helpers::StubEnv
+
+ let(:rspec_config) { instance_double('RSpec::Core::Configuration', append_after: nil, prepend_before: nil) }
+ let(:video_recorder_image) { 'presidenten/selenoid-manual-video-recorder' }
+ let(:video_recorder_version) { 'latest' }
+ let(:selenoid_browser_image) { 'selenoid/chrome' }
+ let(:selenoid_browser_version) { '111.0' }
+ let(:remote_grid) { 'selenoid:4444' }
+ let(:record_video) { 'true' }
+ let(:use_selenoid) { 'true' }
+ let(:docs_link) do
+ 'https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/running_against_remote_grid.md#testing-with-selenoid'
+ end
+
+ shared_examples 'video set up fails' do
+ it 'does not perform configuration' do
+ aggregate_failures do
+ expect(QA::Runtime::Logger).to have_received(:warn)
+ .with(/Test failure video recording setup failed!/)
+
+ expect(RSpec).not_to have_received(:configure)
+ end
+ end
+ end
+
+ shared_examples 'video set up missing variable' do |missing_variable|
+ let(:failure_message) do
+ <<~FAIL.tr("\n", ' ').strip
+ Aborting video recording setup!
+ Missing variables: #{missing_variable} is required!
+ See docs: #{docs_link}
+ FAIL
+ end
+
+ it 'aborts video setup with warning' do
+ aggregate_failures do
+ expect(QA::Runtime::Logger).to have_received(:warn)
+ .with(failure_message)
+
+ expect(described_class).not_to have_received(:get_container_name)
+ expect(RSpec).not_to have_received(:configure)
+ end
+ end
+ end
+
+ before do
+ stub_env('QA_VIDEO_RECORDER_IMAGE', video_recorder_image)
+ stub_env('QA_VIDEO_RECORDER_VERSION', video_recorder_version)
+ stub_env('QA_SELENOID_BROWSER_IMAGE', selenoid_browser_image)
+ stub_env('QA_SELENOID_BROWSER_VERSION', selenoid_browser_version)
+ stub_env('QA_REMOTE_GRID', remote_grid)
+ stub_env('USE_SELENOID', use_selenoid)
+ stub_env('QA_RECORD_VIDEO', record_video)
+
+ allow(RSpec).to receive(:configure).and_yield(rspec_config)
+ allow(described_class).to receive(:get_container_name)
+ allow(described_class).to receive(:shell)
+ allow(QA::Runtime::Logger).to receive(:warn)
+ allow(QA::Runtime::Logger).to receive(:info)
+ end
+
+ context 'with video disabled' do
+ let(:record_video) { 'false' }
+
+ before do
+ described_class.configure!
+ end
+
+ it 'skips configuration' do
+ aggregate_failures do
+ expect(described_class).not_to have_received(:get_container_name)
+ expect(described_class).not_to have_received(:shell)
+ expect(RSpec).not_to have_received(:configure)
+ end
+ end
+ end
+
+ context 'with use_selenoid disabled' do
+ let(:use_selenoid) { 'false' }
+
+ before do
+ described_class.configure!
+ end
+
+ it_behaves_like 'video set up missing variable', 'USE_SELENOID'
+ end
+
+ context 'without video_recorder_image set' do
+ let(:video_recorder_image) { nil }
+
+ before do
+ described_class.configure!
+ end
+
+ it_behaves_like 'video set up missing variable', 'QA_VIDEO_RECORDER_IMAGE'
+ end
+
+ context 'without selenoid_browser_image set' do
+ let(:selenoid_browser_image) { nil }
+
+ before do
+ described_class.configure!
+ end
+
+ it_behaves_like 'video set up missing variable', 'QA_SELENOID_BROWSER_IMAGE'
+ end
+
+ context 'without selenoid_browser_version set' do
+ let(:selenoid_browser_version) { nil }
+
+ before do
+ described_class.configure!
+ end
+
+ it_behaves_like 'video set up missing variable', 'QA_SELENOID_BROWSER_VERSION'
+ end
+
+ context 'without browser_container_hostname' do
+ before do
+ allow(described_class).to receive(:get_container_name)
+ .with(video_recorder_image)
+ .and_return('recorder_container_name')
+ allow(described_class).to receive(:get_container_name)
+ .with("#{selenoid_browser_image}:#{selenoid_browser_version}")
+ .and_return('browser_image_hostname')
+ allow(described_class).to receive(:shell)
+ .and_return(false)
+
+ described_class.configure!
+ end
+
+ it_behaves_like 'video set up fails'
+ end
+
+ context 'without recorder_container_name' do
+ before do
+ allow(described_class).to receive(:get_container_name)
+ .with(video_recorder_image)
+ .and_return('')
+ allow(described_class).to receive(:get_container_name)
+ .with("#{selenoid_browser_image}:#{selenoid_browser_version}")
+ .and_return('browser_image_hostname')
+ allow(described_class).to receive(:shell)
+ .and_return('browser_container_hostname')
+
+ described_class.configure!
+ end
+
+ it_behaves_like 'video set up fails'
+ end
+
+ context 'with recorder_container_name and browser_container_hostname' do
+ before do
+ allow(described_class).to receive(:get_container_name)
+ .with(video_recorder_image)
+ .and_return('recorder_container_name')
+ allow(described_class).to receive(:get_container_name)
+ .with("#{selenoid_browser_image}:#{selenoid_browser_version}")
+ .and_return('browser_image_hostname')
+ allow(described_class).to receive(:shell)
+ .and_return('browser_container_hostname')
+
+ described_class.configure!
+ end
+
+ it 'performs configuration' do
+ aggregate_failures do
+ expect(QA::Runtime::Logger).to have_received(:info)
+ .with(/Test failure video recording setup complete!/)
+ expect(RSpec).to have_received(:configure)
+ expect(rspec_config).to have_received(:prepend_before)
+ expect(rspec_config).to have_received(:append_after)
+ end
+ end
+ end
+ end
+end