lib/gitlab/qa/scenario/test/omnibus/update_from_previous.rb



# frozen_string_literal: true

module Gitlab
  module QA
    module Scenario
      module Test
        module Omnibus
          class UpdateFromPrevious < Scenario::Template
            using Rainbow

            # Test update from N - 1 (major|minor|patch) version to current release
            # Run smoke test suite on previous release to populate some data in database before update
            #
            # @example
            # perform(gitlab-ee:dev-tag, 15.3.0-pre, major)
            # => will perform upgrades 14.9.5 -> 15.0.5 -> gitlab-ee:dev-tag
            #
            # @param [String] release current release docker image
            # @param [String] current_version current gitlab version associated with docker image
            # @param [String] semver_component semver component for N - 1 version detection, major|minor|patch
            # @param [String] from_edition gitlab edition to update from
            # @param [Array] *rspec_args rspec arguments
            # @return [void]
            def perform(release, current_version, semver_component, from_edition = nil, *rspec_args)
              # When from_edition isn't actually passed but RSpec args arg passed with `-- rspec_args...`,
              # from_edition is wrongly set to `--`, so we fix that here.
              if from_edition == "--"
                rspec_args.prepend('--')
                from_edition = nil
              end

              @current_release = QA::Release.new(release)
              @upgrade_path = Support::GitlabUpgradePath.new(
                current_version,
                semver_component,
                from_edition || @current_release.edition
              ).fetch

              upgrade_info = "#{[*upgrade_path, current_release].join(' => ')} (#{current_version})".bright
              Runtime::Logger.info("Performing gitlab update: #{upgrade_info}")

              update(rspec_args)
            end

            private

            attr_reader :current_release, :upgrade_path

            # Perform update
            #
            # @param [Array] rspec_args
            # @return [void]
            def update(rspec_args)
              Docker::Volumes.new.with_temporary_volumes do |volumes|
                # deploy first release in upgrade path and run specs to populate db
                run_gitlab(upgrade_path.first, volumes, ["--", "--tag", "smoke"])

                # deploy releases in upgrade path
                upgrade_path[1..].each { |release| run_gitlab(release, volumes, skip_setup: true) }

                # deploy current release and run tests
                run_gitlab(current_release, volumes, rspec_args, skip_setup: true)
              end
            end

            # Deploy gitlab instance and optionally run specs
            #
            # @param [Gitlab::QA::Release] release
            # @param [Hash] volumes
            # @return [void]
            def run_gitlab(release, volumes, rspec_args = [], skip_setup: false)
              Runtime::Logger.info("Deploying release: #{release.to_s.bright}")

              Component::Gitlab.perform do |gitlab|
                gitlab.release = release
                gitlab.volumes = volumes
                gitlab.network = 'test'

                if skip_setup
                  gitlab.skip_server_hooks = true
                  gitlab.seed_db = false
                  gitlab.seed_admin_token = false
                end

                next gitlab.launch_and_teardown_instance unless run_specs?(release)

                gitlab.instance { run_specs(gitlab, release, rspec_args) }
              end
            end

            # Run specs
            #
            # @param [Gitlab::QA::Component::Gitlab] gitlab
            # @param [Gitlab::QA::Release] release
            # @param [Array] rspec_args
            # @return [void]
            def run_specs(gitlab, release, rspec_args)
              Component::Specs.perform do |specs|
                specs.release = release
                specs.suite = 'Test::Instance::All'
                specs.hostname = "qa-e2e-specs.#{gitlab.network}"
                specs.network = gitlab.network
                specs.args = [gitlab.address, *rspec_args]
                # do not generate reports for non release runs
                specs.env = { 'QA_GENERATE_ALLURE_REPORT' => false } unless release == current_release
              end
            rescue Support::ShellCommand::StatusError => e
              raise e if release == current_release # only fail on current release

              Runtime::Logger.warn("Test run for release '#{gitlab.release}' finished with errors!")
            end

            # Run specs on first release to populate database and release being tested
            #
            # @param [Gitlab::QA::Release] release
            # @return [Boolean]
            def run_specs?(release)
              [upgrade_path.first, current_release].any? { |rel| rel == release }
            end
          end
        end
      end
    end
  end
end