summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-10-21 12:06:14 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-10-21 12:06:14 +0000
commit664c4c7b49c6056136299817eb79e9f1de83e567 (patch)
treeff9e4f53481d42284f82664722278e05f5bbbcbd /spec
parent6791eefead979110cc773720daee6e58c56483d9 (diff)
downloadgitlab-ce-664c4c7b49c6056136299817eb79e9f1de83e567.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/grafana_integrations.rb2
-rw-r--r--spec/features/admin/admin_settings_spec.rb31
-rw-r--r--spec/fixtures/grafana/dashboard_response.json764
-rw-r--r--spec/fixtures/grafana/datasource_response.json21
-rw-r--r--spec/fixtures/grafana/expected_grafana_embed.json27
-rw-r--r--spec/fixtures/grafana/simplified_dashboard_response.json40
-rw-r--r--spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json1
-rw-r--r--spec/fixtures/lib/gitlab/metrics/dashboard/schemas/panels.json1
-rw-r--r--spec/lib/gitlab/metrics/dashboard/processor_spec.rb8
-rw-r--r--spec/lib/gitlab/metrics/dashboard/stages/grafana_formatter_spec.rb106
-rw-r--r--spec/lib/grafana/client_spec.rb26
-rw-r--r--spec/requests/api/branches_spec.rb2
-rw-r--r--spec/services/create_branch_service_spec.rb15
-rw-r--r--spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb177
-rw-r--r--spec/support/helpers/grafana_api_helpers.rb32
-rw-r--r--spec/support/helpers/login_helpers.rb2
16 files changed, 1247 insertions, 8 deletions
diff --git a/spec/factories/grafana_integrations.rb b/spec/factories/grafana_integrations.rb
index c19417f5a90..4eb3bee8b28 100644
--- a/spec/factories/grafana_integrations.rb
+++ b/spec/factories/grafana_integrations.rb
@@ -3,7 +3,7 @@
FactoryBot.define do
factory :grafana_integration, class: GrafanaIntegration do
project
- grafana_url { 'https://grafana.com' }
+ grafana_url { 'https://grafana.example.com' }
token { SecureRandom.hex(10) }
end
end
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index e1c9364067a..99a6165cfc9 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_mock_admin_mode do
include StubENV
include TermsHelper
+ include MobileHelpers
let(:admin) { create(:admin) }
@@ -450,6 +451,32 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
expect(page).to have_link(text: 'Support', href: new_support_url)
end
end
+
+ it 'Shows admin dashboard links on bigger screen' do
+ visit root_dashboard_path
+
+ page.within '.navbar' do
+ expect(page).to have_link(text: 'Admin Area', href: admin_root_path, visible: true)
+ expect(page).to have_link(text: 'Leave Admin Mode', href: destroy_admin_session_path, visible: true)
+ end
+ end
+
+ it 'Relocates admin dashboard links to dropdown list on smaller screen', :js do
+ resize_screen_xs
+ visit root_dashboard_path
+
+ page.within '.navbar' do
+ expect(page).not_to have_link(text: 'Admin Area', href: admin_root_path, visible: true)
+ expect(page).not_to have_link(text: 'Leave Admin Mode', href: destroy_admin_session_path, visible: true)
+ end
+
+ find('.header-more').click
+
+ page.within '.navbar' do
+ expect(page).to have_link(text: 'Admin Area', href: admin_root_path, visible: true)
+ expect(page).to have_link(text: 'Leave Admin Mode', href: destroy_admin_session_path, visible: true)
+ end
+ end
end
context 'when in admin_mode' do
@@ -462,7 +489,7 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
it 'can leave admin mode' do
page.within('.navbar-sub-nav') do
# Select first, link is also included in mobile view list
- click_on 'Leave admin mode', match: :first
+ click_on 'Leave Admin Mode', match: :first
expect(page).to have_link(href: new_admin_session_path)
end
@@ -481,7 +508,7 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
before do
page.within('.navbar-sub-nav') do
# Select first, link is also included in mobile view list
- click_on 'Leave admin mode', match: :first
+ click_on 'Leave Admin Mode', match: :first
end
end
diff --git a/spec/fixtures/grafana/dashboard_response.json b/spec/fixtures/grafana/dashboard_response.json
new file mode 100644
index 00000000000..4743ec39b44
--- /dev/null
+++ b/spec/fixtures/grafana/dashboard_response.json
@@ -0,0 +1,764 @@
+{
+ "meta": {
+ "type": "db",
+ "canSave": true,
+ "canEdit": true,
+ "canAdmin": true,
+ "canStar": true,
+ "slug": "gitlab-omnibus-redis",
+ "url": "/-/grafana/d/XDaNK6amz/gitlab-omnibus-redis",
+ "expires": "0001-01-01T00:00:00Z",
+ "created": "2019-10-04T13:43:20Z",
+ "updated": "2019-10-04T13:43:20Z",
+ "updatedBy": "Anonymous",
+ "createdBy": "Anonymous",
+ "version": 1,
+ "hasAcl": false,
+ "isFolder": false,
+ "folderId": 1,
+ "folderTitle": "GitLab Omnibus",
+ "folderUrl": "/-/grafana/dashboards/f/l2EpNh2Zk/gitlab-omnibus",
+ "provisioned": true,
+ "provisionedExternalId": "redis.json"
+ },
+ "dashboard": {
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations \u0026 Alerts",
+ "type": "dashboard"
+ }
+ ]
+ },
+ "description": "GitLab Omnibus dashboard for Redis servers",
+ "editable": true,
+ "gnetId": 763,
+ "graphTooltip": 0,
+ "id": 3,
+ "iteration": 1556027798221,
+ "links": [],
+ "panels": [
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"],
+ "datasource": "GitLab Omnibus",
+ "decimals": 0,
+ "editable": true,
+ "error": false,
+ "format": "dtdurations",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": { "h": 3, "w": 4, "x": 0, "y": 0 },
+ "id": 9,
+ "interval": null,
+ "isNew": true,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ { "name": "value to text", "value": 1 },
+ { "name": "range to text", "value": 2 }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [{ "from": "null", "text": "N/A", "to": "null" }],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "addr",
+ "targets": [
+ {
+ "expr": "avg(time() - redis_start_time_seconds{instance=~\"$instance\"})",
+ "format": "time_series",
+ "instant": true,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "metric": "",
+ "refId": "A",
+ "step": 1800
+ }
+ ],
+ "thresholds": "",
+ "title": "Uptime",
+ "type": "singlestat",
+ "valueFontSize": "70%",
+ "valueMaps": [{ "op": "=", "text": "N/A", "value": "null" }],
+ "valueName": "current"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"],
+ "datasource": "GitLab Omnibus",
+ "decimals": 0,
+ "editable": true,
+ "error": false,
+ "format": "none",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": { "h": 3, "w": 4, "x": 4, "y": 0 },
+ "hideTimeOverride": true,
+ "id": 12,
+ "interval": null,
+ "isNew": true,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ { "name": "value to text", "value": 1 },
+ { "name": "range to text", "value": 2 }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [{ "from": "null", "text": "N/A", "to": "null" }],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": true
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(\n avg_over_time(redis_connected_clients{instance=~\"$instance\"}[$__interval])\n)",
+ "format": "time_series",
+ "interval": "1m",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "metric": "",
+ "refId": "A",
+ "step": 2
+ }
+ ],
+ "thresholds": "",
+ "timeFrom": "1m",
+ "timeShift": null,
+ "title": "Clients",
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [{ "op": "=", "text": "N/A", "value": "null" }],
+ "valueName": "avg"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "GitLab Omnibus",
+ "editable": true,
+ "error": false,
+ "fill": 1,
+ "grid": {},
+ "gridPos": { "h": 6, "w": 8, "x": 8, "y": 0 },
+ "id": 2,
+ "isNew": true,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(\n rate(redis_commands_processed_total{instance=~\"$instance\"}[$__interval])\n)",
+ "format": "time_series",
+ "interval": "1m",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "metric": "A",
+ "refId": "A",
+ "step": 240,
+ "target": ""
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Commands Executed",
+ "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "cumulative" },
+ "type": "graph",
+ "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] },
+ "yaxes": [
+ { "format": "reqps", "label": null, "logBase": 1, "max": null, "min": "0", "show": true },
+ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }
+ ],
+ "yaxis": { "align": false, "alignLevel": null }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "GitLab Omnibus",
+ "decimals": 2,
+ "editable": true,
+ "error": false,
+ "fill": 1,
+ "grid": {},
+ "gridPos": { "h": 6, "w": 8, "x": 16, "y": 0 },
+ "id": 1,
+ "isNew": true,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": true,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(\n rate(redis_keyspace_hits_total{instance=~\"$instance\"}[$__interval])\n)",
+ "format": "time_series",
+ "hide": false,
+ "interval": "1m",
+ "intervalFactor": 1,
+ "legendFormat": "hits",
+ "metric": "",
+ "refId": "A",
+ "step": 240,
+ "target": ""
+ },
+ {
+ "expr": "sum(\n rate(redis_keyspace_misses_total{instance=~\"$instance\"}[$__interval])\n)",
+ "format": "time_series",
+ "hide": false,
+ "interval": "1m",
+ "intervalFactor": 1,
+ "legendFormat": "misses",
+ "metric": "",
+ "refId": "B",
+ "step": 240,
+ "target": ""
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Hits, Misses per Second",
+ "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "individual" },
+ "type": "graph",
+ "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] },
+ "yaxes": [
+ { "format": "short", "label": "", "logBase": 1, "max": null, "min": 0, "show": true },
+ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }
+ ],
+ "yaxis": { "align": false, "alignLevel": null }
+ },
+ {
+ "aliasColors": { "max": "#BF1B00" },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "GitLab Omnibus",
+ "editable": true,
+ "error": false,
+ "fill": 1,
+ "grid": {},
+ "gridPos": { "h": 10, "w": 8, "x": 0, "y": 3 },
+ "id": 7,
+ "isNew": true,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "hideEmpty": false,
+ "hideZero": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null as zero",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [{ "alias": "/max - .*/", "dashes": true }],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "redis_memory_used_bytes{instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "used - {{instance}}",
+ "metric": "",
+ "refId": "A",
+ "step": 240,
+ "target": ""
+ },
+ {
+ "expr": "redis_config_maxmemory{instance=~\"$instance\"} \u003e 0",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "max - {{instance}}",
+ "refId": "B",
+ "step": 240
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Memory Usage",
+ "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "cumulative" },
+ "type": "graph",
+ "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] },
+ "yaxes": [
+ { "format": "bytes", "label": null, "logBase": 1, "max": null, "min": 0, "show": true },
+ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }
+ ],
+ "yaxis": { "align": false, "alignLevel": null }
+ },
+ {
+ "aliasColors": {
+ "evicts": "#890F02",
+ "memcached_items_evicted_total{instance=\"172.17.0.1:9150\",job=\"prometheus\"}": "#890F02",
+ "reclaims": "#3F6833"
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "GitLab Omnibus",
+ "editable": true,
+ "error": false,
+ "fill": 1,
+ "grid": {},
+ "gridPos": { "h": 7, "w": 8, "x": 8, "y": 6 },
+ "id": 8,
+ "isNew": true,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [{ "alias": "reclaims", "yaxis": 2 }],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(redis_expired_keys_total{instance=~\"$instance\"}[$__interval]))",
+ "format": "time_series",
+ "interval": "1m",
+ "intervalFactor": 2,
+ "legendFormat": "expired",
+ "metric": "",
+ "refId": "A",
+ "step": 240,
+ "target": ""
+ },
+ {
+ "expr": "sum(rate(redis_evicted_keys_total{instance=~\"$instance\"}[$__interval]))",
+ "format": "time_series",
+ "interval": "1m",
+ "intervalFactor": 2,
+ "legendFormat": "evicted",
+ "refId": "B",
+ "step": 240
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Expired / Evicted",
+ "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "cumulative" },
+ "type": "graph",
+ "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] },
+ "yaxes": [
+ { "format": "short", "label": null, "logBase": 1, "max": null, "min": "0", "show": true },
+ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }
+ ],
+ "yaxis": { "align": false, "alignLevel": null }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "GitLab Omnibus",
+ "editable": true,
+ "error": false,
+ "fill": 1,
+ "grid": {},
+ "gridPos": { "h": 7, "w": 8, "x": 16, "y": 6 },
+ "id": 10,
+ "isNew": true,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(\n rate(redis_net_input_bytes_total{instance=~\"$instance\"}[$__interval])\n)",
+ "format": "time_series",
+ "interval": "1m",
+ "intervalFactor": 2,
+ "legendFormat": "In",
+ "refId": "A",
+ "step": 240
+ },
+ {
+ "expr": "sum(\n rate(redis_net_output_bytes_total{instance=~\"$instance\"}[$__interval])\n)",
+ "format": "time_series",
+ "interval": "1m",
+ "intervalFactor": 2,
+ "legendFormat": "Out",
+ "refId": "B",
+ "step": 240
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Network I/O",
+ "tooltip": { "msResolution": true, "shared": true, "sort": 0, "value_type": "cumulative" },
+ "type": "graph",
+ "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] },
+ "yaxes": [
+ { "format": "Bps", "label": null, "logBase": 1, "max": null, "min": "0", "show": true },
+ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }
+ ],
+ "yaxis": { "align": false, "alignLevel": null }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "GitLab Omnibus",
+ "editable": true,
+ "error": false,
+ "fill": 8,
+ "grid": {},
+ "gridPos": { "h": 7, "w": 16, "x": 0, "y": 13 },
+ "id": 14,
+ "isNew": true,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "max": true,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum without (instance) (\n rate(redis_commands_total{instance=~\"$instance\"}[$__interval])\n) \u003e 0",
+ "format": "time_series",
+ "interval": "1m",
+ "intervalFactor": 2,
+ "legendFormat": "{{ cmd }}",
+ "metric": "redis_command_calls_total",
+ "refId": "A",
+ "step": 240
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Command Calls / sec",
+ "tooltip": { "msResolution": true, "shared": true, "sort": 2, "value_type": "individual" },
+ "type": "graph",
+ "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] },
+ "yaxes": [
+ { "format": "short", "label": null, "logBase": 1, "max": null, "min": "0", "show": true },
+ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }
+ ],
+ "yaxis": { "align": false, "alignLevel": null }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "GitLab Omnibus",
+ "editable": true,
+ "error": false,
+ "fill": 7,
+ "grid": {},
+ "gridPos": { "h": 7, "w": 8, "x": 16, "y": 13 },
+ "id": 13,
+ "isNew": true,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(redis_db_keys{instance=~\"$instance\"} - redis_db_keys_expiring{instance=~\"$instance\"}) ",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "not expiring",
+ "refId": "A",
+ "step": 240,
+ "target": ""
+ },
+ {
+ "expr": "sum(redis_db_keys_expiring{instance=~\"$instance\"})",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "expiring",
+ "metric": "",
+ "refId": "B",
+ "step": 240
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Expiring vs Not-Expiring Keys",
+ "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "individual" },
+ "type": "graph",
+ "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] },
+ "yaxes": [
+ { "format": "short", "label": null, "logBase": 1, "max": null, "min": "0", "show": true },
+ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }
+ ],
+ "yaxis": { "align": false, "alignLevel": null }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "GitLab Omnibus",
+ "editable": true,
+ "error": false,
+ "fill": 7,
+ "grid": {},
+ "gridPos": { "h": 7, "w": 16, "x": 0, "y": 20 },
+ "id": 5,
+ "isNew": true,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum by (db) (\n redis_db_keys{instance=~\"$instance\"}\n)",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{ db }} ",
+ "refId": "A",
+ "step": 240,
+ "target": ""
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Items per DB",
+ "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "individual" },
+ "type": "graph",
+ "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] },
+ "yaxes": [
+ { "format": "none", "label": null, "logBase": 1, "max": null, "min": "0", "show": true },
+ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }
+ ],
+ "yaxis": { "align": false, "alignLevel": null }
+ }
+ ],
+ "refresh": "1m",
+ "schemaVersion": 18,
+ "style": "dark",
+ "tags": ["redis"],
+ "templating": {
+ "list": [
+ {
+ "allValue": null,
+ "current": { "tags": [], "text": "All", "value": "$__all" },
+ "datasource": "GitLab Omnibus",
+ "definition": "",
+ "hide": 0,
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "instance",
+ "options": [],
+ "query": "label_values(up{job=\"redis\"}, instance)",
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": { "from": "now-24h", "to": "now" },
+ "timepicker": {
+ "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
+ "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
+ },
+ "timezone": "",
+ "title": "GitLab Omnibus - Redis",
+ "uid": "XDaNK6amz",
+ "version": 1
+ }
+}
diff --git a/spec/fixtures/grafana/datasource_response.json b/spec/fixtures/grafana/datasource_response.json
new file mode 100644
index 00000000000..07c075beb35
--- /dev/null
+++ b/spec/fixtures/grafana/datasource_response.json
@@ -0,0 +1,21 @@
+{
+ "id": 1,
+ "orgId": 1,
+ "name": "GitLab Omnibus",
+ "type": "prometheus",
+ "typeLogoUrl": "",
+ "access": "proxy",
+ "url": "http://localhost:9090",
+ "password": "",
+ "user": "",
+ "database": "",
+ "basicAuth": false,
+ "basicAuthUser": "",
+ "basicAuthPassword": "",
+ "withCredentials": false,
+ "isDefault": true,
+ "jsonData": {},
+ "secureJsonFields": {},
+ "version": 1,
+ "readOnly": true
+}
diff --git a/spec/fixtures/grafana/expected_grafana_embed.json b/spec/fixtures/grafana/expected_grafana_embed.json
new file mode 100644
index 00000000000..72fb5477b9e
--- /dev/null
+++ b/spec/fixtures/grafana/expected_grafana_embed.json
@@ -0,0 +1,27 @@
+{
+ "panel_groups": [
+ {
+ "panels": [
+ {
+ "title": "Network I/O",
+ "type": "area-chart",
+ "y_label": "",
+ "metrics": [
+ {
+ "id": "In_0",
+ "query_range": "sum( rate(redis_net_input_bytes_total{instance=~\"localhost:9121\"}[1m]))",
+ "label": "In",
+ "prometheus_endpoint_path": "/foo/bar/-/grafana/proxy/1/api/v1/query_range?query=sum%28++rate%28redis_net_input_bytes_total%7Binstance%3D~%22localhost%3A9121%22%7D%5B1m%5D%29%29"
+ },
+ {
+ "id": "Out_1",
+ "query_range": "sum( rate(redis_net_output_bytes_total{instance=~\"localhost:9121\"}[1m]))",
+ "label": "Out",
+ "prometheus_endpoint_path": "/foo/bar/-/grafana/proxy/1/api/v1/query_range?query=sum%28++rate%28redis_net_output_bytes_total%7Binstance%3D~%22localhost%3A9121%22%7D%5B1m%5D%29%29"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/spec/fixtures/grafana/simplified_dashboard_response.json b/spec/fixtures/grafana/simplified_dashboard_response.json
new file mode 100644
index 00000000000..b450fda082b
--- /dev/null
+++ b/spec/fixtures/grafana/simplified_dashboard_response.json
@@ -0,0 +1,40 @@
+{
+ "dashboard": {
+ "panels": [
+ {
+ "datasource": "GitLab Omnibus",
+ "id": 8,
+ "lines": true,
+ "targets": [
+ {
+ "expr": "sum(\n rate(redis_net_input_bytes_total{instance=~\"$instance\"}[$__interval])\n)",
+ "format": "time_series",
+ "interval": "1m",
+ "legendFormat": "In",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(\n rate(redis_net_output_bytes_total{instance=~\"[[instance]]\"}[$__interval])\n)",
+ "format": "time_series",
+ "interval": "1m",
+ "legendFormat": "Out",
+ "refId": "B"
+ }
+ ],
+ "title": "Network I/O",
+ "type": "graph",
+ "yaxes": [{ "format": "Bps" }, { "format": "short" }]
+ }
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "value": "localhost:9121"
+ },
+ "name": "instance"
+ }
+ ]
+ }
+ }
+}
diff --git a/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json b/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json
index 9c1be32645a..ac40f2dcd13 100644
--- a/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json
+++ b/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json
@@ -1,7 +1,6 @@
{
"type": "object",
"required": [
- "unit",
"label",
"prometheus_endpoint_path"
],
diff --git a/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/panels.json b/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/panels.json
index 1548daacd64..a16f1ef592f 100644
--- a/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/panels.json
+++ b/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/panels.json
@@ -3,7 +3,6 @@
"required": [
"title",
"y_label",
- "weight",
"metrics"
],
"properties": {
diff --git a/spec/lib/gitlab/metrics/dashboard/processor_spec.rb b/spec/lib/gitlab/metrics/dashboard/processor_spec.rb
index e2ce1869810..4fa136bc405 100644
--- a/spec/lib/gitlab/metrics/dashboard/processor_spec.rb
+++ b/spec/lib/gitlab/metrics/dashboard/processor_spec.rb
@@ -25,6 +25,14 @@ describe Gitlab::Metrics::Dashboard::Processor do
end
end
+ context 'when the dashboard is not present' do
+ let(:dashboard_yml) { nil }
+
+ it 'returns nil' do
+ expect(dashboard).to be_nil
+ end
+ end
+
context 'when dashboard config corresponds to common metrics' do
let!(:common_metric) { create(:prometheus_metric, :common, identifier: 'metric_a1') }
diff --git a/spec/lib/gitlab/metrics/dashboard/stages/grafana_formatter_spec.rb b/spec/lib/gitlab/metrics/dashboard/stages/grafana_formatter_spec.rb
new file mode 100644
index 00000000000..5c2ec6dae6b
--- /dev/null
+++ b/spec/lib/gitlab/metrics/dashboard/stages/grafana_formatter_spec.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Metrics::Dashboard::Stages::GrafanaFormatter do
+ include GrafanaApiHelpers
+
+ let_it_be(:namespace) { create(:namespace, name: 'foo') }
+ let_it_be(:project) { create(:project, namespace: namespace, name: 'bar') }
+
+ describe '#transform!' do
+ let(:grafana_dashboard) { JSON.parse(fixture_file('grafana/simplified_dashboard_response.json'), symbolize_names: true) }
+ let(:datasource) { JSON.parse(fixture_file('grafana/datasource_response.json'), symbolize_names: true) }
+
+ let(:dashboard) { described_class.new(project, {}, params).transform! }
+
+ let(:params) do
+ {
+ grafana_dashboard: grafana_dashboard,
+ datasource: datasource,
+ grafana_url: valid_grafana_dashboard_link('https://grafana.example.com')
+ }
+ end
+
+ context 'when the query and resources are configured correctly' do
+ let(:expected_dashboard) { JSON.parse(fixture_file('grafana/expected_grafana_embed.json'), symbolize_names: true) }
+
+ it 'generates a gitlab-yml formatted dashboard' do
+ expect(dashboard).to eq(expected_dashboard)
+ end
+ end
+
+ context 'when the inputs are invalid' do
+ shared_examples_for 'processing error' do
+ it 'raises a processing error' do
+ expect { dashboard }
+ .to raise_error(Gitlab::Metrics::Dashboard::Stages::InputFormatValidator::DashboardProcessingError)
+ end
+ end
+
+ context 'when the datasource is not proxyable' do
+ before do
+ params[:datasource][:access] = 'not-proxy'
+ end
+
+ it_behaves_like 'processing error'
+ end
+
+ context 'when query param "panelId" is not specified' do
+ before do
+ params[:grafana_url].gsub!('panelId=8', '')
+ end
+
+ it_behaves_like 'processing error'
+ end
+
+ context 'when query param "from" is not specified' do
+ before do
+ params[:grafana_url].gsub!('from=1570397739557', '')
+ end
+
+ it_behaves_like 'processing error'
+ end
+
+ context 'when query param "to" is not specified' do
+ before do
+ params[:grafana_url].gsub!('to=1570484139557', '')
+ end
+
+ it_behaves_like 'processing error'
+ end
+
+ context 'when the panel is not a graph' do
+ before do
+ params[:grafana_dashboard][:dashboard][:panels][0][:type] = 'singlestat'
+ end
+
+ it_behaves_like 'processing error'
+ end
+
+ context 'when the panel is not a line graph' do
+ before do
+ params[:grafana_dashboard][:dashboard][:panels][0][:lines] = false
+ end
+
+ it_behaves_like 'processing error'
+ end
+
+ context 'when the query dashboard includes undefined variables' do
+ before do
+ params[:grafana_url].gsub!('&var-instance=localhost:9121', '')
+ end
+
+ it_behaves_like 'processing error'
+ end
+
+ context 'when the expression contains unsupported global variables' do
+ before do
+ params[:grafana_dashboard][:dashboard][:panels][0][:targets][0][:expr] = 'sum(important_metric[$__interval_ms])'
+ end
+
+ it_behaves_like 'processing error'
+ end
+ end
+ end
+end
diff --git a/spec/lib/grafana/client_spec.rb b/spec/lib/grafana/client_spec.rb
index bd93a3c59a2..699344e940e 100644
--- a/spec/lib/grafana/client_spec.rb
+++ b/spec/lib/grafana/client_spec.rb
@@ -35,7 +35,7 @@ describe Grafana::Client do
it 'does not follow redirects' do
expect { subject }.to raise_exception(
Grafana::Client::Error,
- 'Grafana response status code: 302'
+ 'Grafana response status code: 302, Message: {}'
)
expect(redirect_req_stub).to have_been_requested
@@ -67,6 +67,30 @@ describe Grafana::Client do
end
end
+ describe '#get_dashboard' do
+ let(:grafana_api_url) { 'https://grafanatest.com/-/grafana-project/api/dashboards/uid/FndfgnX' }
+
+ subject do
+ client.get_dashboard(uid: 'FndfgnX')
+ end
+
+ it_behaves_like 'calls grafana api'
+ it_behaves_like 'no redirects'
+ it_behaves_like 'handles exceptions'
+ end
+
+ describe '#get_datasource' do
+ let(:grafana_api_url) { 'https://grafanatest.com/-/grafana-project/api/datasources/name/Test%20Name' }
+
+ subject do
+ client.get_datasource(name: 'Test Name')
+ end
+
+ it_behaves_like 'calls grafana api'
+ it_behaves_like 'no redirects'
+ it_behaves_like 'handles exceptions'
+ end
+
describe '#proxy_datasource' do
let(:grafana_api_url) do
'https://grafanatest.com/-/grafana-project/' \
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index f9c8b42afa8..d1e20cb1770 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -602,7 +602,7 @@ describe API::Branches do
post api(route, user), params: { branch: 'new_design3', ref: 'foo' }
expect(response).to have_gitlab_http_status(400)
- expect(json_response['message']).to eq('Invalid reference name')
+ expect(json_response['message']).to eq('Invalid reference name: new_design3')
end
end
diff --git a/spec/services/create_branch_service_spec.rb b/spec/services/create_branch_service_spec.rb
index 0d34c7f9a82..9661173c9e7 100644
--- a/spec/services/create_branch_service_spec.rb
+++ b/spec/services/create_branch_service_spec.rb
@@ -22,5 +22,20 @@ describe CreateBranchService do
expect(project.repository.branch_exists?('my-feature')).to be_truthy
end
end
+
+ context 'when creating a branch fails' do
+ let(:project) { create(:project_empty_repo) }
+
+ before do
+ allow(project.repository).to receive(:add_branch).and_return(false)
+ end
+
+ it 'retruns an error with the branch name' do
+ result = service.execute('my-feature', 'master')
+
+ expect(result[:status]).to eq(:error)
+ expect(result[:message]).to eq("Invalid reference name: my-feature")
+ end
+ end
end
end
diff --git a/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb b/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb
new file mode 100644
index 00000000000..f200c636aac
--- /dev/null
+++ b/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb
@@ -0,0 +1,177 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Metrics::Dashboard::GrafanaMetricEmbedService do
+ include MetricsDashboardHelpers
+ include ReactiveCachingHelpers
+ include GrafanaApiHelpers
+
+ let_it_be(:project) { build(:project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:grafana_integration) { create(:grafana_integration, project: project) }
+
+ let(:grafana_url) do
+ valid_grafana_dashboard_link(grafana_integration.grafana_url)
+ end
+
+ before do
+ project.add_maintainer(user)
+ end
+
+ describe '.valid_params?' do
+ let(:valid_params) { { embedded: true, grafana_url: grafana_url } }
+
+ subject { described_class.valid_params?(params) }
+
+ let(:params) { valid_params }
+
+ it { is_expected.to be_truthy }
+
+ context 'not embedded' do
+ let(:params) { valid_params.except(:embedded) }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'undefined grafana_url' do
+ let(:params) { valid_params.except(:grafana_url) }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe '.from_cache' do
+ let(:params) { [project.id, user.id, grafana_url] }
+
+ subject { described_class.from_cache(*params) }
+
+ it 'initializes an instance of GrafanaMetricEmbedService' do
+ expect(subject).to be_an_instance_of(described_class)
+ expect(subject.project).to eq(project)
+ expect(subject.current_user).to eq(user)
+ expect(subject.params[:grafana_url]).to eq(grafana_url)
+ end
+ end
+
+ describe '#get_dashboard', :use_clean_rails_memory_store_caching do
+ let(:service_params) do
+ [
+ project,
+ user,
+ {
+ embedded: true,
+ grafana_url: grafana_url
+ }
+ ]
+ end
+
+ let(:service) { described_class.new(*service_params) }
+ let(:service_call) { service.get_dashboard }
+
+ context 'without caching' do
+ before do
+ synchronous_reactive_cache(service)
+ end
+
+ it_behaves_like 'raises error for users with insufficient permissions'
+
+ context 'without a grafana integration' do
+ before do
+ allow(project).to receive(:grafana_integration).and_return(nil)
+ end
+
+ it_behaves_like 'misconfigured dashboard service response', :bad_request
+ end
+
+ context 'when grafana cannot be reached' do
+ before do
+ allow(grafana_integration.client).to receive(:get_dashboard).and_raise(::Grafana::Client::Error)
+ end
+
+ it_behaves_like 'misconfigured dashboard service response', :service_unavailable
+ end
+
+ context 'when panelId is missing' do
+ let(:grafana_url) do
+ grafana_integration.grafana_url +
+ '/d/XDaNK6amz/gitlab-omnibus-redis' \
+ '?from=1570397739557&to=1570484139557'
+ end
+
+ before do
+ stub_dashboard_request(grafana_integration.grafana_url)
+ end
+
+ it_behaves_like 'misconfigured dashboard service response', :unprocessable_entity
+ end
+
+ context 'when uid is missing' do
+ let(:grafana_url) { grafana_integration.grafana_url + '/d/' }
+
+ before do
+ stub_dashboard_request(grafana_integration.grafana_url)
+ end
+
+ it_behaves_like 'misconfigured dashboard service response', :unprocessable_entity
+ end
+
+ context 'when the dashboard response contains misconfigured json' do
+ before do
+ stub_dashboard_request(grafana_integration.grafana_url, body: '')
+ end
+
+ it_behaves_like 'misconfigured dashboard service response', :unprocessable_entity
+ end
+
+ context 'when the datasource response contains misconfigured json' do
+ before do
+ stub_dashboard_request(grafana_integration.grafana_url)
+ stub_datasource_request(grafana_integration.grafana_url, body: '')
+ end
+
+ it_behaves_like 'misconfigured dashboard service response', :unprocessable_entity
+ end
+
+ context 'when the embed was created successfully' do
+ before do
+ stub_dashboard_request(grafana_integration.grafana_url)
+ stub_datasource_request(grafana_integration.grafana_url)
+ end
+
+ it_behaves_like 'valid embedded dashboard service response'
+ end
+ end
+
+ context 'with caching', :use_clean_rails_memory_store_caching do
+ let(:cache_params) { [project.id, user.id, grafana_url] }
+
+ context 'when value not present in cache' do
+ it 'returns nil' do
+ expect(ReactiveCachingWorker)
+ .to receive(:perform_async)
+ .with(service.class, service.id, *cache_params)
+
+ expect(service_call).to eq(nil)
+ end
+ end
+
+ context 'when value present in cache' do
+ let(:return_value) { { 'http_status' => :ok, 'dashboard' => '{}' } }
+
+ before do
+ stub_reactive_cache(service, return_value, cache_params)
+ end
+
+ it 'returns cached value' do
+ expect(ReactiveCachingWorker)
+ .not_to receive(:perform_async)
+ .with(service.class, service.id, *cache_params)
+
+ expect(service_call[:http_status]).to eq(return_value[:http_status])
+ expect(service_call[:dashboard]).to eq(return_value[:dashboard])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/helpers/grafana_api_helpers.rb b/spec/support/helpers/grafana_api_helpers.rb
new file mode 100644
index 00000000000..b212cbf2943
--- /dev/null
+++ b/spec/support/helpers/grafana_api_helpers.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module GrafanaApiHelpers
+ def valid_grafana_dashboard_link(base_url)
+ base_url +
+ '/d/XDaNK6amz/gitlab-omnibus-redis' \
+ '?from=1570397739557&to=1570484139557' \
+ '&var-instance=localhost:9121&panelId=8'
+ end
+
+ def stub_dashboard_request(base_url, path: '/api/dashboards/uid/XDaNK6amz', body: nil)
+ body ||= fixture_file('grafana/dashboard_response.json')
+
+ stub_request(:get, "#{base_url}#{path}")
+ .to_return(
+ status: 200,
+ body: body,
+ headers: { 'Content-Type' => 'application/json' }
+ )
+ end
+
+ def stub_datasource_request(base_url, path: '/api/datasources/name/GitLab%20Omnibus', body: nil)
+ body ||= fixture_file('grafana/datasource_response.json')
+
+ stub_request(:get, "#{base_url}#{path}")
+ .to_return(
+ status: 200,
+ body: body,
+ headers: { 'Content-Type' => 'application/json' }
+ )
+ end
+end
diff --git a/spec/support/helpers/login_helpers.rb b/spec/support/helpers/login_helpers.rb
index 7d5896e4eeb..1d42f26ad3e 100644
--- a/spec/support/helpers/login_helpers.rb
+++ b/spec/support/helpers/login_helpers.rb
@@ -53,7 +53,7 @@ module LoginHelpers
fill_in 'password', with: user.password
- click_button 'Enter admin mode'
+ click_button 'Enter Admin Mode'
end
def gitlab_sign_in_via(provider, user, uid, saml_response = nil)