summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/frontend/diffs/utils/uuids_spec.js92
-rw-r--r--spec/frontend/monitoring/components/dashboard_spec.js17
-rw-r--r--spec/frontend/monitoring/store/utils_spec.js6
-rw-r--r--spec/frontend/monitoring/store_utils.js12
-rw-r--r--spec/frontend/vue_shared/components/project_selector/project_selector_spec.js22
-rw-r--r--spec/initializers/google_api_client_spec.rb17
-rw-r--r--spec/lib/gitlab/auth/ldap/person_spec.rb7
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/models/project_services/prometheus_service_spec.rb44
-rw-r--r--spec/presenters/projects/prometheus/alert_presenter_spec.rb35
-rw-r--r--spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb80
-rw-r--r--spec/services/design_management/delete_designs_service_spec.rb26
-rw-r--r--spec/services/design_management/save_designs_service_spec.rb25
-rw-r--r--spec/services/event_create_service_spec.rb91
14 files changed, 422 insertions, 53 deletions
diff --git a/spec/frontend/diffs/utils/uuids_spec.js b/spec/frontend/diffs/utils/uuids_spec.js
new file mode 100644
index 00000000000..79d3ebadd4f
--- /dev/null
+++ b/spec/frontend/diffs/utils/uuids_spec.js
@@ -0,0 +1,92 @@
+import { uuids } from '~/diffs/utils/uuids';
+
+const HEX = /[a-f0-9]/i;
+const HEX_RE = HEX.source;
+const UUIDV4 = new RegExp(
+ `${HEX_RE}{8}-${HEX_RE}{4}-4${HEX_RE}{3}-[89ab]${HEX_RE}{3}-${HEX_RE}{12}`,
+ 'i',
+);
+
+describe('UUIDs Util', () => {
+ describe('uuids', () => {
+ const SEQUENCE_FOR_GITLAB_SEED = [
+ 'a1826a44-316c-480e-a93d-8cdfeb36617c',
+ 'e049db1f-a4cf-4cba-aa60-6d95e3b547dc',
+ '6e3c737c-13a7-4380-b17d-601f187d7e69',
+ 'bee5cc7f-c486-45c0-8ad3-d1ac5402632d',
+ 'af248c9f-a3a6-4d4f-a311-fe151ffab25a',
+ ];
+ const SEQUENCE_FOR_12345_SEED = [
+ 'edfb51e2-e3e1-4de5-90fd-fd1d21760881',
+ '2f154da4-0a2d-4da9-b45e-0ffed391517e',
+ '91566d65-8836-4222-9875-9e1df4d0bb01',
+ 'f6ea6c76-7640-4d71-a736-9d3bec7a1a8e',
+ 'bfb85869-5fb9-4c5b-a750-5af727ac5576',
+ ];
+
+ it('returns version 4 UUIDs', () => {
+ expect(uuids()[0]).toMatch(UUIDV4);
+ });
+
+ it('outputs an array of UUIDs', () => {
+ const ids = uuids({ count: 11 });
+
+ expect(ids.length).toEqual(11);
+ expect(ids.every(id => UUIDV4.test(id))).toEqual(true);
+ });
+
+ it.each`
+ seeds | uuid
+ ${['some', 'special', 'seed']} | ${'6fa53e51-0f70-4072-9c84-1c1eee1b9934'}
+ ${['magic']} | ${'fafae8cd-7083-44f3-b82d-43b30bd27486'}
+ ${['seeded']} | ${'e06ed291-46c5-4e42-836b-e7c772d48b49'}
+ ${['GitLab']} | ${'a1826a44-316c-480e-a93d-8cdfeb36617c'}
+ ${['JavaScript']} | ${'12dfb297-1560-4c38-9775-7178ef8472fb'}
+ ${[99, 169834, 2619]} | ${'3ecc8ad6-5b7c-4c9b-94a8-c7271c2fa083'}
+ ${[12]} | ${'2777374b-723b-469b-bd73-e586df964cfd'}
+ ${[9876, 'mixed!', 7654]} | ${'865212e0-4a16-4934-96f9-103cf36a6931'}
+ ${[123, 1234, 12345, 6]} | ${'40aa2ee6-0a11-4e67-8f09-72f5eba04244'}
+ ${[0]} | ${'8c7f0aac-97c4-4a2f-b716-a675d821ccc0'}
+ `(
+ 'should always output the UUID $uuid when the options.seeds argument is $seeds',
+ ({ uuid, seeds }) => {
+ expect(uuids({ seeds })[0]).toEqual(uuid);
+ },
+ );
+
+ describe('unseeded UUID randomness', () => {
+ const nonRandom = Array(6)
+ .fill(0)
+ .map((_, i) => uuids({ seeds: [i] })[0]);
+ const random = uuids({ count: 6 });
+ const moreRandom = uuids({ count: 6 });
+
+ it('is different from a seeded result', () => {
+ random.forEach((id, i) => {
+ expect(id).not.toEqual(nonRandom[i]);
+ });
+ });
+
+ it('is different from other random results', () => {
+ random.forEach((id, i) => {
+ expect(id).not.toEqual(moreRandom[i]);
+ });
+ });
+
+ it('never produces any duplicates', () => {
+ expect(new Set(random).size).toEqual(random.length);
+ });
+ });
+
+ it.each`
+ seed | sequence
+ ${'GitLab'} | ${SEQUENCE_FOR_GITLAB_SEED}
+ ${12345} | ${SEQUENCE_FOR_12345_SEED}
+ `(
+ 'should output the same sequence of UUIDs for the given seed "$seed"',
+ ({ seed, sequence }) => {
+ expect(uuids({ seeds: [seed], count: 5 })).toEqual(sequence);
+ },
+ );
+ });
+});
diff --git a/spec/frontend/monitoring/components/dashboard_spec.js b/spec/frontend/monitoring/components/dashboard_spec.js
index 5e2d2847cad..7bb4c68b4cd 100644
--- a/spec/frontend/monitoring/components/dashboard_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_spec.js
@@ -16,6 +16,7 @@ import DashboardsDropdown from '~/monitoring/components/dashboards_dropdown.vue'
import EmptyState from '~/monitoring/components/empty_state.vue';
import GroupEmptyState from '~/monitoring/components/group_empty_state.vue';
import DashboardPanel from '~/monitoring/components/dashboard_panel.vue';
+import LinksSection from '~/monitoring/components/links_section.vue';
import { createStore } from '~/monitoring/stores';
import * as types from '~/monitoring/stores/mutation_types';
import {
@@ -24,6 +25,7 @@ import {
setMetricResult,
setupStoreWithData,
setupStoreWithVariable,
+ setupStoreWithLinks,
} from '../store_utils';
import { environmentData, dashboardGitResponse, propsData } from '../mock_data';
import { metricsDashboardViewModel, metricsDashboardPanelCount } from '../fixture_data';
@@ -483,6 +485,21 @@ describe('Dashboard', () => {
});
});
+ describe('links section', () => {
+ beforeEach(() => {
+ createShallowWrapper({ hasMetrics: true });
+ setupStoreWithData(store);
+ setupStoreWithLinks(store);
+
+ return wrapper.vm.$nextTick();
+ });
+
+ it('shows the links section', () => {
+ expect(wrapper.vm.shouldShowLinksSection).toBe(true);
+ expect(wrapper.find(LinksSection)).toExist();
+ });
+ });
+
describe('single panel expands to "full screen" mode', () => {
const findExpandedPanel = () => wrapper.find({ ref: 'expandedPanel' });
diff --git a/spec/frontend/monitoring/store/utils_spec.js b/spec/frontend/monitoring/store/utils_spec.js
index f6c2b5b9682..02cdd3d7f41 100644
--- a/spec/frontend/monitoring/store/utils_spec.js
+++ b/spec/frontend/monitoring/store/utils_spec.js
@@ -16,6 +16,8 @@ describe('mapToDashboardViewModel', () => {
expect(mapToDashboardViewModel({})).toEqual({
dashboard: '',
panelGroups: [],
+ links: [],
+ variables: {},
});
});
@@ -44,6 +46,8 @@ describe('mapToDashboardViewModel', () => {
expect(mapToDashboardViewModel(response)).toEqual({
dashboard: 'Dashboard Name',
+ links: [],
+ variables: {},
panelGroups: [
{
group: 'Group 1',
@@ -76,6 +80,8 @@ describe('mapToDashboardViewModel', () => {
it('key', () => {
const response = {
dashboard: 'Dashboard Name',
+ links: [],
+ variables: {},
panel_groups: [
{
group: 'Group A',
diff --git a/spec/frontend/monitoring/store_utils.js b/spec/frontend/monitoring/store_utils.js
index 8ac8b4367c6..eb2578aa9db 100644
--- a/spec/frontend/monitoring/store_utils.js
+++ b/spec/frontend/monitoring/store_utils.js
@@ -38,6 +38,18 @@ export const setupStoreWithVariable = store => {
});
};
+export const setupStoreWithLinks = store => {
+ store.commit(`monitoringDashboard/${types.RECEIVE_METRICS_DASHBOARD_SUCCESS}`, {
+ ...metricsDashboardPayload,
+ links: [
+ {
+ title: 'GitLab Website',
+ url: `https://gitlab.com/website`,
+ },
+ ],
+ });
+};
+
export const setupStoreWithData = store => {
setupAllDashboards(store);
setupStoreWithDashboard(store);
diff --git a/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js b/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js
index 691e98236e4..6d1ebe85aa0 100644
--- a/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js
+++ b/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js
@@ -110,4 +110,26 @@ describe('ProjectSelector component', () => {
);
});
});
+
+ describe('the search results legend', () => {
+ it.each`
+ count | total | expected
+ ${0} | ${0} | ${'Showing 0 projects'}
+ ${1} | ${0} | ${'Showing 1 project'}
+ ${2} | ${0} | ${'Showing 2 projects'}
+ ${2} | ${3} | ${'Showing 2 of 3 projects'}
+ `(
+ 'is "$expected" given $count results are showing out of $total',
+ ({ count, total, expected }) => {
+ wrapper.setProps({
+ projectSearchResults: searchResults.slice(0, count),
+ totalResults: total,
+ });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.text()).toContain(expected);
+ });
+ },
+ );
+ });
});
diff --git a/spec/initializers/google_api_client_spec.rb b/spec/initializers/google_api_client_spec.rb
deleted file mode 100644
index 44a1bc0836c..00000000000
--- a/spec/initializers/google_api_client_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-describe './config/initializers/google_api_client.rb' do
- subject { Google::Apis::ContainerV1beta1 }
-
- it 'is needed' do |example|
- is_expected.not_to be_const_defined(:CloudRunConfig),
- <<-MSG.strip_heredoc
- The google-api-client gem has been upgraded!
- Remove:
- #{example.example_group.description}
- #{example.file_path}
- MSG
- end
-end
diff --git a/spec/lib/gitlab/auth/ldap/person_spec.rb b/spec/lib/gitlab/auth/ldap/person_spec.rb
index e90917cfce1..403a48d40ef 100644
--- a/spec/lib/gitlab/auth/ldap/person_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/person_spec.rb
@@ -57,14 +57,17 @@ describe Gitlab::Auth::Ldap::Person do
'attributes' => {
'name' => 'cn',
'email' => 'mail',
- 'username' => %w(uid mail memberof)
+ 'username' => %w(uid mail),
+ 'first_name' => ''
}
}
)
config = Gitlab::Auth::Ldap::Config.new('ldapmain')
ldap_attributes = described_class.ldap_attributes(config)
- expect(ldap_attributes).to match_array(%w(dn uid cn mail memberof))
+ expect(ldap_attributes).to include('dn', 'uid', 'cn', 'mail')
+ expect(ldap_attributes).to be_present
+ expect(ldap_attributes.uniq!).to eq(nil)
end
end
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 6d903ce5fc9..432190b4318 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -599,6 +599,7 @@ design: &design
- versions
- notes
- user_mentions
+- events
designs: *design
actions:
- design
diff --git a/spec/models/project_services/prometheus_service_spec.rb b/spec/models/project_services/prometheus_service_spec.rb
index a85dbe3a7df..ec5bef92cde 100644
--- a/spec/models/project_services/prometheus_service_spec.rb
+++ b/spec/models/project_services/prometheus_service_spec.rb
@@ -252,6 +252,26 @@ describe PrometheusService, :use_clean_rails_memory_store_caching do
end
end
end
+
+ context 'behind IAP' do
+ let(:manual_configuration) { true }
+
+ before do
+ # dummy private key generated only for this test to pass openssl validation
+ service.google_iap_service_account_json = '{"type":"service_account","private_key":"-----BEGIN RSA PRIVATE KEY-----\nMIIBOAIBAAJAU85LgUY5o6j6j/07GMLCNUcWJOBA1buZnNgKELayA6mSsHrIv31J\nY8kS+9WzGPQninea7DcM4hHA7smMgQD1BwIDAQABAkAqKxMy6PL3tn7dFL43p0ex\nJyOtSmlVIiAZG1t1LXhE/uoLpYi5DnbYqGgu0oih+7nzLY/dXpNpXUmiRMOUEKmB\nAiEAoTi2rBXbrLSi2C+H7M/nTOjMQQDuZ8Wr4uWpKcjYJTMCIQCFEskL565oFl/7\nRRQVH+cARrAsAAoJSbrOBAvYZ0PI3QIgIEFwis10vgEF86rOzxppdIG/G+JL0IdD\n9IluZuXAGPECIGUo7qSaLr75o2VEEgwtAFH5aptIPFjrL5LFCKwtdB4RAiAYZgFV\nHCMmaooAw/eELuMoMWNYmujZ7VaAnOewGDW0uw==\n-----END RSA PRIVATE KEY-----\n"}'
+ service.google_iap_audience_client_id = "IAP_CLIENT_ID.apps.googleusercontent.com"
+
+ stub_request(:post, "https://oauth2.googleapis.com/token").to_return(status: 200, body: '{"id_token": "FOO"}', headers: { 'Content-Type': 'application/json; charset=UTF-8' })
+
+ stub_feature_flags(prometheus_service_iap_auth: true)
+ end
+
+ it 'includes the authorization header' do
+ expect(service.prometheus_client).not_to be_nil
+ expect(service.prometheus_client.send(:options)).to have_key(:headers)
+ expect(service.prometheus_client.send(:options)[:headers]).to eq(authorization: "Bearer FOO")
+ end
+ end
end
describe '#prometheus_available?' do
@@ -457,9 +477,33 @@ describe PrometheusService, :use_clean_rails_memory_store_caching do
}
]
end
+ let(:feature_flagged_fields) do
+ [
+ {
+ type: 'text',
+ name: 'google_iap_audience_client_id',
+ title: 'Google IAP Audience Client ID',
+ placeholder: s_('PrometheusService|Client ID of the IAP secured resource (looks like IAP_CLIENT_ID.apps.googleusercontent.com)'),
+ required: false
+ },
+ {
+ type: 'textarea',
+ name: 'google_iap_service_account_json',
+ title: 'Google IAP Service Account JSON',
+ placeholder: s_('PrometheusService|Contents of the credentials.json file of your service account, like: { "type": "service_account", "project_id": ... }'),
+ required: false
+ }
+ ]
+ end
it 'returns fields' do
+ stub_feature_flags(prometheus_service_iap_auth: false)
expect(service.fields).to eq(expected_fields)
end
+
+ it 'returns fields with feature flag on' do
+ stub_feature_flags(prometheus_service_iap_auth: true)
+ expect(service.fields).to eq(expected_fields + feature_flagged_fields)
+ end
end
end
diff --git a/spec/presenters/projects/prometheus/alert_presenter_spec.rb b/spec/presenters/projects/prometheus/alert_presenter_spec.rb
index 967a0fb2c09..8ee5a4d7b3f 100644
--- a/spec/presenters/projects/prometheus/alert_presenter_spec.rb
+++ b/spec/presenters/projects/prometheus/alert_presenter_spec.rb
@@ -24,18 +24,25 @@ describe Projects::Prometheus::AlertPresenter do
it { is_expected.to eq(project.full_path) }
end
- describe '#starts_at' do
- subject { presenter.starts_at }
+ describe '#start_time' do
+ subject { presenter.start_time }
+
+ let(:starts_at) { '2020-10-31T14:02:04Z' }
before do
payload['startsAt'] = starts_at
end
- context 'with valid datetime' do
- let(:datetime) { Time.now }
- let(:starts_at) { datetime.rfc3339 }
+ context 'with valid utc datetime' do
+ it { is_expected.to eq('31 October 2020, 2:02PM (UTC)') }
- it { is_expected.to eq(datetime.rfc3339) }
+ context 'with admin time zone not UTC' do
+ before do
+ allow(Time).to receive(:zone).and_return(ActiveSupport::TimeZone.new('Perth'))
+ end
+
+ it { is_expected.to eq('31 October 2020, 2:02PM (UTC)') }
+ end
end
context 'with invalid datetime' do
@@ -56,7 +63,7 @@ describe Projects::Prometheus::AlertPresenter do
<<~MARKDOWN.chomp
#### Summary
- **Start time:** #{presenter.starts_at}
+ **Start time:** #{presenter.start_time}
MARKDOWN
)
@@ -73,7 +80,7 @@ describe Projects::Prometheus::AlertPresenter do
<<~MARKDOWN.chomp
#### Summary
- **Start time:** #{presenter.starts_at}
+ **Start time:** #{presenter.start_time}
#### Alert Details
@@ -94,7 +101,7 @@ describe Projects::Prometheus::AlertPresenter do
<<~MARKDOWN.chomp
#### Summary
- **Start time:** #{presenter.starts_at}#{markdown_line_break}
+ **Start time:** #{presenter.start_time}#{markdown_line_break}
**full_query:** `query`
MARKDOWN
@@ -122,7 +129,7 @@ describe Projects::Prometheus::AlertPresenter do
<<~MARKDOWN.chomp
#### Summary
- **Start time:** #{presenter.starts_at}#{markdown_line_break}
+ **Start time:** #{presenter.start_time}#{markdown_line_break}
**Service:** service_name#{markdown_line_break}
**Monitoring tool:** monitoring_tool_name#{markdown_line_break}
**Hosts:** http://localhost:3000 http://localhost:3001
@@ -144,7 +151,7 @@ describe Projects::Prometheus::AlertPresenter do
<<~MARKDOWN.chomp
#### Summary
- **Start time:** #{presenter.starts_at}#{markdown_line_break}
+ **Start time:** #{presenter.start_time}#{markdown_line_break}
**Hosts:** http://localhost:3000
MARKDOWN
@@ -161,7 +168,7 @@ describe Projects::Prometheus::AlertPresenter do
<<~MARKDOWN.chomp
#### Summary
- **Start time:** #{presenter.starts_at}#{markdown_line_break}
+ **Start time:** #{presenter.start_time}#{markdown_line_break}
**full_query:** `avg(metric) > 1.0`
[](#{url})
@@ -253,7 +260,7 @@ describe Projects::Prometheus::AlertPresenter do
<<~MARKDOWN.chomp
#### Summary
- **Start time:** #{presenter.starts_at}#{markdown_line_break}
+ **Start time:** #{presenter.start_time}#{markdown_line_break}
**full_query:** `avg(metric) > 1.0`
MARKDOWN
@@ -280,7 +287,7 @@ describe Projects::Prometheus::AlertPresenter do
<<~MARKDOWN.chomp
#### Summary
- **Start time:** #{presenter.starts_at}
+ **Start time:** #{presenter.start_time}
MARKDOWN
end
diff --git a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb
new file mode 100644
index 00000000000..217f538c53e
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Mutations::Metrics::Dashboard::Annotations::Delete do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project, :private, :repository) }
+ let_it_be(:environment) { create(:environment, project: project) }
+ let_it_be(:annotation) { create(:metrics_dashboard_annotation, environment: environment) }
+ let(:mutation) do
+ variables = {
+ id: GitlabSchema.id_from_object(annotation).to_s
+ }
+
+ graphql_mutation(:delete_annotation, variables)
+ end
+
+ def mutation_response
+ graphql_mutation_response(:delete_annotation)
+ end
+
+ specify { expect(described_class).to require_graphql_authorizations(:delete_metrics_dashboard_annotation) }
+
+ context 'when the user has permission to delete the annotation' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ context 'with valid params' do
+ it 'deletes the annotation' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change { Metrics::Dashboard::Annotation.count }.by(-1)
+ end
+ end
+
+ context 'with invalid params' do
+ let(:mutation) do
+ variables = {
+ id: 'invalid_id'
+ }
+
+ graphql_mutation(:delete_annotation, variables)
+ end
+
+ it_behaves_like 'a mutation that returns top-level errors', errors: ['invalid_id is not a valid GitLab id.']
+ end
+
+ context 'when the delete fails' do
+ let(:service_response) { { message: 'Annotation has not been deleted', status: :error, last_step: :delete } }
+
+ before do
+ allow_next_instance_of(Metrics::Dashboard::Annotations::DeleteService) do |delete_service|
+ allow(delete_service).to receive(:execute).and_return(service_response)
+ end
+ end
+ it 'returns the error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['errors']).to eq([service_response[:message]])
+ end
+ end
+ end
+
+ context 'when the user does not have permission to delete the annotation' do
+ before do
+ project.add_reporter(current_user)
+ end
+
+ it_behaves_like 'a mutation that returns top-level errors', errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+
+ it 'does not delete the annotation' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { Metrics::Dashboard::Annotation.count }
+ end
+ end
+end
diff --git a/spec/services/design_management/delete_designs_service_spec.rb b/spec/services/design_management/delete_designs_service_spec.rb
index 2c0c1570cb4..bf5d6b443e6 100644
--- a/spec/services/design_management/delete_designs_service_spec.rb
+++ b/spec/services/design_management/delete_designs_service_spec.rb
@@ -56,6 +56,10 @@ describe DesignManagement::DeleteDesignsService do
let(:enabled) { false }
it_behaves_like "a service error"
+
+ it 'does not create any events in the activity stream' do
+ expect { run_service rescue nil }.not_to change { Event.count }
+ end
end
context "when the feature is available" do
@@ -72,7 +76,9 @@ describe DesignManagement::DeleteDesignsService do
it 'does not log any events' do
counter = ::Gitlab::UsageDataCounters::DesignsCounter
- expect { run_service rescue nil }.not_to change { counter.totals }
+
+ expect { run_service rescue nil }
+ .not_to change { [counter.totals, Event.count] }
end
end
@@ -92,6 +98,12 @@ describe DesignManagement::DeleteDesignsService do
expect { run_service }.to change { counter.read(:delete) }.by(1)
end
+ it 'creates an event in the activity stream' do
+ expect { run_service }
+ .to change { Event.count }.by(1)
+ .and change { Event.destroyed_action.for_design.count }.by(1)
+ end
+
it 'informs the new-version-worker' do
expect(::DesignManagement::NewVersionWorker).to receive(:perform_async).with(Integer)
@@ -129,14 +141,14 @@ describe DesignManagement::DeleteDesignsService do
let!(:designs) { create_designs(2) }
- it 'removes those designs' do
+ it 'makes the correct changes' do
+ counter = ::Gitlab::UsageDataCounters::DesignsCounter
+
expect { run_service }
.to change { issue.designs.current.count }.from(3).to(1)
- end
-
- it 'logs the correct number of deletion events' do
- counter = ::Gitlab::UsageDataCounters::DesignsCounter
- expect { run_service }.to change { counter.read(:delete) }.by(2)
+ .and change { counter.read(:delete) }.by(2)
+ .and change { Event.count }.by(2)
+ .and change { Event.destroyed_action.for_design.count }.by(2)
end
it_behaves_like "a success"
diff --git a/spec/services/design_management/save_designs_service_spec.rb b/spec/services/design_management/save_designs_service_spec.rb
index 013d5473860..3be3ac9daca 100644
--- a/spec/services/design_management/save_designs_service_spec.rb
+++ b/spec/services/design_management/save_designs_service_spec.rb
@@ -65,6 +65,10 @@ describe DesignManagement::SaveDesignsService do
end
it_behaves_like 'a service error'
+
+ it 'does not create an event in the activity stream' do
+ expect { run_service }.not_to change { Event.count }
+ end
end
context 'when the feature is available' do
@@ -89,6 +93,12 @@ describe DesignManagement::SaveDesignsService do
expect { run_service }.to change { counter.read(:create) }.by(1)
end
+ it 'creates an event in the activity stream' do
+ expect { run_service }
+ .to change { Event.count }.by(1)
+ .and change { Event.for_design.created_action.count }.by(1)
+ end
+
it 'creates a commit in the repository' do
run_service
@@ -166,9 +176,12 @@ describe DesignManagement::SaveDesignsService do
expect(updated_designs.first.versions.size).to eq(2)
end
- it 'increments the update counter' do
+ it 'records the correct events' do
counter = Gitlab::UsageDataCounters::DesignsCounter
- expect { run_service }.to change { counter.read(:update) }.by 1
+ expect { run_service }
+ .to change { counter.read(:update) }.by(1)
+ .and change { Event.count }.by(1)
+ .and change { Event.for_design.updated_action.count }.by(1)
end
context 'when uploading a new design' do
@@ -217,6 +230,14 @@ describe DesignManagement::SaveDesignsService do
.and change { counter.read(:update) }.by(1)
end
+ it 'creates the correct activity stream events' do
+ expect { run_service }
+ .to change { Event.count }.by(2)
+ .and change { Event.for_design.count }.by(2)
+ .and change { Event.created_action.count }.by(1)
+ .and change { Event.updated_action.count }.by(1)
+ end
+
it 'creates a single commit' do
commit_count = -> do
design_repository.expire_all_method_caches
diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb
index a43678626f7..73c089334ed 100644
--- a/spec/services/event_create_service_spec.rb
+++ b/spec/services/event_create_service_spec.rb
@@ -5,6 +5,9 @@ require 'spec_helper'
describe EventCreateService do
let(:service) { described_class.new }
+ let_it_be(:user, reload: true) { create :user }
+ let_it_be(:project) { create(:project) }
+
describe 'Issues' do
describe '#open_issue' do
let(:issue) { create(:issue) }
@@ -87,8 +90,6 @@ describe EventCreateService do
end
describe 'Milestone' do
- let(:user) { create :user }
-
describe '#open_milestone' do
let(:milestone) { create(:milestone) }
@@ -210,9 +211,6 @@ describe EventCreateService do
end
describe '#push', :clean_gitlab_redis_shared_state do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
-
let(:push_data) do
{
commits: [
@@ -234,9 +232,6 @@ describe EventCreateService do
end
describe '#bulk_push', :clean_gitlab_redis_shared_state do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
-
let(:push_data) do
{
action: :created,
@@ -251,9 +246,6 @@ describe EventCreateService do
end
describe 'Project' do
- let(:user) { create :user }
- let(:project) { create(:project) }
-
describe '#join_project' do
subject { service.join_project(project, user) }
@@ -268,4 +260,81 @@ describe EventCreateService do
it { expect { subject }.to change { Event.count }.from(0).to(1) }
end
end
+
+ describe 'design events' do
+ let_it_be(:design) { create(:design, project: project) }
+ let_it_be(:author) { user }
+
+ shared_examples 'feature flag gated multiple event creation' do
+ context 'the feature flag is off' do
+ before do
+ stub_feature_flags(design_activity_events: false)
+ end
+
+ specify { expect(result).to be_empty }
+ specify { expect { result }.not_to change { Event.count } }
+ specify { expect { result }.not_to exceed_query_limit(0) }
+ end
+
+ context 'the feature flag is enabled for a single project' do
+ before do
+ stub_feature_flags(design_activity_events: project)
+ end
+
+ specify { expect(result).not_to be_empty }
+ specify { expect { result }.to change { Event.count }.by(1) }
+ end
+ end
+
+ describe '#save_designs' do
+ let_it_be(:updated) { create_list(:design, 5) }
+ let_it_be(:created) { create_list(:design, 3) }
+
+ let(:result) { service.save_designs(author, create: created, update: updated) }
+
+ specify { expect { result }.to change { Event.count }.by(8) }
+
+ specify { expect { result }.not_to exceed_query_limit(1) }
+
+ it 'creates 3 created design events' do
+ ids = result.pluck('id')
+ events = Event.created_action.where(id: ids)
+
+ expect(events.map(&:design)).to match_array(created)
+ end
+
+ it 'creates 5 created design events' do
+ ids = result.pluck('id')
+ events = Event.updated_action.where(id: ids)
+
+ expect(events.map(&:design)).to match_array(updated)
+ end
+
+ it_behaves_like 'feature flag gated multiple event creation' do
+ let(:project) { created.first.project }
+ end
+ end
+
+ describe '#destroy_designs' do
+ let_it_be(:designs) { create_list(:design, 5) }
+ let_it_be(:author) { create(:user) }
+
+ let(:result) { service.destroy_designs(designs, author) }
+
+ specify { expect { result }.to change { Event.count }.by(5) }
+
+ specify { expect { result }.not_to exceed_query_limit(1) }
+
+ it 'creates 5 destroyed design events' do
+ ids = result.pluck('id')
+ events = Event.destroyed_action.where(id: ids)
+
+ expect(events.map(&:design)).to match_array(designs)
+ end
+
+ it_behaves_like 'feature flag gated multiple event creation' do
+ let(:project) { designs.first.project }
+ end
+ end
+ end
end