提交 97265d39 编写于 作者: M Mark Lapierre 提交者: Ramya Authappan

[CE] Improve `wait_for_push`

上级 25af9032
......@@ -62,6 +62,11 @@ module QA
autoload :Fork, 'qa/resource/fork'
autoload :SSHKey, 'qa/resource/ssh_key'
module Events
autoload :Base, 'qa/resource/events/base'
autoload :Project, 'qa/resource/events/project'
end
module Repository
autoload :Push, 'qa/resource/repository/push'
autoload :ProjectPush, 'qa/resource/repository/project_push'
......@@ -361,6 +366,7 @@ module QA
autoload :Logging, 'qa/support/page/logging'
end
autoload :Api, 'qa/support/api'
autoload :Waiter, 'qa/support/waiter'
end
end
......
......@@ -18,19 +18,10 @@ module QA
page.refresh
end
def wait(max: 60, time: 0.1, reload: true)
start = Time.now
while Time.now - start < max
result = yield
return result if result
sleep(time)
refresh if reload
def wait(max: 60, interval: 0.1, reload: true)
QA::Support::Waiter.wait(max: max, interval: interval) do
yield || (reload && refresh && false)
end
false
end
def with_retry(max_attempts: 3, reload: false)
......@@ -73,7 +64,7 @@ module QA
xhr.send();
JS
return false unless wait(time: 0.5, max: 60, reload: false) do
return false unless wait(interval: 0.5, max: 60, reload: false) do
page.evaluate_script('xhr.readyState == XMLHttpRequest.DONE')
end
......
......@@ -21,11 +21,6 @@ module QA
repository_clone_location(:ssh_clone_url)
end
def wait_for_push
sleep 5
refresh
end
private
def repository_clone_location(kind)
......
......@@ -27,11 +27,6 @@ module QA
Git::Location.new(find('#project_clone').value)
end
def wait_for_push
sleep 5
refresh
end
private
def choose_repository_clone(kind, detect_text)
......
......@@ -148,7 +148,7 @@ module QA
end
def add_comment_to_diff(text)
wait(time: 5) do
wait(interval: 5) do
has_text?("No newline at end of file")
end
all_elements(:new_diff_line).first.hover
......
......@@ -62,7 +62,7 @@ module QA
sleep 5
refresh
wait(time: 1) do
wait(interval: 1) do
within_element_by_index(:mirrored_repository_row, row_index) do
last_update = find_element(:mirror_last_update_at, wait: 0)
last_update.has_text?('just now') || last_update.has_text?('seconds')
......
......@@ -27,6 +27,10 @@ module QA
attributes.each(&method(:public_send))
end
def wait(max: 60, interval: 0.1)
QA::Support::Waiter.wait(max: max, interval: interval)
end
private
def populate_attribute(name, block)
......
# frozen_string_literal: true
module QA
module Resource
module Events
MAX_WAIT = 10
EventNotFoundError = Class.new(RuntimeError)
module Base
def events(action: nil)
path = [api_get_events]
path << "?action=#{CGI.escape(action)}" if action
parse_body(api_get_from("#{path.join}"))
end
private
def api_get_events
"#{api_get_path}/events"
end
def wait_for_event
event_found = QA::Support::Waiter.wait(max: max_wait) do
yield
end
raise EventNotFoundError, "Timed out waiting for event" unless event_found
end
def max_wait
MAX_WAIT
end
end
end
end
end
# frozen_string_literal: true
module QA
module Resource
module Events
module Project
include Events::Base
def wait_for_push(commit_message)
QA::Runtime::Logger.debug(%Q[#{self.class.name} - wait_for_push with commit message "#{commit_message}"])
wait_for_event do
events(action: 'pushed').any? { |event| event.dig(:push_data, :commit_title) == commit_message }
end
end
def wait_for_push_new_branch(branch_name = "master")
QA::Runtime::Logger.debug(%Q[#{self.class.name} - wait_for_push_new_branch with branch_name "#{branch_name}"])
wait_for_event do
events(action: 'pushed').any? { |event| event.dig(:push_data, :ref) == branch_name }
end
end
end
end
end
end
......@@ -5,12 +5,12 @@ module QA
class Fork < Base
attribute :project do
Resource::Project.fabricate! do |resource|
resource.name = push.project.name
resource.path_with_namespace = "#{user.name}/#{push.project.name}"
resource.name = upstream.project.name
resource.path_with_namespace = "#{user.name}/#{upstream.project.name}"
end
end
attribute :push do
attribute :upstream do
Repository::ProjectPush.fabricate!
end
......@@ -24,7 +24,7 @@ module QA
end
def fabricate!
populate(:push, :user)
populate(:upstream, :user)
# Sign out as admin and sign is as the fork user
Page::Main::Menu.perform(&:sign_out)
......@@ -33,7 +33,7 @@ module QA
login.sign_in_using_credentials(user)
end
push.project.visit!
upstream.project.visit!
Page::Project::Show.perform(&:fork_project)
......
......@@ -33,7 +33,7 @@ module QA
end
# Ensure that the group was actually created
group_show.wait(time: 1) do
group_show.wait(interval: 1) do
group_show.has_text?(path) &&
group_show.has_new_project_or_subgroup_dropdown?
end
......
......@@ -58,10 +58,7 @@ module QA
populate(:target, :source)
project.visit!
Page::Project::Show.perform do |project|
project.wait_for_push
project.new_merge_request
end
Page::Project::Show.perform(&:new_merge_request)
Page::MergeRequest::New.perform do |page|
page.fill_title(@title)
page.fill_description(@description)
......
......@@ -5,6 +5,8 @@ require 'securerandom'
module QA
module Resource
class Project < Base
include Events::Project
attribute :name
attribute :description
......
......@@ -4,6 +4,8 @@ module QA
module Resource
module Repository
class ProjectPush < Repository::Push
attr_writer :wait_for_push
attribute :project do
Project.fabricate! do |resource|
resource.name = 'project-with-code'
......@@ -17,6 +19,7 @@ module QA
@commit_message = "This is a test commit"
@branch_name = 'master'
@new_branch = true
@wait_for_push = true
end
def repository_http_uri
......@@ -30,6 +33,7 @@ module QA
def fabricate!
super
project.visit!
project.wait_for_push @commit_message if @wait_for_push
end
end
end
......
......@@ -26,7 +26,6 @@ module QA
push.file_content = "Test with unicode characters ❤✓€❄"
end
Page::Project::Show.perform(&:wait_for_push)
merge_request.visit!
expect(page).to have_text('to be squashed')
......@@ -38,9 +37,7 @@ module QA
merge_request.project.visit!
Git::Repository.perform do |repository|
repository.uri = Page::Project::Show.act do
repository_clone_http_location.uri
end
repository.uri = merge_request.project.repository_http_location.uri
repository.use_default_credentials
......
......@@ -23,7 +23,6 @@ module QA
proj.name = 'project-qa-test'
proj.description = 'project for qa test'
end
project.visit!
Git::Repository.perform do |repository|
repository.uri = project.repository_http_location.uri
......@@ -53,7 +52,8 @@ module QA
push_changes(third_branch)
end
end
Page::Project::Show.perform(&:wait_for_push)
project.wait_for_push commit_message_of_third_branch
project.visit!
end
it 'branches are correctly listed after CRUD operations' do
......
......@@ -3,22 +3,18 @@
module QA
context 'Create' do
describe 'Git clone over HTTP', :ldap_no_tls do
let(:location) do
Page::Project::Show.perform(&:repository_clone_http_location).uri
end
before do
before(:all) do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
project = Resource::Project.fabricate! do |scenario|
@project = Resource::Project.fabricate! do |scenario|
scenario.name = 'project-with-code'
scenario.description = 'project for git clone tests'
end
project.visit!
@project.visit!
Git::Repository.perform do |repository|
repository.uri = location
repository.uri = @project.repository_http_location.uri
repository.use_default_credentials
repository.act do
......@@ -29,12 +25,12 @@ module QA
push_changes
end
end
Page::Project::Show.perform(&:wait_for_push)
@project.wait_for_push_new_branch
end
it 'user performs a deep clone' do
Git::Repository.perform do |repository|
repository.uri = location
repository.uri = @project.repository_http_location.uri
repository.use_default_credentials
repository.clone
......@@ -45,7 +41,7 @@ module QA
it 'user performs a shallow clone' do
Git::Repository.perform do |repository|
repository.uri = location
repository.uri = @project.repository_http_location.uri
repository.use_default_credentials
repository.shallow_clone
......
......@@ -35,7 +35,7 @@ module QA
end
project.visit!
Page::Project::Show.perform(&:wait_for_push)
project.wait_for_push_new_branch
# Check that the push worked
expect(page).to have_content(file_name)
......
......@@ -70,7 +70,7 @@ module QA
end
project.visit!
Page::Project::Show.perform(&:wait_for_push)
project.wait_for_push_new_branch
# Check that the push worked
expect(page).to have_content(file_name)
......
......@@ -23,10 +23,7 @@ module QA
push.project.visit!
Page::Project::Show.perform do |page|
page.wait_for_push
page.wait_for_viewers_to_load
end
Page::Project::Show.perform(&:wait_for_viewers_to_load)
expect(page).to have_content('README.md')
expect(page).to have_content('This is a test project')
......
......@@ -20,8 +20,6 @@ module QA
end
source_project_push.project.visit!
Page::Project::Show.perform(&:wait_for_push)
Page::Project::Menu.perform(&:click_repository_settings)
Page::Project::Settings::Repository.perform do |settings|
settings.expand_mirroring_repositories do |mirror_settings|
......
......@@ -31,7 +31,7 @@ module QA
set_file_size_limit(5)
expect(page).to have_content("Application settings saved successfully")
push = push_new_file('oversize_file_1.bin')
push = push_new_file('oversize_file_1.bin', wait_for_push: true)
expect(push.output).not_to have_content 'remote: fatal: pack exceeds maximum allowed size'
end
......@@ -39,7 +39,7 @@ module QA
set_file_size_limit(1)
expect(page).to have_content("Application settings saved successfully")
push = push_new_file('oversize_file_2.bin')
push = push_new_file('oversize_file_2.bin', wait_for_push: false)
expect(push.output).to have_content 'remote: fatal: pack exceeds maximum allowed size'
end
......@@ -55,7 +55,7 @@ module QA
end
end
def push_new_file(file_name)
def push_new_file(file_name, wait_for_push: true)
@project.visit!
Resource::Repository::ProjectPush.fabricate! do |p|
......@@ -63,6 +63,7 @@ module QA
p.file_name = file_name
p.file_content = SecureRandom.random_bytes(2000000)
p.commit_message = 'Adding a new file'
p.wait_for_push = wait_for_push
end
end
end
......
......@@ -5,7 +5,7 @@ module QA
describe 'Git push over HTTP', :ldap_no_tls do
it 'user pushes code to the repository' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
Page::Main::Login.perform(&:sign_in_using_credentials)
project_push = Resource::Repository::ProjectPush.fabricate! do |push|
push.file_name = 'README.md'
......@@ -13,7 +13,6 @@ module QA
push.commit_message = 'Add README.md'
end
project_push.project.visit!
Page::Project::Show.act { wait_for_push }
expect(page).to have_content('README.md')
expect(page).to have_content('This is a test project')
......
......@@ -63,6 +63,7 @@ module QA
resource.commit_message = 'Add new_file.md'
resource.branch_name = branch_name
resource.new_branch = false
resource.wait_for_push = false
end
end
end
......
......@@ -10,7 +10,7 @@ module QA
it 'user adds an ssh key and pushes code to the repository' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
Page::Main::Login.perform(&:sign_in_using_credentials)
key = Resource::SSHKey.fabricate! do |resource|
resource.title = key_title
......@@ -24,13 +24,12 @@ module QA
end
project_push.project.visit!
Page::Project::Show.act { wait_for_push }
expect(page).to have_content('README.md')
expect(page).to have_content('Test Use SSH Key')
Page::Main::Menu.act { go_to_profile_settings }
Page::Profile::Menu.act { click_ssh_keys }
Page::Main::Menu.perform(&:go_to_profile_settings)
Page::Profile::Menu.perform(&:click_ssh_keys)
Page::Profile::SSHKeys.perform do |ssh_keys|
ssh_keys.remove_key(key_title)
......
......@@ -11,7 +11,7 @@ module QA
it 'users creates a pipeline which gets processed' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
Page::Main::Login.perform(&:sign_in_using_credentials)
project = Resource::Project.fabricate! do |project|
project.name = 'project-with-pipelines'
......@@ -60,11 +60,9 @@ module QA
EOF
end
Page::Project::Show.act { wait_for_push }
expect(page).to have_content('Add .gitlab-ci.yml')
Page::Project::Menu.act { click_ci_cd_pipelines }
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
expect(page).to have_content('All 1')
expect(page).to have_content('Add .gitlab-ci.yml')
......@@ -72,7 +70,7 @@ module QA
puts 'Waiting for the runner to process the pipeline'
sleep 15 # Runner should process all jobs within 15 seconds.
Page::Project::Pipeline::Index.act { go_to_latest_pipeline }
Page::Project::Pipeline::Index.perform(&:go_to_latest_pipeline)
Page::Project::Pipeline::Show.perform do |pipeline|
expect(pipeline).to be_running
......
......@@ -8,7 +8,7 @@ module QA
describe 'Git clone using a deploy key' do
def login
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
Page::Main::Login.perform(&:sign_in_using_credentials)
end
before(:all) do
......@@ -29,7 +29,7 @@ module QA
resource.image = 'gitlab/gitlab-runner:ubuntu'
end
Page::Main::Menu.act { sign_out }
Page::Main::Menu.perform(&:sign_out)
end
after(:all) do
......@@ -90,10 +90,9 @@ module QA
sha1sum = Digest::SHA1.hexdigest(gitlab_ci)
Page::Project::Show.act { wait_for_push }
Page::Project::Menu.act { click_ci_cd_pipelines }
Page::Project::Pipeline::Index.act { go_to_latest_pipeline }
Page::Project::Pipeline::Show.act { go_to_first_job }
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:go_to_latest_pipeline)
Page::Project::Pipeline::Show.perform(&:go_to_first_job)
Page::Project::Job::Show.perform do |job|
expect(job).to be_successful, "Job status did not become \"passed\"."
......
......@@ -8,7 +8,7 @@ module QA
describe 'Auto DevOps support' do
def login
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
Page::Main::Login.perform(&:sign_in_using_credentials)
end
[true, false].each do |rbac|
......@@ -38,8 +38,6 @@ module QA
push.commit_message = 'Create Auto DevOps compatible rack application'
end
Page::Project::Show.act { wait_for_push }
# Create and connect K8s cluster
@cluster = Service::KubernetesCluster.new(rbac: rbac).create!
kubernetes_cluster = Resource::KubernetesCluster.fabricate! do |cluster|
......@@ -53,7 +51,7 @@ module QA
kubernetes_cluster.populate(:ingress_ip)
@project.visit!
Page::Project::Menu.act { click_ci_cd_settings }
Page::Project::Menu.perform(&:click_ci_cd_settings)
Page::Project::Settings::CICD.perform do |p|
p.enable_auto_devops
end
......@@ -71,8 +69,8 @@ module QA
it 'runs auto devops' do
@project.visit!
Page::Project::Menu.act { click_ci_cd_pipelines }
Page::Project::Pipeline::Index.act { go_to_latest_pipeline }
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:go_to_latest_pipeline)
Page::Project::Pipeline::Show.perform do |pipeline|
pipeline.go_to_job('build')
......@@ -101,7 +99,7 @@ module QA
job.click_element(:pipeline_path)
end
Page::Project::Menu.act { click_operations_environments }
Page::Project::Menu.perform(&:click_operations_environments)
Page::Project::Operations::Environments::Index.perform do |index|
index.go_to_environment('production')
end
......@@ -132,8 +130,8 @@ module QA
end
@project.visit!
Page::Project::Menu.act { click_ci_cd_pipelines }
Page::Project::Pipeline::Index.act { go_to_latest_pipeline }
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:go_to_latest_pipeline)
Page::Project::Pipeline::Show.perform do |pipeline|
pipeline.go_to_job('build')
......@@ -162,7 +160,7 @@ module QA
job.click_element(:pipeline_path)
end
Page::Project::Menu.act { click_operations_environments }
Page::Project::Menu.perform(&:click_operations_environments)
Page::Project::Operations::Environments::Index.perform do |index|
index.go_to_environment('production')
......
......@@ -10,15 +10,11 @@ module QA
super
end
def wait(max: 60, time: 0.1, reload: true)
log("with wait: max #{max}; time #{time}; reload #{reload}")
now = Time.now
element = super
def wait(max: 60, interval: 0.1, reload: true)
log("next wait uses reload: #{reload}")
# Logging of wait start/end/duration is handled by QA::Support::Waiter
log("ended wait after #{Time.now - now} seconds")
element
super
end
def scroll_to(selector, text: nil)
......
# frozen_string_literal: true
module QA
module Support
module Waiter
module_function
def wait(max: 60, interval: 0.1)
QA::Runtime::Logger.debug("with wait: max #{max}; interval #{interval}")
start = Time.now
while Time.now - start < max
result = yield
if result
log_end(Time.now - start)
return result
end
sleep(interval)
end
log_end(Time.now - start)
false
end
def self.log_end(duration)
QA::Runtime::Logger.debug("ended wait after #{duration} seconds")
end
end
end
end
describe QA::Git::Repository do
include Support::StubENV
include Helpers::StubENV
shared_context 'git directory' do
let(:repository) { described_class.new }
......
# Inspired by https://github.com/ljkbennett/stub_env/blob/master/lib/stub_env/helpers.rb
module Support
module Helpers
module StubENV
def stub_env(key_or_hash, value = nil)
init_stub unless env_stubbed?
......
......@@ -59,4 +59,34 @@ describe QA::Page::Base do
end
end
end
describe '#wait' do
subject { Class.new(described_class).new }
context 'when the condition is true' do
it 'does not refresh' do
expect(subject).not_to receive(:refresh)
subject.wait(max: 0.01) { true }
end
it 'returns true' do
expect(subject.wait(max: 0.1) { true }).to be_truthy
end
end
context 'when the condition is false' do
it 'refreshes' do
expect(subject).to receive(:refresh).at_least(:once)
subject.wait(max: 0.01) { false }
end
it 'returns false' do
allow(subject).to receive(:refresh)
expect(subject.wait(max: 0.01) { false }).to be_falsey
end
end
end
end
......@@ -4,8 +4,6 @@ require 'capybara/dsl'
require 'logger'
describe QA::Support::Page::Logging do
include Support::StubENV
let(:page) { double.as_null_object }
before do
......@@ -30,12 +28,23 @@ describe QA::Support::Page::Logging do
end
it 'logs wait' do
expect { subject.wait(max: 0) {} }
.to output(/next wait uses reload: true/).to_stdout_from_any_process
expect { subject.wait(max: 0) {} }
.to output(/with wait/).to_stdout_from_any_process
expect { subject.wait(max: 0) {} }
.to output(/ended wait after .* seconds$/).to_stdout_from_any_process
end
it 'logs wait with reload false' do
expect { subject.wait(max: 0, reload: false) {} }
.to output(/next wait uses reload: false/).to_stdout_from_any_process
expect { subject.wait(max: 0, reload: false) {} }
.to output(/with wait/).to_stdout_from_any_process
expect { subject.wait(max: 0, reload: false) {} }
.to output(/ended wait after .* seconds$/).to_stdout_from_any_process
end
it 'logs scroll_to' do
expect { subject.scroll_to(:element) }
.to output(/scrolling to :element/).to_stdout_from_any_process
......
# frozen_string_literal: true
describe QA::Resource::Base do
include Support::StubENV
include Helpers::StubENV
let(:resource) { spy('resource') }
let(:location) { 'http://location' }
......
# frozen_string_literal: true
describe QA::Resource::Events::Base do
let(:resource) do
Class.new(QA::Resource::Base) do
def api_get_path
'/foo'
end
end
end
subject { resource.tap { |f| f.include(described_class) }.new }
describe "#events" do
it 'fetches all events when called without parameters' do
allow(subject).to receive(:parse_body).and_return('returned')
expect(subject).to receive(:api_get_from).with('/foo/events')
expect(subject.events).to eq('returned')
end
it 'fetches events with a specified action type' do
allow(subject).to receive(:parse_body).and_return('returned')
expect(subject).to receive(:api_get_from).with('/foo/events?action=pushed')
expect(subject.events(action: 'pushed')).to eq('returned')
end
end
end
# frozen_string_literal: true
describe QA::Resource::Events::Project do
let(:resource) do
Class.new(QA::Resource::Base) do
def api_get_path
'/foo'
end
end
end
let(:all_events) do
[
{
"action_name": "pushed",
"push_data": {
"commit_title": "foo commit"
}
},
{
"action_name": "pushed",
"push_data": {
"ref": "master"
}
},
{
"action_name": "pushed",
"push_data": {
"ref": "another-branch"
}
}
]
end
before do
allow(subject).to receive(:max_wait).and_return(0.01)
allow(subject).to receive(:parse_body).and_return(all_events)
end
subject { resource.tap { |f| f.include(described_class) }.new }
describe "#wait_for_push" do
it 'waits for a push with a specified commit message' do
expect(subject).to receive(:api_get_from).with('/foo/events?action=pushed')
expect { subject.wait_for_push('foo commit') }.not_to raise_error
end
it 'raises an error if a push with the specified commit message is not found' do
expect(subject).to receive(:api_get_from).with('/foo/events?action=pushed').at_least(:once)
expect { subject.wait_for_push('bar') }.to raise_error(QA::Resource::Events::EventNotFoundError)
end
end
describe "#wait_for_push_new_branch" do
it 'waits for a push to master if no branch is given' do
expect(subject).to receive(:api_get_from).with('/foo/events?action=pushed')
expect { subject.wait_for_push_new_branch }.not_to raise_error
end
it 'waits for a push to the given branch' do
expect(subject).to receive(:api_get_from).with('/foo/events?action=pushed')
expect { subject.wait_for_push_new_branch('another-branch') }.not_to raise_error
end
it 'raises an error if a push with the specified branch is not found' do
expect(subject).to receive(:api_get_from).with('/foo/events?action=pushed').at_least(:once)
expect { subject.wait_for_push_new_branch('bar') }.to raise_error(QA::Resource::Events::EventNotFoundError)
end
end
end
describe QA::Runtime::API::Client do
include Support::StubENV
include Helpers::StubENV
describe 'initialization' do
it 'defaults to :gitlab address' do
......
# frozen_string_literal: true
describe QA::Runtime::Env do
include Support::StubENV
include Helpers::StubENV
shared_examples 'boolean method' do |**kwargs|
it_behaves_like 'boolean method with parameter', kwargs
......
require_relative '../qa'
Dir[::File.join(__dir__, 'support', '**', '*.rb')].each { |f| require f }
%w[helpers shared_examples].each do |d|
Dir[::File.join(__dir__, d, '**', '*.rb')].each { |f| require f }
end
RSpec.configure do |config|
ServerNotRespondingError = Class.new(RuntimeError)
......
# frozen_string_literal: true
require 'logger'
describe QA::Support::Waiter do
before do
logger = ::Logger.new $stdout
logger.level = ::Logger::DEBUG
QA::Runtime::Logger.logger = logger
end
describe '.wait' do
context 'when the condition is true' do
it 'logs the start' do
expect { subject.wait(max: 0) {} }
.to output(/with wait: max 0; interval 0.1/).to_stdout_from_any_process
end
it 'logs the end' do
expect { subject.wait(max: 0) {} }
.to output(/ended wait after .* seconds$/).to_stdout_from_any_process
end
end
context 'when the condition is false' do
it 'logs the start' do
expect { subject.wait(max: 0) { false } }
.to output(/with wait: max 0; interval 0.1/).to_stdout_from_any_process
end
it 'logs the end' do
expect { subject.wait(max: 0) { false } }
.to output(/ended wait after .* seconds$/).to_stdout_from_any_process
end
end
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册