Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-12-20 21:10:56 +00:00
parent 13f6669657
commit 3774672ae1
31 changed files with 135 additions and 86 deletions

View file

@ -5,7 +5,7 @@
# Following are the files we need:
# - ./config/initializers/0_inject_enterprise_edition_module.rb
# - ./ee/app/models/license.rb
# - ./lib/gitlab.rb
# - ./lib/gitlab_edition.rb
# - ./lib/gitlab/utils.rb
# - ./qa/
# - ./INSTALLATION_TYPE

View file

@ -1 +1 @@
2ed3a40e02e3b5d284af33f14dbad2f5aff044d6
2db02e932c25bb96b269a9ac7a93f5bf52869865

View file

@ -258,7 +258,7 @@ module Types
end
def commits_without_merge_commits
object.recent_commits.without_merge_commits
object.commits.without_merge_commits
end
def security_auto_fix

View file

@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/344309
milestone: '14.5'
type: development
group: group::import
default_enabled: false
default_enabled: true

View file

@ -0,0 +1,8 @@
---
name: track_geo_proxy_events
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76587
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/348414
milestone: '14.6'
type: development
group: group::geo
default_enabled: false

View file

@ -46,7 +46,7 @@ module InjectEnterpriseEditionModule
end
def each_extension_for(constant_name, namespace)
Gitlab.extensions.each do |extension_name|
GitlabEdition.extensions.each do |extension_name|
extension_namespace =
const_get_maybe_false(namespace, extension_name.upcase)

View file

@ -6,8 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# IP whitelist **(FREE SELF)**
> Introduced in GitLab 9.4.
NOTE:
We intend to [rename IP whitelist as `IP allowlist`](https://gitlab.com/groups/gitlab-org/-/epics/3478).

View file

@ -22,10 +22,8 @@ GitLab monitors its own internal service metrics, and makes them available at th
`/-/metrics` endpoint. Unlike other [Prometheus](https://prometheus.io) exporters, to access
the metrics, the client IP address must be [explicitly allowed](../ip_whitelist.md).
For [Omnibus GitLab](https://docs.gitlab.com/omnibus/) and Chart installations,
these metrics are enabled and collected as of
[GitLab 9.4](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/1702).
For source installations, these metrics must be enabled
These metrics are enabled and collected for [Omnibus GitLab](https://docs.gitlab.com/omnibus/)
and Chart installations. For source installations, these metrics must be enabled
manually and collected by a Prometheus server.
For enabling and viewing metrics from Sidekiq nodes, see [Sidekiq metrics](#sidekiq-metrics).
@ -107,7 +105,7 @@ The following metrics are available:
| `pipelines_created_total` | Counter | 9.4 | Counter of pipelines created | |
| `rack_uncaught_errors_total` | Counter | 9.4 | Rack connections handling uncaught errors count | |
| `user_session_logins_total` | Counter | 9.4 | Counter of how many users have logged in since GitLab was started or restarted | |
| `upload_file_does_not_exist` | Counter | 10.7 | Number of times an upload record could not find its file. Made available in all tiers in GitLab 11.5. | |
| `upload_file_does_not_exist` | Counter | 10.7 | Number of times an upload record could not find its file. | |
| `failed_login_captcha_total` | Gauge | 11.0 | Counter of failed CAPTCHA attempts during login | |
| `successful_login_captcha_total` | Gauge | 11.0 | Counter of successful CAPTCHA attempts during login | |
| `auto_devops_pipelines_completed_total` | Counter | 12.7 | Counter of completed Auto DevOps pipelines, labeled by status | |

View file

@ -19,6 +19,7 @@ The [`StandardContext`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/g
| `project_id` | **{dotted-circle}** | integer | |
| `namespace_id` | **{dotted-circle}** | integer | |
| `user_id` | **{dotted-circle}** | integer | User database record ID attribute. This file undergoes a pseudonymization process at the collector level. |
| `context_generated_at` | **{dotted-circle}** | string (date time format) | Timestamp indicating when context was generated. |
| `environment` | **{check-circle}** | string (max 32 chars) | Name of the source environment, such as `production` or `staging` |
| `source` | **{check-circle}** | string (max 32 chars) | Name of the source application, such as `gitlab-rails` or `gitlab-javascript` |
| `plan` | **{dotted-circle}** | string (max 32 chars) | Name of the plan for the namespace, such as `free`, `premium`, or `ultimate`. Automatically picked from the `namespace`. |

View file

@ -6,12 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Health Check **(FREE SELF)**
> - Liveness and readiness probes were [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10416) in GitLab 9.1.
> - The `health_check` endpoint was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/3888) in GitLab 8.8 and was
> deprecated in GitLab 9.1.
> - [Access token](#access-token-deprecated) has been deprecated in GitLab 9.4
> in favor of [IP whitelist](#ip-whitelist).
GitLab provides liveness and readiness probes to indicate service health and
reachability to required services. These probes report on the status of the
database connection, Redis connection, and access to the file system. These
@ -137,29 +131,6 @@ On failure, the endpoint returns a `503` HTTP status code.
This check is being exempt from Rack Attack.
## Access token (Deprecated)
NOTE:
Access token has been deprecated in GitLab 9.4 in favor of [IP whitelist](#ip-whitelist).
An access token needs to be provided while accessing the probe endpoints. You can
find the current accepted token in the user interface:
1. On the top bar, select **Menu > Admin**.
1. On the left sidebar, select **Monitoring > Health Check**. (`admin/health_check`)
![access token](img/health_check_token.png)
The access token can be passed as a URL parameter:
```plaintext
https://gitlab.example.com/-/readiness?token=ACCESS_TOKEN
```
NOTE:
In case the database or Redis service are inaccessible, the probe endpoints response is not guaranteed to be correct.
You should switch to [IP whitelist](#ip-whitelist) from deprecated access token to avoid it.
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues

View file

@ -26,6 +26,7 @@ The following aspects of a project are imported:
- Regular issue and pull request comments
- [Git Large File Storage (LFS) Objects](../../../topics/git/lfs/index.md)
- Pull request comments replies in discussions ([GitLab.com & 14.5+](https://gitlab.com/gitlab-org/gitlab/-/issues/336596))
- Diff Notes suggestions ([GitLab.com & 14.7+](https://gitlab.com/gitlab-org/gitlab/-/issues/340624)) [with a flag](../../../administration/feature_flags.md) named `github_importer_use_diff_note_with_suggestions`. Enabled by default.
References to pull requests and issues are preserved (GitLab.com & 8.7+), and
each imported repository maintains visibility level unless that [visibility

View file

@ -6,8 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Prometheus integration **(FREE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8935) in GitLab 9.0.
GitLab offers powerful integration with [Prometheus](https://prometheus.io) for
monitoring key metrics of your apps, directly in GitLab.
Metrics for each environment are retrieved from Prometheus, and then displayed
@ -41,10 +39,9 @@ See [Prometheus cluster integration](../../clusters/integrations.md#prometheus-c
Integration with Prometheus requires the following:
1. GitLab 9.0 or higher
1. Prometheus must be configured to collect one of the [supported metrics](prometheus_library/index.md)
1. Each metric must be have a label to indicate the environment
1. GitLab must have network connectivity to the Prometheus server
- Prometheus must be configured to collect one of the [supported metrics](prometheus_library/index.md)
- Each metric must be have a label to indicate the environment
- GitLab must have network connectivity to the Prometheus server
#### Getting started
@ -113,9 +110,6 @@ can use only one:
## Determining the performance impact of a merge
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10408) in GitLab 9.2.
> - GitLab 9.3 added the [numeric comparison](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/27439) of the 30 minute averages.
Developers can view the performance impact of their changes in the merge
request workflow. This feature requires [Kubernetes](prometheus_library/kubernetes.md) metrics.

View file

@ -6,8 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Monitoring HAProxy **(FREE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/12621) in GitLab 9.4
GitLab has support for automatically detecting and monitoring HAProxy. This is provided by leveraging the [HAProxy Exporter](https://github.com/prometheus/haproxy_exporter), which translates HAProxy statistics into a Prometheus readable form.
## Requirements

View file

@ -6,8 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Prometheus Metrics library **(FREE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8935) in GitLab 9.0.
GitLab offers automatic detection of select [Prometheus exporters](https://prometheus.io/docs/instrumenting/exporters/).
## Exporters

View file

@ -6,8 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Monitoring Kubernetes **(FREE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8935) in GitLab 9.0.
GitLab has support for automatically detecting and monitoring Kubernetes metrics.
## Requirements
@ -44,8 +42,6 @@ Instead, the [Deployment](https://kubernetes.io/docs/concepts/workloads/controll
## Displaying Canary metrics **(PREMIUM)**
> Introduced in [GitLab 10.2](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/15201).
GitLab also gathers Kubernetes metrics for [canary deployments](../../canary_deployments.md), allowing easy comparison between the current deployed version and the canary.
These metrics expect the [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) or [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) name to begin with `$CI_ENVIRONMENT_SLUG-canary`, to isolate the canary metrics.

View file

@ -6,8 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Monitoring NGINX **(FREE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/12621) in GitLab 9.4
GitLab has support for automatically detecting and monitoring NGINX. This is provided by leveraging the [NGINX VTS exporter](https://github.com/hnlq715/nginx-vts-exporter), which translates [VTS statistics](https://github.com/vozlt/nginx-module-vts) into a Prometheus readable form.
## Requirements

View file

@ -6,8 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Monitoring NGINX Ingress Controller with VTS metrics **(FREE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13438) in GitLab 9.5.
NOTE:
[NGINX Ingress version 0.16](nginx_ingress.md) and above have built-in Prometheus metrics, which are different than the VTS based metrics.

View file

@ -78,7 +78,7 @@ You can create a merge request by running Git commands on your local machine.
```plaintext
...
remote: To create a merge request for docs-new-merge-request, visit:
remote: To create a merge request for my-new-branch, visit:
remote: https://gitlab.example.com/my-group/my-project/merge_requests/new?merge_request%5Bsource_branch%5D=my-new-branch
```

View file

@ -3,7 +3,7 @@
module Gitlab
module Tracking
class StandardContext
GITLAB_STANDARD_SCHEMA_URL = 'iglu:com.gitlab/gitlab_standard/jsonschema/1-0-7'
GITLAB_STANDARD_SCHEMA_URL = 'iglu:com.gitlab/gitlab_standard/jsonschema/1-0-8'
GITLAB_RAILS_SOURCE = 'gitlab-rails'
def initialize(namespace: nil, project: nil, user: nil, **extra)
@ -46,7 +46,8 @@ module Gitlab
extra: extra,
user_id: user&.id,
namespace_id: namespace&.id,
project_id: project_id
project_id: project_id,
context_generated_at: Time.current
}
end

View file

@ -373,3 +373,9 @@
redis_slot: network_policies
category: network_policies
aggregation: weekly
# Geo group
- name: g_geo_proxied_requests
category: geo
redis_slot: geo
aggregation: daily
feature_flag: track_geo_proxy_events

View file

@ -77,7 +77,7 @@ COPY ./config/initializers/0_inject_enterprise_edition_module.rb /home/gitlab/co
# The [b] part makes ./ee/app/models/license.r[b] a pattern that is allowed to return no files (which is the case in FOSS)
COPY VERSION ./ee/app/models/license.r[b] /home/gitlab/ee/app/models/
COPY ./config/bundler_setup.rb /home/gitlab/config/
COPY ./lib/gitlab.rb /home/gitlab/lib/
COPY ./lib/gitlab_edition.rb /home/gitlab/lib/
COPY ./lib/gitlab/utils.rb /home/gitlab/lib/gitlab/
COPY ./INSTALLATION_TYPE ./VERSION /home/gitlab/

View file

@ -2,7 +2,7 @@
Encoding.default_external = 'UTF-8'
require_relative '../lib/gitlab'
require_relative '../lib/gitlab_edition'
require_relative '../lib/gitlab/utils'
require_relative '../config/initializers/0_inject_enterprise_edition_module'

View file

@ -34,9 +34,8 @@ module QA
reporter.print_report
reporter.report_in_issue_and_slack if report_in_issue_and_slack == "true"
rescue StandardError => e
puts "Report creation failed! Error: '#{e}'".colorize(:red)
reporter.notify_failure(e)
exit(1)
raise(e)
end
# Print top stable specs
@ -96,13 +95,17 @@ module QA
#
# @return [String]
def report_issue_body
execution_interval = "(#{Date.today - range} - #{Date.today})"
issue = []
issue << "[[_TOC_]]"
issue << "# Candidates for promotion to reliable\n\n```\n#{stable_summary_table}\n```"
issue << "# Candidates for promotion to reliable #{execution_interval}"
issue << "```\n#{stable_summary_table}\n```"
issue << results_markdown(stable_results_tables)
return issue.join("\n\n") if unstable_reliable_test_runs.empty?
issue << "# Reliable specs with failures\n\n```\n#{unstable_summary_table}\n```"
issue << "# Reliable specs with failures #{execution_interval}"
issue << "```\n#{unstable_summary_table}\n```"
issue << results_markdown(unstable_reliable_results_tables)
issue.join("\n\n")
end
@ -255,9 +258,14 @@ module QA
all_runs = query_api.query(query: query(reliable)).values
all_runs.each_with_object(Hash.new { |hsh, key| hsh[key] = {} }) do |table, result|
records = table.records
name = records.last.values["name"]
file = records.last.values["file_path"].split("/").last
stage = records.last.values["stage"] || "unknown"
# skip specs that executed less time than defined by range
# offset 1 day due to how schedulers are configured and first run can be 1 day later
next if (Date.today - Date.parse(records.first.values["_time"])).to_i < (range - 1)
last_record = records.last.values
name = last_record["name"]
file = last_record["file_path"].split("/").last
stage = last_record["stage"] || "unknown"
runs = records.count
failed = records.count { |r| r.values["status"] == "failed" }

View file

@ -13,9 +13,16 @@ describe QA::Tools::ReliableReport do
let(:slack_channel) { "#quality-reports" }
let(:range) { 14 }
let(:issue_url) { "https://gitlab.com/issue/1" }
let(:time) { "2021-12-07T04:05:25.000000000+00:00" }
let(:runs) do
values = { "name" => "stable spec", "status" => "passed", "file_path" => "some/spec.rb", "stage" => "manage" }
values = {
"name" => "stable spec",
"status" => "passed",
"file_path" => "some/spec.rb",
"stage" => "manage",
"_time" => time
}
{
0 => instance_double(
"InfluxDB2::FluxTable",
@ -29,7 +36,13 @@ describe QA::Tools::ReliableReport do
end
let(:reliable_runs) do
values = { "name" => "unstable spec", "status" => "failed", "file_path" => "some/spec.rb", "stage" => "create" }
values = {
"name" => "unstable spec",
"status" => "failed",
"file_path" => "some/spec.rb",
"stage" => "create",
"_time" => time
}
{
0 => instance_double(
"InfluxDB2::FluxTable",
@ -136,11 +149,11 @@ describe QA::Tools::ReliableReport do
<<~TXT.strip
[[_TOC_]]
# Candidates for promotion to reliable
# Candidates for promotion to reliable (#{Date.today - range} - #{Date.today})
#{markdown_section([['manage', 1]], [[name_column('stable spec'), 3, 0, '0%']], 'manage', 'stable')}
# Reliable specs with failures
# Reliable specs with failures (#{Date.today - range} - #{Date.today})
#{markdown_section([['create', 1]], [[name_column('unstable spec'), 3, 2, '66.67%']], 'create', 'unstable')}
TXT
@ -180,7 +193,7 @@ describe QA::Tools::ReliableReport do
end
it "notifies failure", :aggregate_failures do
expect { expect { run }.to raise_error(SystemExit) }.to output.to_stdout
expect { expect { run }.to raise_error("Connection error!") }.to output.to_stdout
expect(slack_notifier).to have_received(:post).with(
icon_emoji: ":sadpanda:",

View file

@ -11,7 +11,7 @@ RSpec.describe InjectEnterpriseEditionModule do
before do
# Make sure we're not relying on which mode we're running under
allow(Gitlab).to receive(:extensions).and_return([extension_name.downcase])
allow(GitlabEdition).to receive(:extensions).and_return([extension_name.downcase])
# Test on an imagined extension and imagined class
stub_const(fish_name, fish_class) # Fish

View file

@ -58,6 +58,10 @@ RSpec.describe Gitlab::Tracking::StandardContext do
expect(snowplow_context.to_json.dig(:data, :source)).to eq(described_class::GITLAB_RAILS_SOURCE)
end
it 'contains context_generated_at timestamp', :freeze_time do
expect(snowplow_context.to_json.dig(:data, :context_generated_at)).to eq(Time.current)
end
context 'plan' do
context 'when namespace is not available' do
it 'is nil' do

View file

@ -48,7 +48,8 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
'epic_boards_usage',
'secure',
'importer',
'network_policies'
'network_policies',
'geo'
)
end
end

View file

@ -18,10 +18,17 @@ type Proxy struct {
Version string
reverseProxy *httputil.ReverseProxy
AllowResponseBuffering bool
customHeaders map[string]string
}
func NewProxy(myURL *url.URL, version string, roundTripper http.RoundTripper) *Proxy {
p := Proxy{Version: version, AllowResponseBuffering: true}
func WithCustomHeaders(customHeaders map[string]string) func(*Proxy) {
return func(proxy *Proxy) {
proxy.customHeaders = customHeaders
}
}
func NewProxy(myURL *url.URL, version string, roundTripper http.RoundTripper, options ...func(*Proxy)) *Proxy {
p := Proxy{Version: version, AllowResponseBuffering: true, customHeaders: make(map[string]string)}
if myURL == nil {
myURL = defaultTarget
@ -31,6 +38,11 @@ func NewProxy(myURL *url.URL, version string, roundTripper http.RoundTripper) *P
u.Path = ""
p.reverseProxy = httputil.NewSingleHostReverseProxy(&u)
p.reverseProxy.Transport = roundTripper
for _, option := range options {
option(&p)
}
return &p
}
@ -43,6 +55,10 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
req.Header.Set("Gitlab-Workhorse", p.Version)
req.Header.Set("Gitlab-Workhorse-Proxy-Start", fmt.Sprintf("%d", time.Now().UnixNano()))
for k, v := range p.customHeaders {
req.Header.Set(k, v)
}
if p.AllowResponseBuffering {
helper.AllowResponseBuffering(w)
}

View file

@ -37,6 +37,7 @@ var (
upload.RewrittenFieldsHeader,
}
geoProxyApiPollingInterval = 10 * time.Second
geoProxyWorkhorseHeaders = map[string]string{"Gitlab-Workhorse-Geo-Proxy": "1"}
)
type upstream struct {
@ -237,7 +238,12 @@ func (u *upstream) updateGeoProxyFields(geoProxyURL *url.URL) {
}
geoProxyRoundTripper := roundtripper.NewBackendRoundTripper(u.geoProxyBackend, "", u.ProxyHeadersTimeout, u.DevelopmentMode)
geoProxyUpstream := proxypkg.NewProxy(u.geoProxyBackend, u.Version, geoProxyRoundTripper)
geoProxyUpstream := proxypkg.NewProxy(
u.geoProxyBackend,
u.Version,
geoProxyRoundTripper,
proxypkg.WithCustomHeaders(geoProxyWorkhorseHeaders),
)
u.geoProxyCableRoute = u.wsRoute(`^/-/cable\z`, geoProxyUpstream)
u.geoProxyRoute = u.route("", "", geoProxyUpstream, withGeoProxy())
}

View file

@ -209,6 +209,23 @@ func TestGeoProxyFeatureEnablingAndDisabling(t *testing.T) {
runTestCases(t, ws, testCasesProxied)
}
func TestGeoProxySetsCustomHeader(t *testing.T) {
remoteServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "1", r.Header.Get("Gitlab-Workhorse-Geo-Proxy"), "custom proxy header")
w.WriteHeader(http.StatusOK)
}))
defer remoteServer.Close()
geoProxyEndpointResponseBody := fmt.Sprintf(`{"geo_proxy_url":"%v"}`, remoteServer.URL)
railsServer, deferredClose := startRailsServer("Local Rails server", &geoProxyEndpointResponseBody)
defer deferredClose()
ws, wsDeferredClose, _ := startWorkhorseServer(railsServer.URL, true)
defer wsDeferredClose()
http.Get(ws.URL)
}
func runTestCases(t *testing.T, ws *httptest.Server, testCases []testCase) {
t.Helper()
for _, tc := range testCases {

View file

@ -22,12 +22,12 @@ import (
const testVersion = "123"
func newProxy(url string, rt http.RoundTripper) *proxy.Proxy {
func newProxy(url string, rt http.RoundTripper, opts ...func(*proxy.Proxy)) *proxy.Proxy {
parsedURL := helper.URLMustParse(url)
if rt == nil {
rt = roundtripper.NewTestBackendRoundTripper(parsedURL)
}
return proxy.NewProxy(parsedURL, testVersion, rt)
return proxy.NewProxy(parsedURL, testVersion, rt, opts...)
}
func TestProxyRequest(t *testing.T) {
@ -64,6 +64,24 @@ func TestProxyRequest(t *testing.T) {
require.Equal(t, "test", w.Header().Get("Custom-Response-Header"), "custom response header")
}
func TestProxyWithCustomHeaders(t *testing.T) {
ts := testhelper.TestServerWithHandler(regexp.MustCompile(`/url/path\z`), func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "value", r.Header.Get("Custom-Header"), "custom proxy header")
require.Equal(t, testVersion, r.Header.Get("Gitlab-Workhorse"), "version header")
_, err := w.Write([]byte(`ok`))
require.NoError(t, err, "write ok response")
})
httpRequest, err := http.NewRequest("POST", ts.URL+"/url/path", nil)
require.NoError(t, err)
w := httptest.NewRecorder()
testProxy := newProxy(ts.URL, nil, proxy.WithCustomHeaders(map[string]string{"Custom-Header": "value"}))
testProxy.ServeHTTP(w, httpRequest)
testhelper.RequireResponseBody(t, w, "ok")
}
func TestProxyError(t *testing.T) {
httpRequest, err := http.NewRequest("POST", "/url/path", bytes.NewBufferString("REQUEST"))
require.NoError(t, err)