Commit e015edfc authored by svistas's avatar svistas

Expand the dashbord fixture to include metrics data

Prior to this change, the dashboard fixture
was only generating the dashboard json
to feed to the integration specs.

This change allows to make the tests
more dynamic by introducing the metrics data
too and avoid a hardcoded fixture to mantain.

Apply diff and update snapshot

Rename to dashboardProps

Fix CI issues
parent 4a8e1e7a
......@@ -353,7 +353,10 @@ export default {
</gl-deprecated-button>
</div>
<div v-if="externalDashboardUrl.length" class="mb-2 mr-2 d-flex d-sm-block">
<div
v-if="externalDashboardUrl && externalDashboardUrl.length"
class="mb-2 mr-2 d-flex d-sm-block"
>
<gl-deprecated-button
class="flex-grow-1 js-external-dashboard-link"
variant="primary"
......
import Vue from 'vue';
import { GlToast } from '@gitlab/ui';
import { parseBoolean } from '~/lib/utils/common_utils';
import { getParameterValues } from '~/lib/utils/url_utility';
import { createStore } from './stores';
import createRouter from './router';
import { stateAndPropsFromDataset } from './utils';
Vue.use(GlToast);
......@@ -12,37 +12,10 @@ export default (props = {}) => {
if (el && el.dataset) {
const [currentDashboard] = getParameterValues('dashboard');
const { metricsDashboardBasePath, ...dataset } = el.dataset;
const {
deploymentsEndpoint,
dashboardEndpoint,
dashboardsEndpoint,
projectPath,
logsPath,
currentEnvironmentName,
dashboardTimezone,
metricsDashboardBasePath,
customDashboardBasePath,
...dataProps
} = el.dataset;
const store = createStore({
currentDashboard,
deploymentsEndpoint,
dashboardEndpoint,
dashboardsEndpoint,
dashboardTimezone,
projectPath,
logsPath,
currentEnvironmentName,
customDashboardBasePath,
});
// HTML attributes are always strings, parse other types.
dataProps.hasMetrics = parseBoolean(dataProps.hasMetrics);
dataProps.customMetricsAvailable = parseBoolean(dataProps.customMetricsAvailable);
dataProps.prometheusAlertsAvailable = parseBoolean(dataProps.prometheusAlertsAvailable);
const { initState, dataProps } = stateAndPropsFromDataset({ currentDashboard, ...dataset });
const store = createStore(initState);
const router = createRouter(metricsDashboardBasePath);
// eslint-disable-next-line no-new
......
......@@ -5,6 +5,7 @@ import {
removeParams,
updateHistory,
} from '~/lib/utils/url_utility';
import { parseBoolean } from '~/lib/utils/common_utils';
import {
timeRangeParamNames,
timeRangeFromParams,
......@@ -12,6 +13,46 @@ import {
} from '~/lib/utils/datetime_range';
import { VARIABLE_PREFIX } from './constants';
/**
* Extracts the initial state and props from HTML dataset
* and places them in separate objects to setup bundle.
* @param {*} dataset
*/
export const stateAndPropsFromDataset = (dataset = {}) => {
const {
currentDashboard,
deploymentsEndpoint,
dashboardEndpoint,
dashboardsEndpoint,
dashboardTimezone,
projectPath,
logsPath,
currentEnvironmentName,
customDashboardBasePath,
...dataProps
} = dataset;
// HTML attributes are always strings, parse other types.
dataProps.hasMetrics = parseBoolean(dataProps.hasMetrics);
dataProps.customMetricsAvailable = parseBoolean(dataProps.customMetricsAvailable);
dataProps.prometheusAlertsAvailable = parseBoolean(dataProps.prometheusAlertsAvailable);
return {
initState: {
currentDashboard,
deploymentsEndpoint,
dashboardEndpoint,
dashboardsEndpoint,
dashboardTimezone,
projectPath,
logsPath,
currentEnvironmentName,
customDashboardBasePath,
},
dataProps,
};
};
/**
* List of non time range url parameters
* This will be removed once we add support for free text variables
......
......@@ -6,10 +6,11 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
include MetricsDashboardHelpers
let(:user) { create(:user) }
let(:project) { project_with_dashboard('.gitlab/dashboards/test.yml') }
let(:environment) { create(:environment, project: project) }
let(:params) { { environment: environment } }
let_it_be(:user) { create(:user) }
let_it_be(:namespace) { create(:namespace, name: 'monitoring' )}
let_it_be(:project) { project_with_dashboard_namespace('.gitlab/dashboards/test.yml', namespace: namespace) }
let_it_be(:environment) { create(:environment, id: 1, project: project) }
let_it_be(:params) { { environment: environment } }
before(:all) do
clean_frontend_fixtures('metrics_dashboard/')
......@@ -24,6 +25,7 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do
project.add_maintainer(user)
allow(controller).to receive(:project).and_return(project)
allow(controller).to receive(:environment).and_return(environment)
allow(controller)
.to receive(:metrics_dashboard_params)
.and_return(params)
......@@ -35,7 +37,9 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do
it 'metrics_dashboard/environment_metrics_dashboard.json' do
routes.draw { get "metrics_dashboard" => "anonymous#metrics_dashboard" }
response = get :metrics_dashboard, format: :json
expect(response).to be_successful
end
end
......@@ -4,6 +4,10 @@ exports[`Dashboard template matches the default snapshot 1`] = `
<div
class="prometheus-graphs"
data-qa-selector="prometheus_graphs"
environmentstate="available"
metricsdashboardbasepath="/monitoring/monitor-project/-/environments/1/metrics"
metricsendpoint="/monitoring/monitor-project/-/environments/1/additional_metrics.json"
prometheusstatus=""
>
<div
class="prometheus-graphs-header d-sm-flex flex-sm-wrap pt-2 pr-1 pb-0 pl-2 border-bottom bg-gray-light"
......@@ -135,15 +139,15 @@ exports[`Dashboard template matches the default snapshot 1`] = `
<!---->
<empty-state-stub
clusterspath="/path/to/clusters"
documentationpath="/path/to/docs"
emptygettingstartedsvgpath="/path/to/getting-started.svg"
emptyloadingsvgpath="/path/to/loading.svg"
emptynodatasmallsvgpath="/path/to/no-data-small.svg"
emptynodatasvgpath="/path/to/no-data.svg"
emptyunabletoconnectsvgpath="/path/to/unable-to-connect.svg"
clusterspath="/monitoring/monitor-project/-/clusters"
documentationpath="/help/administration/monitoring/prometheus/index.md"
emptygettingstartedsvgpath="/images/illustrations/monitoring/getting_started.svg"
emptyloadingsvgpath="/images/illustrations/monitoring/loading.svg"
emptynodatasmallsvgpath="/images/illustrations/chart-empty-state-small.svg"
emptynodatasvgpath="/images/illustrations/monitoring/no_data.svg"
emptyunabletoconnectsvgpath="/images/illustrations/monitoring/unable_to_connect.svg"
selectedstate="gettingStarted"
settingspath="/path/to/settings"
settingspath="/monitoring/monitor-project/-/services/prometheus/edit"
/>
</div>
`;
......@@ -18,8 +18,8 @@ import {
singleStatMetricsResult,
graphDataPrometheusQueryRangeMultiTrack,
barMockData,
propsData,
} from '../mock_data';
import { dashboardProps, graphData, graphDataEmpty } from '../fixture_data';
import { panelTypes } from '~/monitoring/constants';
......@@ -32,7 +32,6 @@ import MonitorColumnChart from '~/monitoring/components/charts/column.vue';
import MonitorBarChart from '~/monitoring/components/charts/bar.vue';
import MonitorStackedColumnChart from '~/monitoring/components/charts/stacked_column.vue';
import { graphData, graphDataEmpty } from '../fixture_data';
import { createStore, monitoringDashboard } from '~/monitoring/stores';
import { createStore as createEmbedGroupStore } from '~/monitoring/stores/embed_group';
......@@ -63,7 +62,7 @@ describe('Dashboard Panel', () => {
wrapper = shallowMount(DashboardPanel, {
propsData: {
graphData,
settingsPath: propsData.settingsPath,
settingsPath: dashboardProps.settingsPath,
...props,
},
store,
......@@ -316,7 +315,7 @@ describe('Dashboard Panel', () => {
return wrapper.vm.$nextTick(() => {
expect(findEditCustomMetricLink().text()).toBe('Edit metrics');
expect(findEditCustomMetricLink().attributes('href')).toBe(propsData.settingsPath);
expect(findEditCustomMetricLink().attributes('href')).toBe(dashboardProps.settingsPath);
});
});
});
......@@ -433,7 +432,7 @@ describe('Dashboard Panel', () => {
wrapper = shallowMount(DashboardPanel, {
propsData: {
clipboardText: exampleText,
settingsPath: propsData.settingsPath,
settingsPath: dashboardProps.settingsPath,
graphData: {
y_label: 'metric',
...graphData,
......@@ -483,7 +482,7 @@ describe('Dashboard Panel', () => {
wrapper = shallowMount(DashboardPanel, {
propsData: {
graphData,
settingsPath: propsData.settingsPath,
settingsPath: dashboardProps.settingsPath,
namespace: mockNamespace,
},
store,
......
......@@ -29,8 +29,12 @@ import {
setupStoreWithVariable,
setupStoreWithLinks,
} from '../store_utils';
import { environmentData, dashboardGitResponse, propsData } from '../mock_data';
import { metricsDashboardViewModel, metricsDashboardPanelCount } from '../fixture_data';
import { environmentData, dashboardGitResponse } from '../mock_data';
import {
metricsDashboardViewModel,
metricsDashboardPanelCount,
dashboardProps,
} from '../fixture_data';
import createFlash from '~/flash';
jest.mock('~/flash');
......@@ -50,7 +54,7 @@ describe('Dashboard', () => {
const createShallowWrapper = (props = {}, options = {}) => {
wrapper = shallowMount(Dashboard, {
propsData: { ...propsData, ...props },
propsData: { ...dashboardProps, ...props },
store,
stubs: {
DashboardHeader,
......@@ -61,7 +65,7 @@ describe('Dashboard', () => {
const createMountedWrapper = (props = {}, options = {}) => {
wrapper = mount(Dashboard, {
propsData: { ...propsData, ...props },
propsData: { ...dashboardProps, ...props },
store,
stubs: {
'graph-group': true,
......
......@@ -5,7 +5,7 @@ import Dashboard from '~/monitoring/components/dashboard.vue';
import DashboardHeader from '~/monitoring/components/dashboard_header.vue';
import { createStore } from '~/monitoring/stores';
import { setupAllDashboards } from '../store_utils';
import { propsData } from '../mock_data';
import { dashboardProps } from '../fixture_data';
jest.mock('~/lib/utils/url_utility');
......@@ -29,7 +29,7 @@ describe('Dashboard template', () => {
it('matches the default snapshot', () => {
wrapper = shallowMount(Dashboard, {
propsData: { ...propsData },
propsData: { ...dashboardProps },
store,
stubs: {
DashboardHeader,
......
......@@ -9,7 +9,8 @@ import {
updateHistory,
} from '~/lib/utils/url_utility';
import axios from '~/lib/utils/axios_utils';
import { mockProjectDir, propsData } from '../mock_data';
import { mockProjectDir } from '../mock_data';
import { dashboardProps } from '../fixture_data';
import Dashboard from '~/monitoring/components/dashboard.vue';
import DashboardHeader from '~/monitoring/components/dashboard_header.vue';
......@@ -26,7 +27,7 @@ describe('dashboard invalid url parameters', () => {
const createMountedWrapper = (props = { hasMetrics: true }, options = {}) => {
wrapper = mount(Dashboard, {
propsData: { ...propsData, ...props },
propsData: { ...dashboardProps, ...props },
store,
stubs: { 'graph-group': true, 'dashboard-panel': true, 'dashboard-header': DashboardHeader },
...options,
......
import { stateAndPropsFromDataset } from '~/monitoring/utils';
import { mapToDashboardViewModel } from '~/monitoring/stores/utils';
import { metricStates } from '~/monitoring/constants';
import { convertObjectProps } from '~/lib/utils/common_utils';
import { convertToCamelCase } from '~/lib/utils/text_utility';
import { metricsResult } from './mock_data';
......@@ -8,6 +11,19 @@ export const metricsDashboardResponse = getJSONFixture(
'metrics_dashboard/environment_metrics_dashboard.json',
);
export const metricsDashboardPayload = metricsDashboardResponse.dashboard;
const datasetState = stateAndPropsFromDataset(
// It's preferable to have props in snake_case, this will be addressed at:
// https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33574
convertObjectProps(
// Some props use kebab-case, convert to snake_case first
key => convertToCamelCase(key.replace(/-/g, '_')),
metricsDashboardResponse.metrics_data,
),
);
export const dashboardProps = datasetState.dataProps;
export const metricsDashboardViewModel = mapToDashboardViewModel(metricsDashboardPayload);
export const metricsDashboardPanelCount = 22;
......
......@@ -11,8 +11,8 @@ import MockAdapter from 'axios-mock-adapter';
import Dashboard from '~/monitoring/components/dashboard.vue';
import { createStore } from '~/monitoring/stores';
import axios from '~/lib/utils/axios_utils';
import { mockApiEndpoint, propsData } from '../mock_data';
import { metricsDashboardPayload } from '../fixture_data';
import { mockApiEndpoint } from '../mock_data';
import { metricsDashboardPayload, dashboardProps } from '../fixture_data';
import { setupStoreWithData } from '../store_utils';
const localVue = createLocalVue();
......@@ -56,7 +56,7 @@ describe('Dashboard', () => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: {
...propsData,
...dashboardProps,
hasMetrics: true,
showPanels: true,
},
......
......@@ -7,6 +7,12 @@ module MetricsDashboardHelpers
create(:project, :custom_repo, files: { dashboard_path => dashboard_yml })
end
def project_with_dashboard_namespace(dashboard_path, dashboard_yml = nil)
dashboard_yml ||= fixture_file('lib/gitlab/metrics/dashboard/sample_dashboard.yml')
create(:project, :custom_repo, namespace: namespace, path: 'monitor-project', files: { dashboard_path => dashboard_yml })
end
def delete_project_dashboard(project, user, dashboard_path)
project.repository.delete_file(
user,
......
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