Commit 39b6a70f authored by Mark Lapierre's avatar Mark Lapierre

Add e2e test of distributed reads

parent 1db40d61
......@@ -48,3 +48,89 @@ only to prevent it from running in the pipelines for live environments such as S
If Jenkins Docker container exits without providing any information in the logs, try increasing the memory used by
the Docker Engine.
## Gitaly Cluster tests
The tests tagged `:gitaly_ha` are orchestrated tests that can only be run against a set of Docker containers as configured and started by [the `Test::Integration::GitalyCluster` GitLab QA scenario](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md#testintegrationgitalycluster-ceeefull-image-address).
As described in the documentation about the scenario noted above, the following command will run the tests:
```shell
gitlab-qa Test::Integration::GitalyCluster EE
```
However, that will remove the containers after it finishes running the tests. If you would like to do further testing, for example, if you would like to run a single test via a debugger, you can use [the `--no-tests` option](https://gitlab.com/gitlab-org/gitlab-qa#command-line-options) to make `gitlab-qa` skip running the tests, and to leave the containers running so that you can continue to use them.
```shell
gitlab-qa Test::Integration::GitalyCluster EE --no-tests
```
When all the containers are running you will see the output of the `docker ps` command, showing on which ports the GitLab container can be accessed. For example:
```plaintext
CONTAINER ID ... PORTS NAMES
d15d3386a0a8 ... 22/tcp, 443/tcp, 0.0.0.0:32772->80/tcp gitlab-gitaly-ha
```
That shows that the GitLab instance running in the `gitlab-gitaly-ha` container can be reached via `http://localhost:32772`. However, Git operations like cloning and pushing are performed against the URL revealed via the UI as the clone URL. It uses the hostname configured for the GitLab instance, which in this case matches the Docker container name and network, `gitlab-gitaly-ha.test`. Before you can run the tests you need to configure your computer to access the container via that address. One option is to [use caddyserver as described for running tests against GDK](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/run_qa_against_gdk.md#workarounds).
Another option is to use NGINX.
In both cases you will need to configure your machine to translate `gitlab-gitlab-ha.test` into an appropriate IP address:
```shell
echo '127.0.0.1 gitlab-gitaly-ha.test' | sudo tee -a /etc/hosts
```
Then install NGINX:
```shell
# on macOS
brew install nginx
# on Debian/Ubuntu
apt install nginx
# on Fedora
yum install nginx
```
Finally, configure NGINX to pass requests for `gitlab-gitaly-ha.test` to the GitLab instance:
```plaintext
# On Debian/Ubuntu, in /etc/nginx/sites-enabled/gitlab-cluster
# On macOS, in /usr/local/etc/nginx/nginx.conf
server {
server_name gitlab-gitaly-ha.test;
client_max_body_size 500m;
location / {
proxy_pass http://127.0.0.1:32772;
proxy_set_header Host gitlab-gitaly-ha.test;
}
}
```
Restart NGINX for the configuration to take effect. For example:
```shell
# On Debian/Ubuntu
sudo systemctl restart nginx
# on macOS
sudo nginx -s reload
```
You could then run the tests from the `/qa` directory:
```shell
CHROME_HEADLESS=false bin/qa Test::Instance::All http://gitlab-gitaly-ha.test -- --tag gitaly_ha
```
Once you have finished testing you can stop and remove the Docker containers:
```shell
docker stop gitlab-gitaly-ha praefect postgres gitaly3 gitaly2 gitaly1
docker rm gitlab-gitaly-ha praefect postgres gitaly3 gitaly2 gitaly1
```
......@@ -59,14 +59,19 @@ module QA
@update_files = files
end
def resource_web_url(resource)
# If `actions` are specified, it performs the actions to create,
# update, or delete commits. If no actions are specified it
# gets existing commits.
def fabricate_via_api!
return api_get if actions.empty?
super
rescue ResourceNotFoundError
super
rescue ResourceURLMissingError
# this particular resource does not expose a web_url property
end
def api_get_path
"#{api_post_path}/#{@sha}"
api_post_path
end
def api_post_path
......
......@@ -7,6 +7,8 @@ module QA
attr_accessor :gitlab
PrometheusQueryError = Class.new(StandardError)
def initialize
@gitlab = 'gitlab-gitaly-ha'
@praefect = 'praefect'
......@@ -106,6 +108,18 @@ module QA
)
end
def query_read_distribution
output = shell "docker exec gitlab-gitaly-ha bash -c 'curl -s http://localhost:9090/api/v1/query?query=gitaly_praefect_read_distribution'" do |line|
QA::Runtime::Logger.debug(line)
break line
end
result = JSON.parse(output)
raise PrometheusQueryError, "Unable to query read distribution metrics" unless result['status'] == 'success'
result['data']['result'].map { |result| { node: result['metric']['storage'], value: result['value'][1].to_i } }
end
def replication_queue_lock_count
result = []
shell sql_to_docker_exec_cmd("select count(*) from replication_queue_lock where acquired = 't';") do |line|
......@@ -285,6 +299,18 @@ module QA
)
end
# Waits until there is an increase in the number of reads for
# any node compared to the number of reads provided
def wait_for_read_count_change(pre_read_data)
diff_found = false
Support::Waiter.wait_until(sleep_interval: 5) do
query_read_distribution.each_with_index do |data, index|
diff_found = true if data[:value] > pre_read_data[index][:value]
end
diff_found
end
end
def wait_for_reliable_connection
QA::Runtime::Logger.info('Wait until GitLab and Praefect can communicate reliably')
wait_for_praefect
......
# frozen_string_literal: true
require 'parallel'
module QA
RSpec.describe 'Create' do
context 'Gitaly' do
# Issue to track removal of feature flag: https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/602
describe 'Distributed reads', :orchestrated, :gitaly_ha, :skip_live_env, :requires_admin do
let(:number_of_reads) { 100 }
let(:praefect_manager) { Service::PraefectManager.new }
let(:project) do
Resource::Project.fabricate! do |project|
project.name = "gitaly_cluster"
project.initialize_with_readme = true
end
end
before do
Runtime::Feature.enable_and_verify('gitaly_distributed_reads')
praefect_manager.wait_for_replication(project.id)
end
after do
Runtime::Feature.disable_and_verify('gitaly_distributed_reads')
end
it 'reads from each node' do
pre_read_data = praefect_manager.query_read_distribution
QA::Runtime::Logger.info('Fetching commits from the repository')
Parallel.each((1..number_of_reads)) do |index|
Resource::Repository::Commit.fabricate_via_api! do |commits|
commits.project = project
end
end
praefect_manager.wait_for_read_count_change(pre_read_data)
aggregate_failures "each gitaly node" do
praefect_manager.query_read_distribution.each_with_index do |data, index|
expect(data[:value])
.to be > pre_read_data[index][:value],
"Read counts did not differ for node #{pre_read_data[index][:node]}"
end
end
end
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment