First pass at new automated QA API test for #52703

Checks that archives of two different user projects with the same name aren't the same via checksum.  I.E. a user can't download the archive of another's project by mistake.

To enable the test some enhancements were made.  Namely updating the client module to handle more than one API instance and the creation a custom rest call method that downloads to tmp.
This commit is contained in:
Grant Young 2019-07-01 06:01:44 +00:00 committed by Mark Lapierre
parent 58f3a56154
commit eecd85d461
8 changed files with 151 additions and 23 deletions

View File

@ -13,6 +13,8 @@ module QA
ResourceURLMissingError = Class.new(RuntimeError)
attr_reader :api_resource, :api_response
attr_writer :api_client
attr_accessor :user
def api_support?
respond_to?(:api_get_path) &&
@ -29,9 +31,12 @@ module QA
end
def eager_load_api_client!
return unless api_client.nil?
api_client.tap do |client|
# Eager-load the API client so that the personal token creation isn't
# taken in account in the actual resource creation timing.
client.user = user
client.personal_access_token
end
end
@ -76,7 +81,7 @@ module QA
def api_client
@api_client ||= begin
Runtime::API::Client.new(:gitlab, is_new_session: !current_url.start_with?('http'))
Runtime::API::Client.new(:gitlab, is_new_session: !current_url.start_with?('http'), user: user)
end
end

View File

@ -21,7 +21,7 @@ module QA
def fabricate!
populate(:push)
fork.visit!
fork.project.visit!
Page::Project::Show.perform(&:new_merge_request)
Page::MergeRequest::New.perform(&:create_merge_request)

View File

@ -11,7 +11,9 @@ module QA
attribute :id
attribute :name
attribute :add_name_uuid
attribute :description
attribute :standalone
attribute :group do
Group.fabricate!
@ -38,18 +40,21 @@ module QA
end
def initialize
@add_name_uuid = true
@standalone = false
@description = 'My awesome project'
@initialize_with_readme = false
end
def name=(raw_name)
@name = "#{raw_name}-#{SecureRandom.hex(8)}"
@name = @add_name_uuid ? "#{raw_name}-#{SecureRandom.hex(8)}" : raw_name
end
def fabricate!
group.visit!
Page::Group::Show.perform(&:go_to_new_project)
unless @standalone
group.visit!
Page::Group::Show.perform(&:go_to_new_project)
end
Page::Project::New.perform do |page|
page.choose_test_namespace
@ -71,19 +76,28 @@ module QA
"/projects/#{CGI.escape(path_with_namespace)}"
end
def api_get_archive_path(type = 'tar.gz')
"#{api_get_path}/repository/archive.#{type}"
end
def api_post_path
'/projects'
end
def api_post_body
{
namespace_id: group.id,
path: name,
post_body = {
name: name,
description: description,
visibility: 'public',
initialize_with_readme: @initialize_with_readme
}
unless @standalone
post_body[:namespace_id] = group.id
post_body[:path] = name
end
post_body
end
private

View File

@ -88,7 +88,7 @@ module QA
}.merge(ldap_post_body)
end
def self.fabricate_or_use(username, password)
def self.fabricate_or_use(username = nil, password = nil)
if Runtime::Env.signup_disabled?
self.new.tap do |user|
user.username = username

View File

@ -6,31 +6,34 @@ module QA
module Runtime
module API
class Client
attr_reader :address
attr_reader :address, :user
def initialize(address = :gitlab, personal_access_token: nil, is_new_session: true)
def initialize(address = :gitlab, personal_access_token: nil, is_new_session: true, user: nil)
@address = address
@personal_access_token = personal_access_token
@is_new_session = is_new_session
@user = user
end
def personal_access_token
@personal_access_token ||= begin
# you can set the environment variable GITLAB_QA_ACCESS_TOKEN
# to use a specific access token rather than create one from the UI
Runtime::Env.personal_access_token ||= create_personal_access_token
# unless a specific user has been passed
@user.nil? ? Runtime::Env.personal_access_token ||= create_personal_access_token : create_personal_access_token
end
end
private
def create_personal_access_token
Runtime::Browser.visit(@address, Page::Main::Login) if @is_new_session
do_create_personal_access_token
end
Page::Main::Menu.perform(&:sign_out) if @is_new_session && Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) }
unless Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) }
Runtime::Browser.visit(@address, Page::Main::Login)
Page::Main::Login.perform { |login| login.sign_in_using_credentials(@user) }
end
def do_create_personal_access_token
Page::Main::Login.perform(&:sign_in_using_credentials)
Resource::PersonalAccessToken.fabricate!.access_token
end
end

View File

@ -0,0 +1,75 @@
# frozen_string_literal: true
require 'securerandom'
require 'digest'
module QA
context 'Create' do
describe 'Compare archives of different user projects with the same name and check they\'re different' do
include Support::Api
before(:all) do
@project_name = "project-archive-download-#{SecureRandom.hex(8)}"
@archive_types = %w(tar.gz tar.bz2 tar zip)
@users = {
user1: { username: Runtime::Env.gitlab_qa_username_1, password: Runtime::Env.gitlab_qa_password_1 },
user2: { username: Runtime::Env.gitlab_qa_username_2, password: Runtime::Env.gitlab_qa_password_2 }
}
@users.each do |_, user_info|
user_info[:user] = Resource::User.fabricate_or_use(user_info[:username], user_info[:password])
user_info[:api_client] = Runtime::API::Client.new(:gitlab, user: user_info[:user])
user_info[:api_client].personal_access_token
user_info[:project] = create_project(user_info[:user], user_info[:api_client], @project_name)
Page::Main::Menu.perform(&:sign_out)
end
end
it 'download archives of each user project then check they are different' do
archive_checksums = {}
@users.each do |user_key, user_info|
archive_checksums[user_key] = {}
@archive_types.each do |type|
archive_path = download_project_archive_via_api(user_info[:api_client], user_info[:project], type).path
archive_checksums[user_key][type] = Digest::MD5.hexdigest(File.read(archive_path))
end
end
QA::Runtime::Logger.debug("Archive checksums are #{archive_checksums}")
expect(archive_checksums[:user1]).not_to include(archive_checksums[:user2])
end
def create_project(user, api_client, project_name)
project = Resource::Project.fabricate! do |project|
project.standalone = true
project.add_name_uuid = false
project.name = project_name
project.path_with_namespace = "#{user.name}/#{project_name}"
project.user = user
project.api_client = api_client
end
Resource::Repository::ProjectPush.fabricate! do |push|
push.project = project
push.file_name = 'README.md'
push.file_content = '# This is a test project'
push.commit_message = 'Add README.md'
push.user = user
end
project
end
def download_project_archive_via_api(api_client, project, type = 'tar.gz')
get_project_archive_zip = Runtime::API::Request.new(api_client, project.api_get_archive_path(type))
project_archive_download = get(get_project_archive_zip.url, raw_response: true)
expect(project_archive_download.code).to eq(200)
project_archive_download.file
end
end
end
end

View File

@ -16,11 +16,12 @@ module QA
e.response
end
def get(url)
def get(url, raw_response: false)
RestClient::Request.execute(
method: :get,
url: url,
verify_ssl: false)
verify_ssl: false,
raw_response: raw_response)
rescue RestClient::ExceptionWithResponse => e
e.response
end

View File

@ -16,26 +16,56 @@ describe QA::Runtime::API::Client do
end
describe '#personal_access_token' do
context 'when QA::Runtime::Env.personal_access_token is present' do
context 'when user is nil and QA::Runtime::Env.personal_access_token is present' do
before do
allow(QA::Runtime::Env).to receive(:personal_access_token).and_return('a_token')
end
it 'returns specified token from env' do
expect(described_class.new.personal_access_token).to eq 'a_token'
expect(subject.personal_access_token).to eq 'a_token'
end
end
context 'when QA::Runtime::Env.personal_access_token is nil' do
context 'when user is present and QA::Runtime::Env.personal_access_token is nil' do
before do
allow(QA::Runtime::Env).to receive(:personal_access_token).and_return(nil)
end
it 'returns a created token' do
subject { described_class.new(user: { username: 'foo' }) }
expect(subject).to receive(:create_personal_access_token).and_return('created_token')
expect(subject.personal_access_token).to eq 'created_token'
end
end
context 'when user is nil and QA::Runtime::Env.personal_access_token is nil' do
before do
allow(QA::Runtime::Env).to receive(:personal_access_token).and_return(nil)
end
it 'returns a created token' do
client = described_class.new
expect(client).to receive(:create_personal_access_token).and_return('created_token')
expect(client.personal_access_token).to eq 'created_token'
end
end
context 'when user is present and QA::Runtime::Env.personal_access_token is present' do
before do
allow(QA::Runtime::Env).to receive(:personal_access_token).and_return('a_token')
end
it 'returns a created token' do
client = described_class.new(user: { username: 'foo' })
expect(client).to receive(:create_personal_access_token).and_return('created_token')
expect(client.personal_access_token).to eq 'created_token'
end
end
end
end