diff options
author | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2017-02-20 12:45:04 +0100 |
---|---|---|
committer | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2017-03-09 10:36:27 +0100 |
commit | 7d20e47622c9a6e0a780bdbe9b53c8890c00deba (patch) | |
tree | 9650b8b1d1edde4b92a748a9ee9ab5c4e4c1ba5c /qa/qa | |
parent | 72e940df2c24ab80056dfe296011c7a44ebdf3f0 (diff) | |
download | gitlab-ce-7d20e47622c9a6e0a780bdbe9b53c8890c00deba.tar.gz |
Add GitLab QA integrations tests to GitLab CE / EE
Diffstat (limited to 'qa/qa')
-rw-r--r-- | qa/qa/git/repository.rb | 71 | ||||
-rw-r--r-- | qa/qa/page/admin/license.rb | 20 | ||||
-rw-r--r-- | qa/qa/page/admin/menu.rb | 19 | ||||
-rw-r--r-- | qa/qa/page/base.rb | 12 | ||||
-rw-r--r-- | qa/qa/page/main/entry.rb | 26 | ||||
-rw-r--r-- | qa/qa/page/main/groups.rb | 20 | ||||
-rw-r--r-- | qa/qa/page/main/menu.rb | 46 | ||||
-rw-r--r-- | qa/qa/page/main/projects.rb | 16 | ||||
-rw-r--r-- | qa/qa/page/project/new.rb | 24 | ||||
-rw-r--r-- | qa/qa/page/project/show.rb | 23 | ||||
-rw-r--r-- | qa/qa/runtime/namespace.rb | 15 | ||||
-rw-r--r-- | qa/qa/runtime/user.rb | 15 | ||||
-rw-r--r-- | qa/qa/scenario/actable.rb | 23 | ||||
-rw-r--r-- | qa/qa/scenario/gitlab/license/add.rb | 21 | ||||
-rw-r--r-- | qa/qa/scenario/gitlab/project/create.rb | 31 | ||||
-rw-r--r-- | qa/qa/scenario/template.rb | 16 | ||||
-rw-r--r-- | qa/qa/scenario/test/instance.rb | 27 | ||||
-rw-r--r-- | qa/qa/specs/config.rb | 78 | ||||
-rw-r--r-- | qa/qa/specs/features/login/standard_spec.rb | 14 | ||||
-rw-r--r-- | qa/qa/specs/features/project/create_spec.rb | 19 | ||||
-rw-r--r-- | qa/qa/specs/features/repository/clone_spec.rb | 57 | ||||
-rw-r--r-- | qa/qa/specs/features/repository/push_spec.rb | 39 | ||||
-rw-r--r-- | qa/qa/specs/runner.rb | 15 |
23 files changed, 647 insertions, 0 deletions
diff --git a/qa/qa/git/repository.rb b/qa/qa/git/repository.rb new file mode 100644 index 00000000000..b9e199000d6 --- /dev/null +++ b/qa/qa/git/repository.rb @@ -0,0 +1,71 @@ +require 'uri' + +module QA + module Git + class Repository + include Scenario::Actable + + def self.perform(*args) + Dir.mktmpdir do |dir| + Dir.chdir(dir) { super } + end + end + + def location=(address) + @location = address + @uri = URI(address) + end + + def username=(name) + @username = name + @uri.user = name + end + + def password=(pass) + @password = pass + @uri.password = pass + end + + def use_default_credentials + self.username = Runtime::User.name + self.password = Runtime::User.password + end + + def clone(opts = '') + `git clone #{opts} #{@uri.to_s} ./` + end + + def shallow_clone + clone('--depth 1') + end + + def configure_identity(name, email) + `git config user.name #{name}` + `git config user.email #{email}` + end + + def commit_file(name, contents, message) + add_file(name, contents) + commit(message) + end + + def add_file(name, contents) + File.write(name, contents) + + `git add #{name}` + end + + def commit(message) + `git commit -m "#{message}"` + end + + def push_changes(branch = 'master') + `git push #{@uri.to_s} #{branch}` + end + + def commits + `git log --oneline`.split("\n") + end + end + end +end diff --git a/qa/qa/page/admin/license.rb b/qa/qa/page/admin/license.rb new file mode 100644 index 00000000000..4bdfae30b37 --- /dev/null +++ b/qa/qa/page/admin/license.rb @@ -0,0 +1,20 @@ +module QA + module Page + module Admin + class License < Page::Base + def no_license? + page.has_content?('No GitLab Enterprise Edition ' \ + 'license has been provided yet') + end + + def add_new_license(key) + raise 'License key empty!' if key.to_s.empty? + + choose 'Enter license key' + fill_in 'License key', with: key + click_button 'Upload license' + end + end + end + end +end diff --git a/qa/qa/page/admin/menu.rb b/qa/qa/page/admin/menu.rb new file mode 100644 index 00000000000..b01a4e10f93 --- /dev/null +++ b/qa/qa/page/admin/menu.rb @@ -0,0 +1,19 @@ +module QA + module Page + module Admin + class Menu < Page::Base + def go_to_license + within_middle_menu { click_link 'License' } + end + + private + + def within_middle_menu + page.within('.nav-control') do + yield + end + end + end + end + end +end diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb new file mode 100644 index 00000000000..d55326c5262 --- /dev/null +++ b/qa/qa/page/base.rb @@ -0,0 +1,12 @@ +module QA + module Page + class Base + include Capybara::DSL + include Scenario::Actable + + def refresh + visit current_path + end + end + end +end diff --git a/qa/qa/page/main/entry.rb b/qa/qa/page/main/entry.rb new file mode 100644 index 00000000000..fe80deb6429 --- /dev/null +++ b/qa/qa/page/main/entry.rb @@ -0,0 +1,26 @@ +module QA + module Page + module Main + class Entry < Page::Base + def initialize + visit('/') + + # This resolves cold boot problems with login page + find('.application', wait: 120) + end + + def sign_in_using_credentials + if page.has_content?('Change your password') + fill_in :user_password, with: Runtime::User.password + fill_in :user_password_confirmation, with: Runtime::User.password + click_button 'Change your password' + end + + fill_in :user_login, with: Runtime::User.name + fill_in :user_password, with: Runtime::User.password + click_button 'Sign in' + end + end + end + end +end diff --git a/qa/qa/page/main/groups.rb b/qa/qa/page/main/groups.rb new file mode 100644 index 00000000000..84597719a84 --- /dev/null +++ b/qa/qa/page/main/groups.rb @@ -0,0 +1,20 @@ +module QA + module Page + module Main + class Groups < Page::Base + def prepare_test_namespace + return if page.has_content?(Runtime::Namespace.name) + + click_on 'New Group' + + fill_in 'group_path', with: Runtime::Namespace.name + fill_in 'group_description', + with: "QA test run at #{Runtime::Namespace.time}" + choose 'Private' + + click_button 'Create group' + end + end + end + end +end diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb new file mode 100644 index 00000000000..90ff018b9d2 --- /dev/null +++ b/qa/qa/page/main/menu.rb @@ -0,0 +1,46 @@ +module QA + module Page + module Main + class Menu < Page::Base + def go_to_groups + within_global_menu { click_link 'Groups' } + end + + def go_to_projects + within_global_menu { click_link 'Projects' } + end + + def go_to_admin_area + within_user_menu { click_link 'Admin Area' } + end + + def sign_out + within_user_menu do + find('.header-user-dropdown-toggle').click + click_link('Sign out') + end + end + + def has_personal_area? + page.has_selector?('.header-user-dropdown-toggle') + end + + private + + def within_global_menu + find('.global-dropdown-toggle').click + + page.within('.global-dropdown-menu') do + yield + end + end + + def within_user_menu + page.within('.dropdown-menu-nav') do + yield + end + end + end + end + end +end diff --git a/qa/qa/page/main/projects.rb b/qa/qa/page/main/projects.rb new file mode 100644 index 00000000000..28d3a424022 --- /dev/null +++ b/qa/qa/page/main/projects.rb @@ -0,0 +1,16 @@ +module QA + module Page + module Main + class Projects < Page::Base + def go_to_new_project + ## + # There are 'New Project' and 'New project' buttons on the projects + # page, so we can't use `click_on`. + # + button = find('a', text: /^new project$/i) + button.click + end + end + end + end +end diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb new file mode 100644 index 00000000000..b31bec27b59 --- /dev/null +++ b/qa/qa/page/project/new.rb @@ -0,0 +1,24 @@ +module QA + module Page + module Project + class New < Page::Base + def choose_test_namespace + find('#s2id_project_namespace_id').click + find('.select2-result-label', text: Runtime::Namespace.name).click + end + + def choose_name(name) + fill_in 'project_path', with: name + end + + def add_description(description) + fill_in 'project_description', with: description + end + + def create_new_project + click_on 'Create project' + end + end + end + end +end diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb new file mode 100644 index 00000000000..56a270d8fcc --- /dev/null +++ b/qa/qa/page/project/show.rb @@ -0,0 +1,23 @@ +module QA + module Page + module Project + class Show < Page::Base + def choose_repository_clone_http + find('#clone-dropdown').click + + page.within('#clone-dropdown') do + find('span', text: 'HTTP').click + end + end + + def repository_location + find('#project_clone').value + end + + def wait_for_push + sleep 5 + end + end + end + end +end diff --git a/qa/qa/runtime/namespace.rb b/qa/qa/runtime/namespace.rb new file mode 100644 index 00000000000..e4910b63a14 --- /dev/null +++ b/qa/qa/runtime/namespace.rb @@ -0,0 +1,15 @@ +module QA + module Runtime + module Namespace + extend self + + def time + @time ||= Time.now + end + + def name + 'qa_test_' + time.strftime('%d_%m_%Y_%H-%M-%S') + end + end + end +end diff --git a/qa/qa/runtime/user.rb b/qa/qa/runtime/user.rb new file mode 100644 index 00000000000..12ceda015f0 --- /dev/null +++ b/qa/qa/runtime/user.rb @@ -0,0 +1,15 @@ +module QA + module Runtime + module User + extend self + + def name + ENV['GITLAB_USERNAME'] || 'root' + end + + def password + ENV['GITLAB_PASSWORD'] || 'test1234' + end + end + end +end diff --git a/qa/qa/scenario/actable.rb b/qa/qa/scenario/actable.rb new file mode 100644 index 00000000000..6cdbd24780e --- /dev/null +++ b/qa/qa/scenario/actable.rb @@ -0,0 +1,23 @@ +module QA + module Scenario + module Actable + def act(*args, &block) + instance_exec(*args, &block) + end + + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + def perform + yield new if block_given? + end + + def act(*args, &block) + new.act(*args, &block) + end + end + end + end +end diff --git a/qa/qa/scenario/gitlab/license/add.rb b/qa/qa/scenario/gitlab/license/add.rb new file mode 100644 index 00000000000..ca5e1176959 --- /dev/null +++ b/qa/qa/scenario/gitlab/license/add.rb @@ -0,0 +1,21 @@ +module QA + module Scenario + module Gitlab + module License + class Add < Scenario::Template + def perform + Page::Main::Entry.act { sign_in_using_credentials } + Page::Main::Menu.act { go_to_admin_area } + Page::Admin::Menu.act { go_to_license } + + Page::Admin::License.act do + add_new_license(ENV['EE_LICENSE']) if no_license? + end + + Page::Main::Menu.act { sign_out } + end + end + end + end + end +end diff --git a/qa/qa/scenario/gitlab/project/create.rb b/qa/qa/scenario/gitlab/project/create.rb new file mode 100644 index 00000000000..38522714e64 --- /dev/null +++ b/qa/qa/scenario/gitlab/project/create.rb @@ -0,0 +1,31 @@ +require 'securerandom' + +module QA + module Scenario + module Gitlab + module Project + class Create < Scenario::Template + attr_writer :description + + def name=(name) + @name = "#{name}-#{SecureRandom.hex(8)}" + end + + def perform + Page::Main::Menu.act { go_to_groups } + Page::Main::Groups.act { prepare_test_namespace } + Page::Main::Menu.act { go_to_projects } + Page::Main::Projects.act { go_to_new_project } + + Page::Project::New.perform do |page| + page.choose_test_namespace + page.choose_name(@name) + page.add_description(@description) + page.create_new_project + end + end + end + end + end + end +end diff --git a/qa/qa/scenario/template.rb b/qa/qa/scenario/template.rb new file mode 100644 index 00000000000..341998af160 --- /dev/null +++ b/qa/qa/scenario/template.rb @@ -0,0 +1,16 @@ +module QA + module Scenario + class Template + def self.perform(*args) + new.tap do |scenario| + yield scenario if block_given? + return scenario.perform(*args) + end + end + + def perform(*_args) + raise NotImplementedError + end + end + end +end diff --git a/qa/qa/scenario/test/instance.rb b/qa/qa/scenario/test/instance.rb new file mode 100644 index 00000000000..dcd0a32d79d --- /dev/null +++ b/qa/qa/scenario/test/instance.rb @@ -0,0 +1,27 @@ +module QA + module Scenario + module Test + ## + # Run test suite against any GitLab instance, + # including staging and on-premises installation. + # + class Instance < Scenario::Template + def perform(address, tag, *files) + Specs::Config.perform do |specs| + specs.address = address + end + + ## + # Temporary CE + EE support + Scenario::Gitlab::License::Add.perform if tag.to_s == 'ee' + + Specs::Runner.perform do |specs| + files = files.any? ? files : 'qa/specs/features' + + specs.rspec('--tty', '--tag', tag.to_s, files) + end + end + end + end + end +end diff --git a/qa/qa/specs/config.rb b/qa/qa/specs/config.rb new file mode 100644 index 00000000000..d72187fcd34 --- /dev/null +++ b/qa/qa/specs/config.rb @@ -0,0 +1,78 @@ +require 'rspec/core' +require 'capybara/rspec' +require 'capybara-webkit' +require 'capybara-screenshot/rspec' + +# rubocop:disable Metrics/MethodLength +# rubocop:disable Metrics/LineLength + +module QA + module Specs + class Config < Scenario::Template + attr_writer :address + + def initialize + @address = ENV['GITLAB_URL'] + end + + def perform + raise 'Please configure GitLab address!' unless @address + + configure_rspec! + configure_capybara! + configure_webkit! + end + + def configure_rspec! + RSpec.configure do |config| + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`. + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # Run specs in random order to surface order dependencies. + config.order = :random + Kernel.srand config.seed + + config.before(:all) do + page.current_window.resize_to(1200, 1800) + end + + config.formatter = :documentation + config.color = true + end + end + + def configure_capybara! + Capybara.configure do |config| + config.app_host = @address + config.default_driver = :webkit + config.javascript_driver = :webkit + config.default_max_wait_time = 4 + + # https://github.com/mattheworiordan/capybara-screenshot/issues/164 + config.save_path = 'tmp' + end + end + + def configure_webkit! + Capybara::Webkit.configure do |config| + config.allow_url(@address) + config.block_unknown_urls + end + rescue RuntimeError # rubocop:disable Lint/HandleExceptions + # TODO, Webkit is already configured, this make this + # configuration step idempotent, should be improved. + end + end + end +end diff --git a/qa/qa/specs/features/login/standard_spec.rb b/qa/qa/specs/features/login/standard_spec.rb new file mode 100644 index 00000000000..ecb3f0cb68c --- /dev/null +++ b/qa/qa/specs/features/login/standard_spec.rb @@ -0,0 +1,14 @@ +module QA + feature 'standard root login', :ce, :ee do + scenario 'user logs in using credentials' do + Page::Main::Entry.act { sign_in_using_credentials } + + # TODO, since `Signed in successfully` message was removed + # this is the only way to tell if user is signed in correctly. + # + Page::Main::Menu.perform do |menu| + expect(menu).to have_personal_area + end + end + end +end diff --git a/qa/qa/specs/features/project/create_spec.rb b/qa/qa/specs/features/project/create_spec.rb new file mode 100644 index 00000000000..cf4226252a6 --- /dev/null +++ b/qa/qa/specs/features/project/create_spec.rb @@ -0,0 +1,19 @@ +module QA + feature 'create a new project', :ce, :ee, :staging do + scenario 'user creates a new project' do + Page::Main::Entry.act { sign_in_using_credentials } + + Scenario::Gitlab::Project::Create.perform do |project| + project.name = 'awesome-project' + project.description = 'create awesome project test' + end + + expect(page).to have_content( + /Project \S?awesome-project\S+ was successfully created/ + ) + + expect(page).to have_content('create awesome project test') + expect(page).to have_content('The repository for this project is empty') + end + end +end diff --git a/qa/qa/specs/features/repository/clone_spec.rb b/qa/qa/specs/features/repository/clone_spec.rb new file mode 100644 index 00000000000..a772dc227e3 --- /dev/null +++ b/qa/qa/specs/features/repository/clone_spec.rb @@ -0,0 +1,57 @@ +module QA + feature 'clone code from the repository', :ce, :ee, :staging do + context 'with regular account over http' do + given(:location) do + Page::Project::Show.act do + choose_repository_clone_http + repository_location + end + end + + before do + Page::Main::Entry.act { sign_in_using_credentials } + + Scenario::Gitlab::Project::Create.perform do |scenario| + scenario.name = 'project-with-code' + scenario.description = 'project for git clone tests' + end + + Git::Repository.perform do |repository| + repository.location = location + repository.use_default_credentials + + repository.act do + clone + configure_identity('GitLab QA', 'root@gitlab.com') + commit_file('test.rb', 'class Test; end', 'Add Test class') + commit_file('README.md', '# Test', 'Add Readme') + push_changes + end + end + end + + scenario 'user performs a deep clone' do + Git::Repository.perform do |repository| + repository.location = location + repository.use_default_credentials + + repository.act { clone } + + expect(repository.commits.size).to eq 2 + end + end + + scenario 'user performs a shallow clone' do + Git::Repository.perform do |repository| + repository.location = location + repository.use_default_credentials + + repository.act { shallow_clone } + + expect(repository.commits.size).to eq 1 + expect(repository.commits.first).to include 'Add Readme' + end + end + end + end +end diff --git a/qa/qa/specs/features/repository/push_spec.rb b/qa/qa/specs/features/repository/push_spec.rb new file mode 100644 index 00000000000..4b6cb7908bb --- /dev/null +++ b/qa/qa/specs/features/repository/push_spec.rb @@ -0,0 +1,39 @@ +module QA + feature 'push code to repository', :ce, :ee, :staging do + context 'with regular account over http' do + scenario 'user pushes code to the repository' do + Page::Main::Entry.act { sign_in_using_credentials } + + Scenario::Gitlab::Project::Create.perform do |scenario| + scenario.name = 'project_with_code' + scenario.description = 'project with repository' + end + + Git::Repository.perform do |repository| + repository.location = Page::Project::Show.act do + choose_repository_clone_http + repository_location + end + + repository.use_default_credentials + + repository.act do + clone + configure_identity('GitLab QA', 'root@gitlab.com') + add_file('README.md', '# This is test project') + commit('Add README.md') + push_changes + end + end + + Page::Project::Show.act do + wait_for_push + refresh + end + + expect(page).to have_content('README.md') + expect(page).to have_content('This is test project') + end + end + end +end diff --git a/qa/qa/specs/runner.rb b/qa/qa/specs/runner.rb new file mode 100644 index 00000000000..83ae15d0995 --- /dev/null +++ b/qa/qa/specs/runner.rb @@ -0,0 +1,15 @@ +require 'rspec/core' + +module QA + module Specs + class Runner + include Scenario::Actable + + def rspec(*args) + RSpec::Core::Runner.run(args.flatten, $stderr, $stdout).tap do |status| + abort if status.nonzero? + end + end + end + end +end |