lib/gitlab/qa/component/mock_server.rb (70 lines of code) (raw):
# frozen_string_literal: true
module Gitlab
module QA
module Component
# General purpose http mock server
# see: https://smocker.dev/
#
class MockServer < Base
DOCKER_IMAGE = "thiht/smocker"
DOCKER_IMAGE_TAG = "0.18.2"
def initialize
super
@tls = false
@name = "smocker"
@tls_path = "/etc/smocker/tls"
@ports = [80, 8081]
@environment = { "SMOCKER_MOCK_SERVER_LISTEN_PORT" => 80 }
@tls_volume = { "smocker-ssl" => @tls_path }
end
attr_reader :name, :tls_volume
attr_writer :tls
def prepare
super
alpine_service_container.start_instance
setup_tls if tls
end
def teardown!
# Print smocker log output by using docker logs command because smocker only logs to stdout
Docker::Command.execute("logs #{name}")
# Remove alpine service container
alpine_service_container.teardown!
super
end
private
attr_reader :tls_path, :tls
# Run healthcheck validate startup of mock server
#
# @return [void]
def wait_until_ready
logger.info("Waiting for mock server to start!")
poll_mock_healthcheck(3)
logger.info("Mock server container is healthy!")
end
# Poll healthcheck endpoint
#
# @param [Integer] max_tries
# @return [void]
def poll_mock_healthcheck(max_tries)
url = "#{tls ? 'https' : 'http'}://#{hostname}:8081/version"
curl_cmd = "curl --cacert #{tls_path}/smocker.crt -s -f -o /dev/null -w '%{http_code}' #{url}"
tries = 0
loop do
# Poll healthcheck endpoint and remove service container if it passes
if docker.exec(alpine_service_container.name, curl_cmd, shell: "sh")
alpine_service_container.teardown!
break
end
rescue Support::ShellCommand::StatusError => e
# re-raise StatusError so that built in startup retry is used in case of failure
raise e if tries >= max_tries
tries += 1
sleep 1
end
end
# Set up tls certs
#
# @return [void]
def setup_tls
@volumes = tls_volume
@ports = [443, 8081]
@environment = {
"SMOCKER_MOCK_SERVER_LISTEN_PORT" => 443,
"SMOCKER_TLS_ENABLE" => "true",
"SMOCKER_TLS_CERT_FILE" => "#{tls_path}/smocker.crt",
"SMOCKER_TLS_PRIVATE_KEY_FILE" => "#{tls_path}/smocker.key"
}
docker.copy(alpine_service_container.name, "#{CERTIFICATES_PATH}/smocker/.", tls_path)
end
# Helper container to run tls cert copy and curl healthcheck command
# Separate container is required because tls certs have to be copied before smocker startup and smocker
# container itself doesn't ship with curl to perform healthcheck requests
#
# @return [Component::Alpine]
def alpine_service_container
@alpine_service_container ||= Alpine.new.tap do |alpine|
alpine.volumes = tls_volume
alpine.network = network
end
end
end
end
end
end