Commit b2ddf57e authored by Nailia Iskhakova's avatar Nailia Iskhakova

Merge branch 'add-influxdb-to-ci' into 'master'

Store GPT test results in InfluxDB

See merge request !146
parents 930878be c7fb67a4
......@@ -6,6 +6,7 @@ $stdout.sync = true
require 'chronic_duration'
require 'test_info'
require 'fileutils'
require 'influxdb'
require 'optimist'
require 'rainbow'
require 'run_k6'
......@@ -32,7 +33,7 @@ opts = Optimist.options do
opt :quarantined, "Include any tests inside the test directory's quarantined subfolder when true.", type: :flag, default: false
opt :excludes, "List of words used to exclude tests by matching against their names.", type: :strings
opt :unsafe, "Include any tests that perform unsafe requests (POST, PUT, DELETE, PATCH)", type: :flag, default: false
opt :influxdb_url, "URL of an Influx DB server where GPT can optionally upload test run statistics.", type: :string
opt :influxdb_url, "URL of an Influx DB server where GPT can optionally upload test run statistics.", type: :string, default: ENV['GPT_INFLUXDB_URL'] || nil
banner "\nEnvironment Variable(s):"
banner " ACCESS_TOKEN A valid GitLab Personal Access Token for the specified environment that's required by various tests. The token should come from a User that has admin access for the project(s) to be tested and have API, read_repository, and write_repository permissions. (Default: nil)"
banner "\nExamples:"
......@@ -155,4 +156,9 @@ File.write(results_txt_file, "#{results_summary}\n#{results_table}\n#{results_fo
puts "\n█ Results files\n\n#{results_output_file}\n#{results_json_file}\n#{results_txt_file}"
if opts[:influxdb_url]
influxdb_report, message = InfluxDB.write_data(opts[:influxdb_url], results_json)
warn Rainbow("\nFailed to upload test run statistics to InfluxDB URL #{opts[:influxdb_url]} - #{message}.").red unless influxdb_report
abort("\n" + Rainbow("One or more tests have failed...").red) unless aggregated_success || ENV['GPT_IGNORE_RESULT'] == 'true'
......@@ -427,6 +427,14 @@ Currently, you'll find the following results on our Wiki:
* [Latest Results]( - Our automated CI pipelines run multiple times each week and will post their result summaries to the wiki here each time.
* [GitLab Versions]( - A collection of performance test results done against several select release versions of GitLab.
#### Using InfluxDB to store results
GPT provides a custom [InfluxDB writer]( that sends GPT results summary data once the test run is finished:
- Measurements: `ttfb_avg`, `ttfb_p90`, `ttfb_p95`, `rps_result`, `success_rate`, `score`
- Tags: `gitlab_version`, `gitlab_revision`, `gpt_version`, `test_name`
To use [built-in k6 InfluxDB]( output pass `K6_INFLUXDB_OUTPUT` environment variable along with `--influxdb-url` flag to the GPT.
## Troubleshooting
In this section we'll detail any known potential problems when running `k6` and how to manage them.
......@@ -4,10 +4,10 @@ require 'json'
module GPTCommon
extend self
def make_http_request(method: 'get', url: nil, params: {}, headers: {}, show_response: false, fail_on_error: true)
def make_http_request(method: 'get', url: nil, params: {}, headers: {}, body: "", show_response: false, fail_on_error: true)
raise "URL not defined for making request. Exiting..." unless url
res = HTTP.follow.method(method).call(url, form: params, headers: headers)
res = body.empty? ? HTTP.follow.method(method).call(url, form: params, headers: headers) : HTTP.follow.method(method).call(url, body: body, headers: headers)
if show_response
if res.content_type.mime_type == "application/json"
require 'gpt_common'
require 'uri'
module InfluxDB
extend self
def healthy?(influxdb_host)
GPTCommon.make_http_request(method: 'get', url: URI.join(influxdb_host, "ping?verbose=true").to_s, fail_on_error: false).status.success?
rescue HTTP::ConnectionError, Errno::ECONNREFUSED
def prepare_request_body(measurement, tags, value, time)
"#{measurement},#{ { |h| h.join '=' }.join ','} value=#{value} #{time}"
def prepare_request_data(results_json)
tests_end_time = results_json['time']['end_epoch'] * 1_000_000 # The timestamp for InfluxDB data point in nanosecond-precision Unix time.
tags = {
gitlab_version: results_json['version'],
gitlab_revision: results_json['revision'],
gpt_version: results_json['gpt_version']
results_json['test_results'].map do |test_result|
%w[ttfb_avg ttfb_p90 ttfb_p95 rps_result success_rate score].map do |measurement|
prepare_request_body(measurement, tags.merge({ test_name: test_result['name'] }), test_result[measurement], tests_end_time)
def write_data(influxdb_url, results_json)
return false, "Invalid URL" unless influxdb_url.match?(URI::DEFAULT_PARSER.make_regexp)
influxdb_host = influxdb_url.match(/(.*)\//)[1]
influxdb_db = influxdb_url.split("/")[-1]
influxdb_write_url = URI.join(influxdb_host, "/write?db=#{influxdb_db}").to_s
return false, "URL can’t be reached" unless healthy?(influxdb_host)
body = prepare_request_data(results_json)
GPTCommon.make_http_request(method: 'post', url: influxdb_write_url, body: body, fail_on_error: false)
......@@ -127,7 +127,7 @@ module RunK6
cmd += ['--user-agent', "GPT/#{gpt_version}"]
cmd += ['--insecure-skip-tls-verify']
cmd += ['--http-debug'] if ENV['GPT_DEBUG']
cmd += ['--out', "influxdb=#{opts[:influxdb_url]}"] if opts[:influxdb_url]
cmd += ['--out', "influxdb=#{opts[:influxdb_url]}"] if opts[:influxdb_url] && ENV['K6_INFLUXDB_OUTPUT']
cmd += [test_file]
status = nil
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment