Merge branch 'ml-qa-git-protocol-v2-spec' into 'master'

Add e2e test of push over SSH using Git protocol v2

See merge request gitlab-org/gitlab-ce!22548
This commit is contained in:
Nick Thomas 2018-11-08 00:13:51 +00:00
commit 068e75f660
7 changed files with 211 additions and 13 deletions

View File

@ -109,6 +109,28 @@ module QA
known_hosts_file.close(true) known_hosts_file.close(true)
end end
def push_with_git_protocol(version, file_name, file_content, commit_message = 'Initial commit')
self.git_protocol = version
add_file(file_name, file_content)
commit(commit_message)
push_changes
fetch_supported_git_protocol
end
def git_protocol=(value)
raise ArgumentError, "Please specify the protocol you would like to use: 0, 1, or 2" unless %w[0 1 2].include?(value.to_s)
run("git config protocol.version #{value}")
end
def fetch_supported_git_protocol
# ls-remote is one command known to respond to Git protocol v2 so we use
# it to get output including the version reported via Git tracing
output = run("git ls-remote #{uri}", "GIT_TRACE_PACKET=1")
output[/git< version (\d+)/, 1] || 'unknown'
end
private private
attr_reader :uri, :username, :password, :known_hosts_file, :private_key_file attr_reader :uri, :username, :password, :known_hosts_file, :private_key_file
@ -117,8 +139,8 @@ module QA
!private_key_file.nil? !private_key_file.nil?
end end
def run(command_str) def run(command_str, *extra_env)
command = [env_vars, command_str, '2>&1'].compact.join(' ') command = [env_vars, *extra_env, command_str, '2>&1'].compact.join(' ')
Runtime::Logger.debug "Git: command=[#{command}]" Runtime::Logger.debug "Git: command=[#{command}]"
output, _ = Open3.capture2(command) output, _ = Open3.capture2(command)

View File

@ -7,6 +7,16 @@ module QA
attr_writer :personal_access_token attr_writer :personal_access_token
# The environment variables used to indicate if the environment under test
# supports the given feature
SUPPORTED_FEATURES = {
git_protocol_v2: 'QA_CAN_TEST_GIT_PROTOCOL_V2'
}.freeze
def supported_features
SUPPORTED_FEATURES
end
def debug? def debug?
enabled?(ENV['QA_DEBUG'], default: false) enabled?(ENV['QA_DEBUG'], default: false)
end end
@ -104,6 +114,15 @@ module QA
raise ArgumentError, "Please provide GITHUB_ACCESS_TOKEN" raise ArgumentError, "Please provide GITHUB_ACCESS_TOKEN"
end end
# Returns true if there is an environment variable that indicates that
# the feature is supported in the environment under test.
# All features are supported by default.
def can_test?(feature)
raise ArgumentError, %Q(Unknown feature "#{feature}") unless SUPPORTED_FEATURES.include? feature
enabled?(ENV[SUPPORTED_FEATURES[feature]], default: true)
end
private private
def enabled?(value, default: true) def enabled?(value, default: true)

View File

@ -0,0 +1,84 @@
# frozen_string_literal: true
module QA
context 'Create' do
describe 'Push over SSH using Git protocol version 2', :requires_git_protocol_v2 do
# Note: If you run this test against GDK make sure you've enabled sshd and
# enabled setting the Git protocol by adding `AcceptEnv GIT_PROTOCOL` to
# `sshd_config`
# See: https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/run_qa_against_gdk.md
let(:key_title) { "key for ssh tests #{Time.now.to_f}" }
let(:ssh_key) do
Factory::Resource::SSHKey.fabricate! do |resource|
resource.title = key_title
end
end
def login
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
end
around do |example|
# Create an SSH key to be used with Git
login
ssh_key
example.run
# Remove the SSH key
login
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)
end
end
it 'user pushes to the repository' do
# Create a project to push to
project = Factory::Resource::Project.fabricate! do |project|
project.name = 'git-protocol-project'
end
file_name = 'README.md'
file_content = 'Test Git protocol v2'
git_protocol = '2'
git_protocol_reported = nil
# Use Git to clone the project, push a file to it, and then check the
# supported Git protocol
Git::Repository.perform do |repository|
username = 'GitLab QA'
email = 'root@gitlab.com'
repository.uri = project.repository_ssh_location.uri
begin
repository.use_ssh_key(ssh_key)
repository.clone
repository.configure_identity(username, email)
git_protocol_reported = repository.push_with_git_protocol(
git_protocol,
file_name,
file_content)
ensure
repository.delete_ssh_key
end
end
project.visit!
Page::Project::Show.perform(&:wait_for_push)
# Check that the push worked
expect(page).to have_content(file_name)
expect(page).to have_content(file_content)
# And check that the correct Git protocol was used
expect(git_protocol_reported).to eq(git_protocol)
end
end
end
end

View File

@ -25,6 +25,10 @@ module QA
args.push(%w[--tag ~skip_signup_disabled]) if QA::Runtime::Env.signup_disabled? args.push(%w[--tag ~skip_signup_disabled]) if QA::Runtime::Env.signup_disabled?
QA::Runtime::Env.supported_features.each_key do |key|
args.push(["--tag", "~requires_#{key}"]) unless QA::Runtime::Env.can_test? key
end
args.push(options) args.push(options)
args.push(DEFAULT_TEST_PATH_ARGS) unless options.any? { |opt| opt =~ %r{/features/} } args.push(DEFAULT_TEST_PATH_ARGS) unless options.any? { |opt| opt =~ %r{/features/} }

View File

@ -26,6 +26,36 @@ describe QA::Git::Repository do
end end
end end
describe '#git_protocol=' do
[0, 1, 2].each do |version|
it "configures git to use protocol version #{version}" do
expect(repository).to receive(:run).with("git config protocol.version #{version}")
repository.git_protocol = version
end
end
it 'raises an error if the version is unsupported' do
expect { repository.git_protocol = 'foo' }.to raise_error(ArgumentError, "Please specify the protocol you would like to use: 0, 1, or 2")
end
end
describe '#fetch_supported_git_protocol' do
it "reports the detected version" do
expect(repository).to receive(:run).and_return("packet: git< version 2")
expect(repository.fetch_supported_git_protocol).to eq('2')
end
it 'reports unknown if version is unknown' do
expect(repository).to receive(:run).and_return("packet: git< version -1")
expect(repository.fetch_supported_git_protocol).to eq('unknown')
end
it 'reports unknown if content does not identify a version' do
expect(repository).to receive(:run).and_return("foo")
expect(repository.fetch_supported_git_protocol).to eq('unknown')
end
end
def cd_empty_temp_directory def cd_empty_temp_directory
tmp_dir = 'tmp/git-repository-spec/' tmp_dir = 'tmp/git-repository-spec/'
FileUtils.rm_rf(tmp_dir) if ::File.exist?(tmp_dir) FileUtils.rm_rf(tmp_dir) if ::File.exist?(tmp_dir)

View File

@ -3,49 +3,62 @@
describe QA::Runtime::Env do describe QA::Runtime::Env do
include Support::StubENV include Support::StubENV
shared_examples 'boolean method' do |method, env_key, default| shared_examples 'boolean method' do |**kwargs|
it_behaves_like 'boolean method with parameter', kwargs
end
shared_examples 'boolean method with parameter' do |method:, param: nil, env_key:, default:|
context 'when there is an env variable set' do context 'when there is an env variable set' do
it 'returns false when falsey values specified' do it 'returns false when falsey values specified' do
stub_env(env_key, 'false') stub_env(env_key, 'false')
expect(described_class.public_send(method)).to be_falsey expect(described_class.public_send(method, *param)).to be_falsey
stub_env(env_key, 'no') stub_env(env_key, 'no')
expect(described_class.public_send(method)).to be_falsey expect(described_class.public_send(method, *param)).to be_falsey
stub_env(env_key, '0') stub_env(env_key, '0')
expect(described_class.public_send(method)).to be_falsey expect(described_class.public_send(method, *param)).to be_falsey
end end
it 'returns true when anything else specified' do it 'returns true when anything else specified' do
stub_env(env_key, 'true') stub_env(env_key, 'true')
expect(described_class.public_send(method)).to be_truthy expect(described_class.public_send(method, *param)).to be_truthy
stub_env(env_key, '1') stub_env(env_key, '1')
expect(described_class.public_send(method)).to be_truthy expect(described_class.public_send(method, *param)).to be_truthy
stub_env(env_key, 'anything') stub_env(env_key, 'anything')
expect(described_class.public_send(method)).to be_truthy expect(described_class.public_send(method, *param)).to be_truthy
end end
end end
context 'when there is no env variable set' do context 'when there is no env variable set' do
it "returns the default, #{default}" do it "returns the default, #{default}" do
stub_env(env_key, nil) stub_env(env_key, nil)
expect(described_class.public_send(method)).to be(default) expect(described_class.public_send(method, *param)).to be(default)
end end
end end
end end
describe '.signup_disabled?' do describe '.signup_disabled?' do
it_behaves_like 'boolean method', :signup_disabled?, 'SIGNUP_DISABLED', false it_behaves_like 'boolean method',
method: :signup_disabled?,
env_key: 'SIGNUP_DISABLED',
default: false
end end
describe '.debug?' do describe '.debug?' do
it_behaves_like 'boolean method', :debug?, 'QA_DEBUG', false it_behaves_like 'boolean method',
method: :debug?,
env_key: 'QA_DEBUG',
default: false
end end
describe '.chrome_headless?' do describe '.chrome_headless?' do
it_behaves_like 'boolean method', :chrome_headless?, 'CHROME_HEADLESS', true it_behaves_like 'boolean method',
method: :chrome_headless?,
env_key: 'CHROME_HEADLESS',
default: true
end end
describe '.running_in_ci?' do describe '.running_in_ci?' do
@ -182,4 +195,16 @@ describe QA::Runtime::Env do
expect(described_class.log_destination).to eq('path/to_file') expect(described_class.log_destination).to eq('path/to_file')
end end
end end
describe '.can_test?' do
it_behaves_like 'boolean method with parameter',
method: :can_test?,
param: :git_protocol_v2,
env_key: 'QA_CAN_TEST_GIT_PROTOCOL_V2',
default: true
it 'raises ArgumentError if feature is unknown' do
expect { described_class.can_test? :foo }.to raise_error(ArgumentError, 'Unknown feature "foo"')
end
end
end end

View File

@ -76,6 +76,20 @@ describe QA::Specs::Runner do
end end
end end
context 'when git protocol v2 is not supported' do
before do
allow(QA::Runtime::Env).to receive(:can_test?).with(:git_protocol_v2).and_return(false)
end
subject { described_class.new }
it 'it includes default args and excludes the requires_git_protocol_v2 tag' do
expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~requires_git_protocol_v2', *described_class::DEFAULT_TEST_PATH_ARGS])
subject.perform
end
end
def expect_rspec_runner_arguments(arguments) def expect_rspec_runner_arguments(arguments)
expect(RSpec::Core::Runner).to receive(:run) expect(RSpec::Core::Runner).to receive(:run)
.with(arguments, $stderr, $stdout) .with(arguments, $stderr, $stdout)