diff options
Diffstat (limited to 'spec/support/helpers/gitaly_setup.rb')
-rw-r--r-- | spec/support/helpers/gitaly_setup.rb | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/spec/support/helpers/gitaly_setup.rb b/spec/support/helpers/gitaly_setup.rb new file mode 100644 index 00000000000..2ce4bcfa943 --- /dev/null +++ b/spec/support/helpers/gitaly_setup.rb @@ -0,0 +1,195 @@ +# frozen_string_literal: true + +# This file contains environment settings for gitaly when it's running +# as part of the gitlab-ce/ee test suite. +# +# Please be careful when modifying this file. Your changes must work +# both for local development rspec runs, and in CI. + +require 'securerandom' +require 'socket' +require 'logger' + +module GitalySetup + LOGGER = begin + default_name = ENV['CI'] ? 'DEBUG' : 'WARN' + level_name = ENV['GITLAB_TESTING_LOG_LEVEL']&.upcase + level = Logger.const_get(level_name || default_name, true) # rubocop: disable Gitlab/ConstGetInheritFalse + Logger.new(STDOUT, level: level, formatter: ->(_, _, _, msg) { msg }) + end + + def tmp_tests_gitaly_dir + File.expand_path('../../../tmp/tests/gitaly', __dir__) + end + + def tmp_tests_gitaly_bin_dir + File.join(tmp_tests_gitaly_dir, '_build', 'bin') + end + + def tmp_tests_gitlab_shell_dir + File.expand_path('../../../tmp/tests/gitlab-shell', __dir__) + end + + def rails_gitlab_shell_secret + File.expand_path('../../../.gitlab_shell_secret', __dir__) + end + + def gemfile + File.join(tmp_tests_gitaly_dir, 'ruby', 'Gemfile') + end + + def gemfile_dir + File.dirname(gemfile) + end + + def gitlab_shell_secret_file + File.join(tmp_tests_gitlab_shell_dir, '.gitlab_shell_secret') + end + + def env + { + 'HOME' => File.expand_path('tmp/tests'), + 'GEM_PATH' => Gem.path.join(':'), + 'BUNDLE_APP_CONFIG' => File.join(gemfile_dir, '.bundle'), + 'BUNDLE_INSTALL_FLAGS' => nil, + 'BUNDLE_GEMFILE' => gemfile, + 'RUBYOPT' => nil, + + # Git hooks can't run during tests as the internal API is not running. + 'GITALY_TESTING_NO_GIT_HOOKS' => "1", + 'GITALY_TESTING_ENABLE_ALL_FEATURE_FLAGS' => "true" + } + end + + # rubocop:disable GitlabSecurity/SystemCommandInjection + def set_bundler_config + system('bundle config set --local jobs 4', chdir: gemfile_dir) + system('bundle config set --local retry 3', chdir: gemfile_dir) + + if ENV['CI'] + bundle_path = File.expand_path('../../../vendor/gitaly-ruby', __dir__) + system('bundle', 'config', 'set', '--local', 'path', bundle_path, chdir: gemfile_dir) + end + end + # rubocop:enable GitlabSecurity/SystemCommandInjection + + def config_path(service) + case service + when :gitaly + File.join(tmp_tests_gitaly_dir, 'config.toml') + when :gitaly2 + File.join(tmp_tests_gitaly_dir, 'gitaly2.config.toml') + when :praefect + File.join(tmp_tests_gitaly_dir, 'praefect.config.toml') + end + end + + def service_binary(service) + case service + when :gitaly, :gitaly2 + 'gitaly' + when :praefect + 'praefect' + end + end + + def install_gitaly_gems + system(env, "make #{tmp_tests_gitaly_dir}/.ruby-bundle", chdir: tmp_tests_gitaly_dir) # rubocop:disable GitlabSecurity/SystemCommandInjection + end + + def build_gitaly + system(env, 'make', chdir: tmp_tests_gitaly_dir) # rubocop:disable GitlabSecurity/SystemCommandInjection + end + + def start_gitaly + start(:gitaly) + end + + def start_gitaly2 + start(:gitaly2) + end + + def start_praefect + start(:praefect) + end + + def start(service) + args = ["#{tmp_tests_gitaly_bin_dir}/#{service_binary(service)}"] + args.push("-config") if service == :praefect + args.push(config_path(service)) + pid = spawn(env, *args, [:out, :err] => "log/#{service}-test.log") + + begin + try_connect!(service) + rescue StandardError + Process.kill('TERM', pid) + raise + end + + pid + end + + # Taken from Gitlab::Shell.generate_and_link_secret_token + def ensure_gitlab_shell_secret! + secret_file = rails_gitlab_shell_secret + shell_link = gitlab_shell_secret_file + + unless File.size?(secret_file) + File.write(secret_file, SecureRandom.hex(16)) + end + + unless File.exist?(shell_link) + FileUtils.ln_s(secret_file, shell_link) + end + end + + def check_gitaly_config! + LOGGER.debug "Checking gitaly-ruby Gemfile...\n" + + unless File.exist?(gemfile) + message = "#{gemfile} does not exist." + message += "\n\nThis might have happened if the CI artifacts for this build were destroyed." if ENV['CI'] + abort message + end + + LOGGER.debug "Checking gitaly-ruby bundle...\n" + out = ENV['CI'] ? STDOUT : '/dev/null' + abort 'bundle check failed' unless system(env, 'bundle', 'check', out: out, chdir: File.dirname(gemfile)) + end + + def read_socket_path(service) + # This code needs to work in an environment where we cannot use bundler, + # so we cannot easily use the toml-rb gem. This ad-hoc parser should be + # good enough. + config_text = IO.read(config_path(service)) + + config_text.lines.each do |line| + match_data = line.match(/^\s*socket_path\s*=\s*"([^"]*)"$/) + + return match_data[1] if match_data + end + + raise "failed to find socket_path in #{config_path(service)}" + end + + def try_connect!(service) + LOGGER.debug "Trying to connect to #{service}: " + timeout = 20 + delay = 0.1 + socket = read_socket_path(service) + + Integer(timeout / delay).times do + UNIXSocket.new(socket) + LOGGER.debug " OK\n" + + return + rescue Errno::ENOENT, Errno::ECONNREFUSED + LOGGER.debug '.' + sleep delay + end + + LOGGER.warn " FAILED to connect to #{service}\n" + + raise "could not connect to #{socket}" + end +end |