Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-02-17 15:09:20 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-17 15:09:20 +0300
commitb84eeb256c4a780d902faee1f99ca9a711b3214a (patch)
tree32918aadbea9210eace50efbce9afbfb8cd3ba84 /spec
parent53ae6b7e3f83591ad251a3f771f5bf3b8cf087ba (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/container_expiration_policies.rb13
-rw-r--r--spec/factories/projects.rb6
-rw-r--r--spec/features/merge_request/user_sees_merge_widget_spec.rb131
-rw-r--r--spec/features/projects/settings/registry_settings_spec.rb12
-rw-r--r--spec/fixtures/api/schemas/entities/test_reports_comparer.json2
-rw-r--r--spec/fixtures/api/schemas/entities/test_suite_comparer.json12
-rw-r--r--spec/frontend/issuables_list/components/issuable_spec.js4
-rw-r--r--spec/frontend/issuables_list/issuable_list_test_data.js3
-rw-r--r--spec/frontend/reports/store/utils_spec.js60
-rw-r--r--spec/javascripts/reports/components/grouped_test_reports_app_spec.js48
-rw-r--r--spec/javascripts/reports/mock_data/new_and_fixed_failures_report.json56
-rw-r--r--spec/javascripts/reports/mock_data/new_errors_report.json38
-rw-r--r--spec/javascripts/reports/mock_data/new_failures_report.json39
-rw-r--r--spec/javascripts/reports/mock_data/no_failures_report.json29
-rw-r--r--spec/javascripts/reports/mock_data/resolved_failures.json31
-rw-r--r--spec/lib/gitlab/ci/parsers/test/junit_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb52
-rw-r--r--spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb140
-rw-r--r--spec/lib/gitlab/ci/reports/test_suite_spec.rb9
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml2
-rw-r--r--spec/lib/gitlab/runtime_spec.rb4
-rw-r--r--spec/mailers/emails/pipelines_spec.rb42
-rw-r--r--spec/models/project_spec.rb10
-rw-r--r--spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb244
-rw-r--r--spec/requests/api/graphql/mutations/notes/update/note_spec.rb (renamed from spec/requests/api/graphql/mutations/notes/update_spec.rb)15
-rw-r--r--spec/serializers/test_reports_comparer_entity_spec.rb6
-rw-r--r--spec/serializers/test_suite_comparer_entity_spec.rb78
-rw-r--r--spec/services/snippets/create_service_spec.rb30
-rw-r--r--spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb20
29 files changed, 1067 insertions, 71 deletions
diff --git a/spec/factories/container_expiration_policies.rb b/spec/factories/container_expiration_policies.rb
index 951127a4aa7..41c3a7f8cb9 100644
--- a/spec/factories/container_expiration_policies.rb
+++ b/spec/factories/container_expiration_policies.rb
@@ -2,7 +2,18 @@
FactoryBot.define do
factory :container_expiration_policy, class: 'ContainerExpirationPolicy' do
- association :project, factory: [:project, :without_container_expiration_policy]
+ # Note: because of the project_id primary_key on
+ # container_expiration_policies, and the create_container_expiration_policy
+ # callback on Project, we need to build the project first before assigning
+ # it to a container_expiration_policy.
+ #
+ # Also, if you wish to assign an existing project to a
+ # container_expiration_policy, you will then have to destroy the project's
+ # container_expiration_policy first.
+ before(:create) do |container_expiration_policy|
+ container_expiration_policy.project = build(:project) unless container_expiration_policy.project
+ end
+
cadence { '1d' }
enabled { true }
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 9be0b308680..ba38e1bb312 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -140,12 +140,6 @@ FactoryBot.define do
end
end
- trait :without_container_expiration_policy do
- after(:build) do |project|
- project.class.skip_callback(:create, :after, :create_container_expiration_policy, raise: false)
- end
- end
-
# Build a custom repository by specifying a hash of `filename => content` in
# the transient `files` attribute. Each file will be created in its own
# commit, operating against the master branch. So, the following call:
diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb
index d12843d7150..94f57cdda74 100644
--- a/spec/features/merge_request/user_sees_merge_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb
@@ -699,6 +699,137 @@ describe 'Merge request > User sees merge widget', :js do
end
end
+ context 'when a new error exists' do
+ let(:base_reports) do
+ Gitlab::Ci::Reports::TestReports.new.tap do |reports|
+ reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
+ reports.get_suite('junit').add_test_case(create_test_case_java_success)
+ end
+ end
+
+ let(:head_reports) do
+ Gitlab::Ci::Reports::TestReports.new.tap do |reports|
+ reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
+ reports.get_suite('junit').add_test_case(create_test_case_java_error)
+ end
+ end
+
+ it 'shows test reports summary which includes the new error' do
+ within(".js-reports-container") do
+ click_button 'Expand'
+
+ expect(page).to have_content('Test summary contained 1 failed/error test result out of 2 total tests')
+ within(".js-report-section-container") do
+ expect(page).to have_content('rspec found no changed test results out of 1 total test')
+ expect(page).to have_content('junit found 1 failed/error test result out of 1 total test')
+ expect(page).to have_content('New')
+ expect(page).to have_content('addTest')
+ end
+ end
+ end
+
+ context 'when user clicks the new error' do
+ it 'shows the test report detail' do
+ within(".js-reports-container") do
+ click_button 'Expand'
+
+ within(".js-report-section-container") do
+ click_button 'addTest'
+
+ expect(page).to have_content('8.88')
+ end
+ end
+ end
+ end
+ end
+
+ context 'when an existing error exists' do
+ let(:base_reports) do
+ Gitlab::Ci::Reports::TestReports.new.tap do |reports|
+ reports.get_suite('rspec').add_test_case(create_test_case_rspec_error)
+ reports.get_suite('junit').add_test_case(create_test_case_java_success)
+ end
+ end
+
+ let(:head_reports) do
+ Gitlab::Ci::Reports::TestReports.new.tap do |reports|
+ reports.get_suite('rspec').add_test_case(create_test_case_rspec_error)
+ reports.get_suite('junit').add_test_case(create_test_case_java_success)
+ end
+ end
+
+ it 'shows test reports summary which includes the existing error' do
+ within(".js-reports-container") do
+ click_button 'Expand'
+
+ expect(page).to have_content('Test summary contained 1 failed/error test result out of 2 total tests')
+ within(".js-report-section-container") do
+ expect(page).to have_content('rspec found 1 failed/error test result out of 1 total test')
+ expect(page).to have_content('junit found no changed test results out of 1 total test')
+ expect(page).not_to have_content('New')
+ expect(page).to have_content('Test#sum when a is 4 and b is 4 returns summary')
+ end
+ end
+ end
+
+ context 'when user clicks the existing error' do
+ it 'shows test report detail of it' do
+ within(".js-reports-container") do
+ click_button 'Expand'
+
+ within(".js-report-section-container") do
+ click_button 'Test#sum when a is 4 and b is 4 returns summary'
+
+ expect(page).to have_content('4.44')
+ end
+ end
+ end
+ end
+ end
+
+ context 'when a resolved error exists' do
+ let(:base_reports) do
+ Gitlab::Ci::Reports::TestReports.new.tap do |reports|
+ reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
+ reports.get_suite('junit').add_test_case(create_test_case_java_error)
+ end
+ end
+
+ let(:head_reports) do
+ Gitlab::Ci::Reports::TestReports.new.tap do |reports|
+ reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
+ reports.get_suite('junit').add_test_case(create_test_case_java_success)
+ end
+ end
+
+ it 'shows test reports summary which includes the resolved error' do
+ within(".js-reports-container") do
+ click_button 'Expand'
+
+ expect(page).to have_content('Test summary contained 1 fixed test result out of 2 total tests')
+ within(".js-report-section-container") do
+ expect(page).to have_content('rspec found no changed test results out of 1 total test')
+ expect(page).to have_content('junit found 1 fixed test result out of 1 total test')
+ expect(page).to have_content('addTest')
+ end
+ end
+ end
+
+ context 'when user clicks the resolved error' do
+ it 'shows test report detail of it' do
+ within(".js-reports-container") do
+ click_button 'Expand'
+
+ within(".js-report-section-container") do
+ click_button 'addTest'
+
+ expect(page).to have_content('5.55')
+ end
+ end
+ end
+ end
+ end
+
context 'properly truncates the report' do
let(:base_reports) do
Gitlab::Ci::Reports::TestReports.new.tap do |reports|
diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb
index 4c5bc290402..fc1a85c3efe 100644
--- a/spec/features/projects/settings/registry_settings_spec.rb
+++ b/spec/features/projects/settings/registry_settings_spec.rb
@@ -10,7 +10,6 @@ describe 'Project > Settings > CI/CD > Container registry tag expiration policy'
before do
sign_in(user)
stub_container_registry_config(enabled: true)
- stub_feature_flags(registry_retention_policies_settings: true)
end
context 'as owner' do
@@ -63,15 +62,4 @@ describe 'Project > Settings > CI/CD > Container registry tag expiration policy'
expect(page).not_to have_selector('#js-registry-policies')
end
end
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(registry_retention_policies_settings: false)
- visit project_settings_ci_cd_path(project)
- end
-
- it 'does not exists' do
- expect(page).not_to have_selector('#js-registry-policies')
- end
- end
end
diff --git a/spec/fixtures/api/schemas/entities/test_reports_comparer.json b/spec/fixtures/api/schemas/entities/test_reports_comparer.json
index d7880801c01..03812527f71 100644
--- a/spec/fixtures/api/schemas/entities/test_reports_comparer.json
+++ b/spec/fixtures/api/schemas/entities/test_reports_comparer.json
@@ -12,11 +12,13 @@
"properties": {
"total": { "type": "integer" },
"resolved": { "type": "integer" },
+ "errored": { "type": "integer" },
"failed": { "type": "integer" }
},
"required": [
"total",
"resolved",
+ "errored",
"failed"
]
},
diff --git a/spec/fixtures/api/schemas/entities/test_suite_comparer.json b/spec/fixtures/api/schemas/entities/test_suite_comparer.json
index d63fea1f0db..ecb331ae013 100644
--- a/spec/fixtures/api/schemas/entities/test_suite_comparer.json
+++ b/spec/fixtures/api/schemas/entities/test_suite_comparer.json
@@ -16,17 +16,17 @@
"properties": {
"total": { "type": "integer" },
"resolved": { "type": "integer" },
+ "errored": { "type": "integer" },
"failed": { "type": "integer" }
},
- "required": [
- "total",
- "resolved",
- "failed"
- ]
+ "required": ["total", "resolved", "errored", "failed"]
},
"new_failures": { "type": "array", "items": { "$ref": "test_case.json" } },
"resolved_failures": { "type": "array", "items": { "$ref": "test_case.json" } },
- "existing_failures": { "type": "array", "items": { "$ref": "test_case.json" } }
+ "existing_failures": { "type": "array", "items": { "$ref": "test_case.json" } },
+ "new_errors": { "type": "array", "items": { "$ref": "test_case.json" } },
+ "resolved_errors": { "type": "array", "items": { "$ref": "test_case.json" } },
+ "existing_errors": { "type": "array", "items": { "$ref": "test_case.json" } }
},
"additionalProperties": false
}
diff --git a/spec/frontend/issuables_list/components/issuable_spec.js b/spec/frontend/issuables_list/components/issuable_spec.js
index 81f6b60ae25..980def06078 100644
--- a/spec/frontend/issuables_list/components/issuable_spec.js
+++ b/spec/frontend/issuables_list/components/issuable_spec.js
@@ -122,6 +122,10 @@ describe('Issuable component', () => {
expect(finder().exists()).toBe(false);
});
+ it('show relative reference path', () => {
+ expect(wrapper.find('.js-ref-path').text()).toBe(issuable.references.relative);
+ });
+
it('does not have closed text', () => {
expect(wrapper.text()).not.toContain(TEXT_CLOSED);
});
diff --git a/spec/frontend/issuables_list/issuable_list_test_data.js b/spec/frontend/issuables_list/issuable_list_test_data.js
index 617780fd736..19d8ee7f71a 100644
--- a/spec/frontend/issuables_list/issuable_list_test_data.js
+++ b/spec/frontend/issuables_list/issuable_list_test_data.js
@@ -26,6 +26,9 @@ export const simpleIssue = {
web_url: 'http://localhost:3001/h5bp/html5-boilerplate/issues/31',
has_tasks: false,
weight: null,
+ references: {
+ relative: 'html-boilerplate#45',
+ },
};
export const testLabels = [
diff --git a/spec/frontend/reports/store/utils_spec.js b/spec/frontend/reports/store/utils_spec.js
index f0141b9e162..0d9a8dd4585 100644
--- a/spec/frontend/reports/store/utils_spec.js
+++ b/spec/frontend/reports/store/utils_spec.js
@@ -35,6 +35,16 @@ describe('Reports store utils', () => {
);
});
+ it('should render text for multiple errored results', () => {
+ const name = 'Test summary';
+ const data = { errored: 7, total: 10 };
+ const result = utils.summaryTextBuilder(name, data);
+
+ expect(result).toBe(
+ 'Test summary contained 7 failed/error test results out of 10 total tests',
+ );
+ });
+
it('should render text for multiple fixed results', () => {
const name = 'Test summary';
const data = { resolved: 4, total: 10 };
@@ -62,6 +72,27 @@ describe('Reports store utils', () => {
'Test summary contained 1 failed/error test result and 1 fixed test result out of 10 total tests',
);
});
+
+ it('should render text for singular failed, errored, and fixed results', () => {
+ // these will be singular when the copy is updated
+ const name = 'Test summary';
+ const data = { failed: 1, errored: 1, resolved: 1, total: 10 };
+ const result = utils.summaryTextBuilder(name, data);
+
+ expect(result).toBe(
+ 'Test summary contained 2 failed/error test results and 1 fixed test result out of 10 total tests',
+ );
+ });
+
+ it('should render text for multiple failed, errored, and fixed results', () => {
+ const name = 'Test summary';
+ const data = { failed: 2, errored: 3, resolved: 4, total: 10 };
+ const result = utils.summaryTextBuilder(name, data);
+
+ expect(result).toBe(
+ 'Test summary contained 5 failed/error test results and 4 fixed test results out of 10 total tests',
+ );
+ });
});
describe('reportTextBuilder', () => {
@@ -89,6 +120,14 @@ describe('Reports store utils', () => {
expect(result).toBe('Rspec found 3 failed/error test results out of 10 total tests');
});
+ it('should render text for multiple errored results', () => {
+ const name = 'Rspec';
+ const data = { errored: 7, total: 10 };
+ const result = utils.reportTextBuilder(name, data);
+
+ expect(result).toBe('Rspec found 7 failed/error test results out of 10 total tests');
+ });
+
it('should render text for multiple fixed results', () => {
const name = 'Rspec';
const data = { resolved: 4, total: 10 };
@@ -116,6 +155,27 @@ describe('Reports store utils', () => {
'Rspec found 1 failed/error test result and 1 fixed test result out of 10 total tests',
);
});
+
+ it('should render text for singular failed, errored, and fixed results', () => {
+ // these will be singular when the copy is updated
+ const name = 'Rspec';
+ const data = { failed: 1, errored: 1, resolved: 1, total: 10 };
+ const result = utils.reportTextBuilder(name, data);
+
+ expect(result).toBe(
+ 'Rspec found 2 failed/error test results and 1 fixed test result out of 10 total tests',
+ );
+ });
+
+ it('should render text for multiple failed, errored, and fixed results', () => {
+ const name = 'Rspec';
+ const data = { failed: 2, errored: 3, resolved: 4, total: 10 };
+ const result = utils.reportTextBuilder(name, data);
+
+ expect(result).toBe(
+ 'Rspec found 5 failed/error test results and 4 fixed test results out of 10 total tests',
+ );
+ });
});
describe('statusIcon', () => {
diff --git a/spec/javascripts/reports/components/grouped_test_reports_app_spec.js b/spec/javascripts/reports/components/grouped_test_reports_app_spec.js
index 1b006cdbd4e..154aa881d2d 100644
--- a/spec/javascripts/reports/components/grouped_test_reports_app_spec.js
+++ b/spec/javascripts/reports/components/grouped_test_reports_app_spec.js
@@ -5,6 +5,7 @@ import state from '~/reports/store/state';
import component from '~/reports/components/grouped_test_reports_app.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
import newFailedTestReports from '../mock_data/new_failures_report.json';
+import newErrorsTestReports from '../mock_data/new_errors_report.json';
import successTestReports from '../mock_data/no_failures_report.json';
import mixedResultsTestReports from '../mock_data/new_and_fixed_failures_report.json';
import resolvedFailures from '../mock_data/resolved_failures.json';
@@ -99,6 +100,34 @@ describe('Grouped Test Reports App', () => {
});
});
+ describe('with new error result', () => {
+ beforeEach(() => {
+ mock.onGet('test_results.json').reply(200, newErrorsTestReports, {});
+ vm = mountComponent(Component, {
+ endpoint: 'test_results.json',
+ });
+ });
+
+ it('renders error summary text + new badge', done => {
+ setTimeout(() => {
+ expect(vm.$el.querySelector('.gl-spinner')).toBeNull();
+ expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
+ 'Test summary contained 2 failed/error test results out of 11 total tests',
+ );
+
+ expect(vm.$el.textContent).toContain(
+ 'karma found 2 failed/error test results out of 3 total tests',
+ );
+
+ expect(vm.$el.textContent).toContain('New');
+ expect(vm.$el.textContent).toContain(
+ 'rspec:pg found no changed test results out of 8 total tests',
+ );
+ done();
+ }, 0);
+ });
+ });
+
describe('with mixed results', () => {
beforeEach(() => {
mock.onGet('test_results.json').reply(200, mixedResultsTestReports, {});
@@ -127,7 +156,7 @@ describe('Grouped Test Reports App', () => {
});
});
- describe('with resolved failures', () => {
+ describe('with resolved failures and resolved errors', () => {
beforeEach(() => {
mock.onGet('test_results.json').reply(200, resolvedFailures, {});
vm = mountComponent(Component, {
@@ -139,11 +168,11 @@ describe('Grouped Test Reports App', () => {
setTimeout(() => {
expect(vm.$el.querySelector('.gl-spinner')).toBeNull();
expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
- 'Test summary contained 2 fixed test results out of 11 total tests',
+ 'Test summary contained 4 fixed test results out of 11 total tests',
);
expect(vm.$el.textContent).toContain(
- 'rspec:pg found 2 fixed test results out of 8 total tests',
+ 'rspec:pg found 4 fixed test results out of 8 total tests',
);
done();
}, 0);
@@ -161,6 +190,19 @@ describe('Grouped Test Reports App', () => {
done();
}, 0);
});
+
+ it('renders resolved errors', done => {
+ setTimeout(() => {
+ expect(vm.$el.querySelector('.report-block-container').textContent).toContain(
+ resolvedFailures.suites[0].resolved_errors[0].name,
+ );
+
+ expect(vm.$el.querySelector('.report-block-container').textContent).toContain(
+ resolvedFailures.suites[0].resolved_errors[1].name,
+ );
+ done();
+ }, 0);
+ });
});
describe('with error', () => {
diff --git a/spec/javascripts/reports/mock_data/new_and_fixed_failures_report.json b/spec/javascripts/reports/mock_data/new_and_fixed_failures_report.json
index ceaf894375a..6141e5433a6 100644
--- a/spec/javascripts/reports/mock_data/new_and_fixed_failures_report.json
+++ b/spec/javascripts/reports/mock_data/new_and_fixed_failures_report.json
@@ -1 +1,55 @@
-{"status":"failed","summary":{"total":11,"resolved":2,"failed":2},"suites":[{"name":"rspec:pg","status":"failed","summary":{"total":8,"resolved":2,"failed":1},"new_failures":[{"status":"failed","name":"Test#subtract when a is 2 and b is 1 returns correct result","execution_time":0.00908,"system_output":"Failure/Error: is_expected.to eq(1)\n\n expected: 1\n got: 3\n\n (compared using ==)\n./spec/test_spec.rb:43:in `block (4 levels) in <top (required)>'"}],"resolved_failures":[{"status":"success","name":"Test#sum when a is 1 and b is 2 returns summary","execution_time":0.000318,"system_output":null},{"status":"success","name":"Test#sum when a is 100 and b is 200 returns summary","execution_time":0.000074,"system_output":null}],"existing_failures":[]},{"name":"java ant","status":"failed","summary":{"total":3,"resolved":0,"failed":1},"new_failures":[],"resolved_failures":[],"existing_failures":[{"status":"failed","name":"sumTest","execution_time":0.004,"system_output":"junit.framework.AssertionFailedError: expected:<3> but was:<-1>\n\tat CalculatorTest.sumTest(Unknown Source)\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n"}]}]} \ No newline at end of file
+{
+ "status": "failed",
+ "summary": { "total": 11, "resolved": 2, "errored": 0, "failed": 2 },
+ "suites": [
+ {
+ "name": "rspec:pg",
+ "status": "failed",
+ "summary": { "total": 8, "resolved": 2, "errored": 0, "failed": 1 },
+ "new_failures": [
+ {
+ "status": "failed",
+ "name": "Test#subtract when a is 2 and b is 1 returns correct result",
+ "execution_time": 0.00908,
+ "system_output": "Failure/Error: is_expected.to eq(1)\n\n expected: 1\n got: 3\n\n (compared using ==)\n./spec/test_spec.rb:43:in `block (4 levels) in <top (required)>'"
+ }
+ ],
+ "resolved_failures": [
+ {
+ "status": "success",
+ "name": "Test#sum when a is 1 and b is 2 returns summary",
+ "execution_time": 0.000318,
+ "system_output": null
+ },
+ {
+ "status": "success",
+ "name": "Test#sum when a is 100 and b is 200 returns summary",
+ "execution_time": 0.000074,
+ "system_output": null
+ }
+ ],
+ "existing_failures": [],
+ "new_errors": [],
+ "resolved_errors": [],
+ "existing_errors": []
+ },
+ {
+ "name": "java ant",
+ "status": "failed",
+ "summary": { "total": 3, "resolved": 0, "errored": 0, "failed": 1 },
+ "new_failures": [],
+ "resolved_failures": [],
+ "existing_failures": [
+ {
+ "status": "failed",
+ "name": "sumTest",
+ "execution_time": 0.004,
+ "system_output": "junit.framework.AssertionFailedError: expected:<3> but was:<-1>\n\tat CalculatorTest.sumTest(Unknown Source)\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n"
+ }
+ ],
+ "new_errors": [],
+ "resolved_errors": [],
+ "existing_errors": []
+ }
+ ]
+}
diff --git a/spec/javascripts/reports/mock_data/new_errors_report.json b/spec/javascripts/reports/mock_data/new_errors_report.json
new file mode 100644
index 00000000000..cebf98fdb63
--- /dev/null
+++ b/spec/javascripts/reports/mock_data/new_errors_report.json
@@ -0,0 +1,38 @@
+{
+ "summary": { "total": 11, "resolved": 0, "errored": 2, "failed": 0 },
+ "suites": [
+ {
+ "name": "rspec:pg",
+ "summary": { "total": 8, "resolved": 0, "errored": 0, "failed": 0 },
+ "new_failures": [],
+ "resolved_failures": [],
+ "existing_failures": [],
+ "new_errors": [],
+ "resolved_errors": [],
+ "existing_errors": []
+ },
+ {
+ "name": "karma",
+ "summary": { "total": 3, "resolved": 0, "errored": 2, "failed": 0 },
+ "new_failures": [],
+ "resolved_failures": [],
+ "existing_failures": [],
+ "new_errors": [
+ {
+ "result": "error",
+ "name": "Test#sum when a is 1 and b is 2 returns summary",
+ "execution_time": 0.009411,
+ "system_output": "Failed: Error in render: 'TypeError: Cannot read property 'status' of undefined'"
+ },
+ {
+ "result": "error",
+ "name": "Test#sum when a is 100 and b is 200 returns summary",
+ "execution_time": 0.000162,
+ "system_output": "Failed: Error in render: 'TypeError: Cannot read property 'length' of undefined'"
+ }
+ ],
+ "resolved_errors": [],
+ "existing_errors": []
+ }
+ ]
+}
diff --git a/spec/javascripts/reports/mock_data/new_failures_report.json b/spec/javascripts/reports/mock_data/new_failures_report.json
index 930efe16f65..8b9c12c6271 100644
--- a/spec/javascripts/reports/mock_data/new_failures_report.json
+++ b/spec/javascripts/reports/mock_data/new_failures_report.json
@@ -1 +1,38 @@
-{"summary":{"total":11,"resolved":0,"failed":2},"suites":[{"name":"rspec:pg","summary":{"total":8,"resolved":0,"failed":2},"new_failures":[{"result":"failure","name":"Test#sum when a is 1 and b is 2 returns summary","execution_time":0.009411,"system_output":"Failure/Error: is_expected.to eq(3)\n\n expected: 3\n got: -1\n\n (compared using ==)\n./spec/test_spec.rb:12:in `block (4 levels) in <top (required)>'"},{"result":"failure","name":"Test#sum when a is 100 and b is 200 returns summary","execution_time":0.000162,"system_output":"Failure/Error: is_expected.to eq(300)\n\n expected: 300\n got: -100\n\n (compared using ==)\n./spec/test_spec.rb:21:in `block (4 levels) in <top (required)>'"}],"resolved_failures":[],"existing_failures":[]},{"name":"java ant","summary":{"total":3,"resolved":0,"failed":0},"new_failures":[],"resolved_failures":[],"existing_failures":[]}]} \ No newline at end of file
+{
+ "summary": { "total": 11, "resolved": 0, "errored": 0, "failed": 2 },
+ "suites": [
+ {
+ "name": "rspec:pg",
+ "summary": { "total": 8, "resolved": 0, "errored": 0, "failed": 2 },
+ "new_failures": [
+ {
+ "result": "failure",
+ "name": "Test#sum when a is 1 and b is 2 returns summary",
+ "execution_time": 0.009411,
+ "system_output": "Failure/Error: is_expected.to eq(3)\n\n expected: 3\n got: -1\n\n (compared using ==)\n./spec/test_spec.rb:12:in `block (4 levels) in <top (required)>'"
+ },
+ {
+ "result": "failure",
+ "name": "Test#sum when a is 100 and b is 200 returns summary",
+ "execution_time": 0.000162,
+ "system_output": "Failure/Error: is_expected.to eq(300)\n\n expected: 300\n got: -100\n\n (compared using ==)\n./spec/test_spec.rb:21:in `block (4 levels) in <top (required)>'"
+ }
+ ],
+ "resolved_failures": [],
+ "existing_failures": [],
+ "new_errors": [],
+ "resolved_errors": [],
+ "existing_errors": []
+ },
+ {
+ "name": "java ant",
+ "summary": { "total": 3, "resolved": 0, "errored": 0, "failed": 0 },
+ "new_failures": [],
+ "resolved_failures": [],
+ "existing_failures": [],
+ "new_errors": [],
+ "resolved_errors": [],
+ "existing_errors": []
+ }
+ ]
+}
diff --git a/spec/javascripts/reports/mock_data/no_failures_report.json b/spec/javascripts/reports/mock_data/no_failures_report.json
index 6c0675ff7dc..7da9e0c6211 100644
--- a/spec/javascripts/reports/mock_data/no_failures_report.json
+++ b/spec/javascripts/reports/mock_data/no_failures_report.json
@@ -1 +1,28 @@
-{"status":"success","summary":{"total":11,"resolved":0,"failed":0},"suites":[{"name":"rspec:pg","status":"success","summary":{"total":8,"resolved":0,"failed":0},"new_failures":[],"resolved_failures":[],"existing_failures":[]},{"name":"java ant","status":"success","summary":{"total":3,"resolved":0,"failed":0},"new_failures":[],"resolved_failures":[],"existing_failures":[]}]} \ No newline at end of file
+{
+ "status": "success",
+ "summary": { "total": 11, "resolved": 0, "errored": 0, "failed": 0 },
+ "suites": [
+ {
+ "name": "rspec:pg",
+ "status": "success",
+ "summary": { "total": 8, "resolved": 0, "errored": 0, "failed": 0 },
+ "new_failures": [],
+ "resolved_failures": [],
+ "existing_failures": [],
+ "new_errors": [],
+ "resolved_errors": [],
+ "existing_errors": []
+ },
+ {
+ "name": "java ant",
+ "status": "success",
+ "summary": { "total": 3, "resolved": 0, "errored": 0, "failed": 0 },
+ "new_failures": [],
+ "resolved_failures": [],
+ "existing_failures": [],
+ "new_errors": [],
+ "resolved_errors": [],
+ "existing_errors": []
+ }
+ ]
+}
diff --git a/spec/javascripts/reports/mock_data/resolved_failures.json b/spec/javascripts/reports/mock_data/resolved_failures.json
index d1f347ce5e6..49de6aa840b 100644
--- a/spec/javascripts/reports/mock_data/resolved_failures.json
+++ b/spec/javascripts/reports/mock_data/resolved_failures.json
@@ -1,11 +1,11 @@
{
"status": "success",
- "summary": { "total": 11, "resolved": 2, "failed": 0 },
+ "summary": { "total": 11, "resolved": 4, "errored": 0, "failed": 0 },
"suites": [
{
"name": "rspec:pg",
"status": "success",
- "summary": { "total": 8, "resolved": 2, "failed": 0 },
+ "summary": { "total": 8, "resolved": 4, "errored": 0, "failed": 0 },
"new_failures": [],
"resolved_failures": [
{
@@ -23,15 +23,36 @@
"stack_trace": null
}
],
- "existing_failures": []
+ "existing_failures": [],
+ "new_errors": [],
+ "resolved_errors": [
+ {
+ "status": "success",
+ "name": "Test#sum when a is 4 and b is 4 returns summary",
+ "execution_time": 0.00342,
+ "system_output": null,
+ "stack_trace": null
+ },
+ {
+ "status": "success",
+ "name": "Test#sum when a is 40 and b is 400 returns summary",
+ "execution_time": 0.0000231,
+ "system_output": null,
+ "stack_trace": null
+ }
+ ],
+ "existing_errors": []
},
{
"name": "java ant",
"status": "success",
- "summary": { "total": 3, "resolved": 0, "failed": 0 },
+ "summary": { "total": 3, "resolved": 0, "errored": 0, "failed": 0 },
"new_failures": [],
"resolved_failures": [],
- "existing_failures": []
+ "existing_failures": [],
+ "new_errors": [],
+ "resolved_errors": [],
+ "existing_errors": []
}
]
}
diff --git a/spec/lib/gitlab/ci/parsers/test/junit_spec.rb b/spec/lib/gitlab/ci/parsers/test/junit_spec.rb
index 6a7fe7a5927..b91cf1dd3ed 100644
--- a/spec/lib/gitlab/ci/parsers/test/junit_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/test/junit_spec.rb
@@ -99,7 +99,7 @@ describe Gitlab::Ci::Parsers::Test::Junit do
let(:testcase_content) { '<error>Some error</error>' }
it_behaves_like '<testcase> XML parser',
- ::Gitlab::Ci::Reports::TestCase::STATUS_FAILED,
+ ::Gitlab::Ci::Reports::TestCase::STATUS_ERROR,
'Some error'
end
diff --git a/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb b/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb
index 48eef0643b2..d731afe1fff 100644
--- a/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb
@@ -57,6 +57,17 @@ describe Gitlab::Ci::Reports::TestReportsComparer do
is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
end
end
+
+ context 'when there is an error test case in head suites' do
+ before do
+ head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
+ head_reports.get_suite('junit').add_test_case(create_test_case_java_error)
+ end
+
+ it 'returns the total status in head suite' do
+ is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
+ end
+ end
end
describe '#total_count' do
@@ -75,7 +86,7 @@ describe Gitlab::Ci::Reports::TestReportsComparer do
describe '#resolved_count' do
subject { comparer.resolved_count }
- context 'when there is a resolved test case in head suites' do
+ context 'when there is a resolved failure test case in head suites' do
before do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
base_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
@@ -88,6 +99,19 @@ describe Gitlab::Ci::Reports::TestReportsComparer do
end
end
+ context 'when there is a resolved error test case in head suites' do
+ before do
+ base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
+ base_reports.get_suite('junit').add_test_case(create_test_case_java_error)
+ head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
+ head_reports.get_suite('junit').add_test_case(create_test_case_java_success)
+ end
+
+ it 'returns the correct count' do
+ is_expected.to eq(1)
+ end
+ end
+
context 'when there are no resolved test cases in head suites' do
before do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
@@ -127,4 +151,30 @@ describe Gitlab::Ci::Reports::TestReportsComparer do
end
end
end
+
+ describe '#error_count' do
+ subject { comparer.error_count }
+
+ context 'when there is an error test case in head suites' do
+ before do
+ head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
+ head_reports.get_suite('junit').add_test_case(create_test_case_java_error)
+ end
+
+ it 'returns the correct count' do
+ is_expected.to eq(1)
+ end
+ end
+
+ context 'when there are no error test cases in head suites' do
+ before do
+ head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
+ head_reports.get_suite('junit').add_test_case(create_test_case_rspec_success)
+ end
+
+ it 'returns the correct count' do
+ is_expected.to eq(0)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb b/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb
index cf4690bb334..2d2179a690b 100644
--- a/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb
@@ -9,8 +9,9 @@ describe Gitlab::Ci::Reports::TestSuiteComparer do
let(:name) { 'rpsec' }
let(:base_suite) { Gitlab::Ci::Reports::TestSuite.new(name) }
let(:head_suite) { Gitlab::Ci::Reports::TestSuite.new(name) }
- let(:test_case_success) { create_test_case_rspec_success }
- let(:test_case_failed) { create_test_case_rspec_failed }
+ let(:test_case_success) { create_test_case_java_success }
+ let(:test_case_failed) { create_test_case_java_failed }
+ let(:test_case_error) { create_test_case_java_error }
describe '#new_failures' do
subject { comparer.new_failures }
@@ -135,6 +136,129 @@ describe Gitlab::Ci::Reports::TestSuiteComparer do
end
end
+ describe '#new_errors' do
+ subject { comparer.new_errors }
+
+ context 'when head suite has a new error test case which does not exist in base' do
+ before do
+ base_suite.add_test_case(test_case_success)
+ head_suite.add_test_case(test_case_error)
+ end
+
+ it 'returns the error test case' do
+ is_expected.to eq([test_case_error])
+ end
+ end
+
+ context 'when head suite still has an error test case which errored in base' do
+ before do
+ base_suite.add_test_case(test_case_error)
+ head_suite.add_test_case(test_case_error)
+ end
+
+ it 'does not return the error test case' do
+ is_expected.to be_empty
+ end
+ end
+
+ context 'when head suite has a success test case which errored in base' do
+ before do
+ base_suite.add_test_case(test_case_error)
+ head_suite.add_test_case(test_case_success)
+ end
+
+ it 'does not return the error test case' do
+ is_expected.to be_empty
+ end
+ end
+ end
+
+ describe '#existing_errors' do
+ subject { comparer.existing_errors }
+
+ context 'when head suite has a new error test case which does not exist in base' do
+ before do
+ base_suite.add_test_case(test_case_success)
+ head_suite.add_test_case(test_case_error)
+ end
+
+ it 'does not return the error test case' do
+ is_expected.to be_empty
+ end
+ end
+
+ context 'when head suite still has an error test case which errored in base' do
+ before do
+ base_suite.add_test_case(test_case_error)
+ head_suite.add_test_case(test_case_error)
+ end
+
+ it 'returns the error test case' do
+ is_expected.to eq([test_case_error])
+ end
+ end
+
+ context 'when head suite has a success test case which errored in base' do
+ before do
+ base_suite.add_test_case(test_case_error)
+ head_suite.add_test_case(test_case_success)
+ end
+
+ it 'does not return the error test case' do
+ is_expected.to be_empty
+ end
+ end
+ end
+
+ describe '#resolved_errors' do
+ subject { comparer.resolved_errors }
+
+ context 'when head suite has a new error test case which does not exist in base' do
+ before do
+ base_suite.add_test_case(test_case_success)
+ head_suite.add_test_case(test_case_error)
+ end
+
+ it 'does not return the error test case' do
+ is_expected.to be_empty
+ end
+
+ it 'returns the correct resolved count' do
+ expect(comparer.resolved_count).to eq(0)
+ end
+ end
+
+ context 'when head suite still has an error test case which errored in base' do
+ before do
+ base_suite.add_test_case(test_case_error)
+ head_suite.add_test_case(test_case_error)
+ end
+
+ it 'does not return the error test case' do
+ is_expected.to be_empty
+ end
+
+ it 'returns the correct resolved count' do
+ expect(comparer.resolved_count).to eq(0)
+ end
+ end
+
+ context 'when head suite has a success test case which errored in base' do
+ before do
+ base_suite.add_test_case(test_case_error)
+ head_suite.add_test_case(test_case_success)
+ end
+
+ it 'returns the resolved test case' do
+ is_expected.to eq([test_case_success])
+ end
+
+ it 'returns the correct resolved count' do
+ expect(comparer.resolved_count).to eq(1)
+ end
+ end
+ end
+
describe '#total_count' do
subject { comparer.total_count }
@@ -208,7 +332,17 @@ describe Gitlab::Ci::Reports::TestSuiteComparer do
head_suite.add_test_case(test_case_failed)
end
- it 'returns the total status in head suite' do
+ it 'returns the total status in head suite as failed' do
+ is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
+ end
+ end
+
+ context 'when there is an error test case in head suite' do
+ before do
+ head_suite.add_test_case(test_case_error)
+ end
+
+ it 'returns the total status in head suite as failed' do
is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
end
end
diff --git a/spec/lib/gitlab/ci/reports/test_suite_spec.rb b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
index 8646db43bc8..217713fd899 100644
--- a/spec/lib/gitlab/ci/reports/test_suite_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
@@ -74,6 +74,15 @@ describe Gitlab::Ci::Reports::TestSuite do
it { is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_FAILED) }
end
+
+ context 'when a test case errored' do
+ before do
+ test_suite.add_test_case(test_case_success)
+ test_suite.add_test_case(test_case_error)
+ end
+
+ it { is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_FAILED) }
+ end
end
Gitlab::Ci::Reports::TestCase::STATUS_TYPES.each do |status_type|
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 7250258061a..4dadb310029 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -36,8 +36,6 @@ issues:
- vulnerability_links
- related_vulnerabilities
- user_mentions
-- blocked_by_issue_links
-- blocked_by_issues
events:
- author
- project
diff --git a/spec/lib/gitlab/runtime_spec.rb b/spec/lib/gitlab/runtime_spec.rb
index 56df73161b4..34a775fc206 100644
--- a/spec/lib/gitlab/runtime_spec.rb
+++ b/spec/lib/gitlab/runtime_spec.rb
@@ -50,7 +50,7 @@ describe Gitlab::Runtime do
allow(puma_type).to receive_message_chain(:cli_config, :options).and_return(max_threads: 2)
end
- it_behaves_like "valid runtime", :puma, 2
+ it_behaves_like "valid runtime", :puma, 3
end
context "unicorn" do
@@ -71,7 +71,7 @@ describe Gitlab::Runtime do
allow(sidekiq_type).to receive(:options).and_return(concurrency: 2)
end
- it_behaves_like "valid runtime", :sidekiq, 2
+ it_behaves_like "valid runtime", :sidekiq, 4
end
context "console" do
diff --git a/spec/mailers/emails/pipelines_spec.rb b/spec/mailers/emails/pipelines_spec.rb
index 8d4afe9f00f..ad1aa915fbb 100644
--- a/spec/mailers/emails/pipelines_spec.rb
+++ b/spec/mailers/emails/pipelines_spec.rb
@@ -19,6 +19,25 @@ describe Emails::Pipelines do
expect(subject).to have_body_text status_text
end
+ context 'when pipeline on master branch has a merge request' do
+ let(:pipeline) { create(:ci_pipeline, ref: 'master', sha: sha, project: project) }
+
+ let!(:merge_request) do
+ create(:merge_request, source_branch: 'master', target_branch: 'feature',
+ source_project: project, target_project: project)
+ end
+
+ it 'has correct information that there is no merge request link' do
+ expect(subject)
+ .to have_subject "#{project.name} | Pipeline ##{pipeline.id} has " \
+ "#{status} for #{pipeline.source_ref} | " \
+ "#{pipeline.short_sha}".to_s
+
+ expect(subject).to have_body_text pipeline.source_ref
+ expect(subject).to have_body_text status_text
+ end
+ end
+
context 'when pipeline for merge requests' do
let(:pipeline) { merge_request.all_pipelines.first }
@@ -28,7 +47,7 @@ describe Emails::Pipelines do
target_project: project)
end
- it 'has a correct information with merge request link' do
+ it 'has correct information that there is a merge request link' do
expect(subject)
.to have_subject "#{project.name} | Pipeline ##{pipeline.id} has " \
"#{status} for #{pipeline.source_ref} | " \
@@ -39,6 +58,27 @@ describe Emails::Pipelines do
expect(subject).not_to have_body_text pipeline.ref
end
end
+
+ context 'when branch pipeline is set to a merge request as a head pipeline' do
+ let(:pipeline) do
+ create(:ci_pipeline, project: project, ref: ref, sha: sha,
+ merge_requests_as_head_pipeline: [merge_request])
+ end
+
+ let(:merge_request) do
+ create(:merge_request, source_project: project, target_project: project)
+ end
+
+ it 'has correct information that there is a merge request link' do
+ expect(subject)
+ .to have_subject "#{project.name} | Pipeline ##{pipeline.id} has " \
+ "#{status} for #{pipeline.source_ref} | " \
+ "#{pipeline.short_sha} in !#{merge_request.iid}".to_s
+
+ expect(subject).to have_body_text merge_request.to_reference
+ expect(subject).to have_body_text pipeline.source_ref
+ end
+ end
end
describe '#pipeline_success_email' do
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index dc055244af7..6c90a1b5614 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -153,6 +153,16 @@ describe Project do
expect(project.container_expiration_policy).to be_persisted
end
+ it 'does not create another container expiration policy if there is already one' do
+ project = build(:project)
+
+ expect do
+ container_expiration_policy = create(:container_expiration_policy, project: project)
+
+ expect(project.container_expiration_policy).to eq(container_expiration_policy)
+ end.to change { ContainerExpirationPolicy.count }.by(1)
+ end
+
it 'automatically creates a Pages metadata row' do
expect(project.pages_metadatum).to be_an_instance_of(ProjectPagesMetadatum)
expect(project.pages_metadatum).to be_persisted
diff --git a/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
new file mode 100644
index 00000000000..0362fef2d2e
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
@@ -0,0 +1,244 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Updating an image DiffNote' do
+ include GraphqlHelpers
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:noteable) { create(:merge_request, :with_diffs) }
+ let_it_be(:original_body) { 'Original body' }
+ let_it_be(:original_position) do
+ Gitlab::Diff::Position.new(
+ old_path: 'files/images/any_image.png',
+ new_path: 'files/images/any_image.png',
+ width: 10,
+ height: 20,
+ x: 1,
+ y: 2,
+ diff_refs: noteable.diff_refs,
+ position_type: 'image'
+ )
+ end
+ let_it_be(:updated_body) { 'Updated body' }
+ let_it_be(:updated_width) { 50 }
+ let_it_be(:updated_height) { 100 }
+ let_it_be(:updated_x) { 5 }
+ let_it_be(:updated_y) { 10 }
+ let(:updated_position) do
+ {
+ width: updated_width,
+ height: updated_height,
+ x: updated_x,
+ y: updated_y
+ }
+ end
+ let!(:diff_note) do
+ create(:image_diff_note_on_merge_request,
+ noteable: noteable,
+ project: noteable.project,
+ note: original_body,
+ position: original_position)
+ end
+ let(:mutation) do
+ variables = {
+ id: GitlabSchema.id_from_object(diff_note).to_s,
+ body: updated_body,
+ position: updated_position
+ }
+
+ graphql_mutation(:update_image_diff_note, variables)
+ end
+
+ def mutation_response
+ graphql_mutation_response(:update_image_diff_note)
+ end
+
+ context 'when the user does not have permission' do
+ let_it_be(:current_user) { create(:user) }
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ['The resource that you are attempting to access does not exist or you don\'t have permission to perform this action']
+
+ it 'does not update the DiffNote' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ diff_note.reload
+
+ expect(diff_note).to have_attributes(
+ note: original_body,
+ position: have_attributes(
+ width: original_position.width,
+ height: original_position.height,
+ x: original_position.x,
+ y: original_position.y
+ )
+ )
+ end
+ end
+
+ context 'when the user has permission' do
+ let(:current_user) { diff_note.author }
+
+ it 'updates the DiffNote' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ diff_note.reload
+
+ expect(diff_note).to have_attributes(
+ note: updated_body,
+ position: have_attributes(
+ width: updated_width,
+ height: updated_height,
+ x: updated_x,
+ y: updated_y
+ )
+ )
+ end
+
+ it 'returns the updated DiffNote' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['note']).to include(
+ 'body' => updated_body,
+ 'position' => hash_including(
+ 'width' => updated_width,
+ 'height' => updated_height,
+ 'x' => updated_x,
+ 'y' => updated_y
+ )
+ )
+ end
+
+ describe 'updating single properties at a time' do
+ where(:property, :new_value) do
+ :body | 'foo'
+ :width | 19
+ :height | 18
+ :x | 17
+ :y | 16
+ end
+
+ with_them do
+ # Properties that will be POSTed:
+ let(:updated_body) { value(:body) }
+ let(:updated_width) { value(:width) }
+ let(:updated_height) { value(:height) }
+ let(:updated_x) { value(:x) }
+ let(:updated_y) { value(:y) }
+ # Expectations of the properties:
+ let(:expected_body) { value(:body) || original_body }
+ let(:expected_width) { value(:width) || original_position.width }
+ let(:expected_height) { value(:height) || original_position.height }
+ let(:expected_x) { value(:x) || original_position.x }
+ let(:expected_y) { value(:y) || original_position.y }
+
+ def value(prop)
+ new_value if property == prop
+ end
+
+ it 'updates the DiffNote correctly' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ diff_note.reload
+
+ expect(diff_note).to have_attributes(
+ note: expected_body,
+ position: have_attributes(
+ width: expected_width,
+ height: expected_height,
+ x: expected_x,
+ y: expected_y
+ )
+ )
+ end
+ end
+
+ context 'when position is nil' do
+ let(:updated_position) { nil }
+
+ it 'updates the DiffNote correctly' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ diff_note.reload
+
+ expect(diff_note).to have_attributes(
+ note: updated_body,
+ position: original_position
+ )
+ end
+ end
+ end
+
+ context 'when both body and position args are blank' do
+ let(:updated_body) { nil }
+ let(:updated_position) { nil }
+
+ it_behaves_like 'a mutation that returns top-level errors', errors: ['body or position arguments are required']
+ end
+
+ context 'when resource is not a DiffNote on an image' do
+ let!(:diff_note) { create(:diff_note_on_merge_request, note: original_body) }
+
+ it_behaves_like 'a mutation that returns top-level errors', errors: ['Resource is not an ImageDiffNote']
+ end
+
+ context 'when there are ActiveRecord validation errors' do
+ before do
+ expect(diff_note).to receive_message_chain(
+ :errors,
+ :full_messages
+ ).and_return(['Error 1', 'Error 2'])
+
+ expect_next_instance_of(Notes::UpdateService) do |service|
+ expect(service).to receive(:execute).and_return(diff_note)
+ end
+ end
+
+ it_behaves_like 'a mutation that returns errors in the response', errors: ['Error 1', 'Error 2']
+
+ it 'does not update the DiffNote' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ diff_note.reload
+
+ expect(diff_note).to have_attributes(
+ note: original_body,
+ position: have_attributes(
+ width: original_position.width,
+ height: original_position.height,
+ x: original_position.x,
+ y: original_position.y
+ )
+ )
+ end
+
+ it 'returns the DiffNote with its original body' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['note']).to include(
+ 'body' => original_body,
+ 'position' => hash_including(
+ 'width' => original_position.width,
+ 'height' => original_position.height,
+ 'x' => original_position.x,
+ 'y' => original_position.y
+ )
+ )
+ end
+ end
+
+ context 'when body only contains quick actions' do
+ let(:updated_body) { '/close' }
+
+ it 'returns a nil note and empty errors' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response).to include(
+ 'errors' => [],
+ 'note' => nil
+ )
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/notes/update_spec.rb b/spec/requests/api/graphql/mutations/notes/update/note_spec.rb
index 958f640995a..a5c6b72005e 100644
--- a/spec/requests/api/graphql/mutations/notes/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/update/note_spec.rb
@@ -22,7 +22,7 @@ describe 'Updating a Note' do
end
context 'when the user does not have permission' do
- let(:current_user) { create(:user) }
+ let_it_be(:current_user) { create(:user) }
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not exist or you don\'t have permission to perform this action']
@@ -68,5 +68,18 @@ describe 'Updating a Note' do
expect(mutation_response['note']['body']).to eq(original_body)
end
end
+
+ context 'when body only contains quick actions' do
+ let(:updated_body) { '/close' }
+
+ it 'returns a nil note and empty errors' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response).to include(
+ 'errors' => [],
+ 'note' => nil
+ )
+ end
+ end
end
end
diff --git a/spec/serializers/test_reports_comparer_entity_spec.rb b/spec/serializers/test_reports_comparer_entity_spec.rb
index 2627ad536e4..e7dabc67325 100644
--- a/spec/serializers/test_reports_comparer_entity_spec.rb
+++ b/spec/serializers/test_reports_comparer_entity_spec.rb
@@ -24,7 +24,7 @@ describe TestReportsComparerEntity do
it 'contains correct compared test reports details' do
expect(subject[:status]).to eq('success')
- expect(subject[:summary]).to include(total: 2, resolved: 0, failed: 0)
+ expect(subject[:summary]).to include(total: 2, resolved: 0, failed: 0, errored: 0)
expect(subject[:suites].first[:name]).to eq('rspec')
expect(subject[:suites].first[:status]).to eq('success')
expect(subject[:suites].second[:name]).to eq('junit')
@@ -42,7 +42,7 @@ describe TestReportsComparerEntity do
it 'contains correct compared test reports details' do
expect(subject[:status]).to eq('failed')
- expect(subject[:summary]).to include(total: 2, resolved: 0, failed: 1)
+ expect(subject[:summary]).to include(total: 2, resolved: 0, failed: 1, errored: 0)
expect(subject[:suites].first[:name]).to eq('rspec')
expect(subject[:suites].first[:status]).to eq('success')
expect(subject[:suites].second[:name]).to eq('junit')
@@ -60,7 +60,7 @@ describe TestReportsComparerEntity do
it 'contains correct compared test reports details' do
expect(subject[:status]).to eq('success')
- expect(subject[:summary]).to include(total: 2, resolved: 1, failed: 0)
+ expect(subject[:summary]).to include(total: 2, resolved: 1, failed: 0, errored: 0)
expect(subject[:suites].first[:name]).to eq('rspec')
expect(subject[:suites].first[:status]).to eq('success')
expect(subject[:suites].second[:name]).to eq('junit')
diff --git a/spec/serializers/test_suite_comparer_entity_spec.rb b/spec/serializers/test_suite_comparer_entity_spec.rb
index e22387130a1..9790777a570 100644
--- a/spec/serializers/test_suite_comparer_entity_spec.rb
+++ b/spec/serializers/test_suite_comparer_entity_spec.rb
@@ -12,6 +12,7 @@ describe TestSuiteComparerEntity do
let(:head_suite) { Gitlab::Ci::Reports::TestSuite.new(name) }
let(:test_case_success) { create_test_case_rspec_success }
let(:test_case_failed) { create_test_case_rspec_failed }
+ let(:test_case_error) { create_test_case_rspec_error }
describe '#as_json' do
subject { entity.as_json }
@@ -25,7 +26,7 @@ describe TestSuiteComparerEntity do
it 'contains correct compared test suite details' do
expect(subject[:name]).to eq(name)
expect(subject[:status]).to eq('failed')
- expect(subject[:summary]).to include(total: 1, resolved: 0, failed: 1)
+ expect(subject[:summary]).to include(total: 1, resolved: 0, failed: 1, errored: 0)
subject[:new_failures].first.tap do |new_failure|
expect(new_failure[:status]).to eq(test_case_failed.status)
expect(new_failure[:name]).to eq(test_case_failed.name)
@@ -37,6 +38,27 @@ describe TestSuiteComparerEntity do
end
end
+ context 'when head suite has a new error test case which does not exist in base' do
+ before do
+ base_suite.add_test_case(test_case_success)
+ head_suite.add_test_case(test_case_error)
+ end
+
+ it 'contains correct compared test suite details' do
+ expect(subject[:name]).to eq(name)
+ expect(subject[:status]).to eq('failed')
+ expect(subject[:summary]).to include(total: 1, resolved: 0, failed: 0, errored: 1)
+ subject[:new_errors].first.tap do |new_error|
+ expect(new_error[:status]).to eq(test_case_error.status)
+ expect(new_error[:name]).to eq(test_case_error.name)
+ expect(new_error[:execution_time]).to eq(test_case_error.execution_time)
+ expect(new_error[:system_output]).to eq(test_case_error.system_output)
+ end
+ expect(subject[:resolved_failures]).to be_empty
+ expect(subject[:existing_failures]).to be_empty
+ end
+ end
+
context 'when head suite still has a failed test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
@@ -46,7 +68,7 @@ describe TestSuiteComparerEntity do
it 'contains correct compared test suite details' do
expect(subject[:name]).to eq(name)
expect(subject[:status]).to eq('failed')
- expect(subject[:summary]).to include(total: 1, resolved: 0, failed: 1)
+ expect(subject[:summary]).to include(total: 1, resolved: 0, failed: 1, errored: 0)
expect(subject[:new_failures]).to be_empty
expect(subject[:resolved_failures]).to be_empty
subject[:existing_failures].first.tap do |existing_failure|
@@ -67,7 +89,7 @@ describe TestSuiteComparerEntity do
it 'contains correct compared test suite details' do
expect(subject[:name]).to eq(name)
expect(subject[:status]).to eq('success')
- expect(subject[:summary]).to include(total: 1, resolved: 1, failed: 0)
+ expect(subject[:summary]).to include(total: 1, resolved: 1, failed: 0, errored: 0)
expect(subject[:new_failures]).to be_empty
subject[:resolved_failures].first.tap do |resolved_failure|
expect(resolved_failure[:status]).to eq(test_case_success.status)
@@ -88,42 +110,57 @@ describe TestSuiteComparerEntity do
context 'prefers new over existing and resolved' do
before do
3.times { add_new_failure }
+ 3.times { add_new_error }
3.times { add_existing_failure }
+ 3.times { add_existing_error }
3.times { add_resolved_failure }
+ 3.times { add_resolved_error }
end
- it 'returns 2 new failures, and 1 of resolved and existing' do
- expect(subject[:summary]).to include(total: 9, resolved: 3, failed: 6)
+ it 'returns 2 of each new category, and 1 of each resolved and existing' do
+ expect(subject[:summary]).to include(total: 18, resolved: 6, failed: 6, errored: 6)
expect(subject[:new_failures].count).to eq(2)
+ expect(subject[:new_errors].count).to eq(2)
expect(subject[:existing_failures].count).to eq(1)
+ expect(subject[:existing_errors].count).to eq(1)
expect(subject[:resolved_failures].count).to eq(1)
+ expect(subject[:resolved_errors].count).to eq(1)
end
end
context 'prefers existing over resolved' do
before do
3.times { add_existing_failure }
+ 3.times { add_existing_error }
3.times { add_resolved_failure }
+ 3.times { add_resolved_error }
end
- it 'returns 2 existing failures, and 1 resolved' do
- expect(subject[:summary]).to include(total: 6, resolved: 3, failed: 3)
+ it 'returns 2 of each existing category, and 1 of each resolved' do
+ expect(subject[:summary]).to include(total: 12, resolved: 6, failed: 3, errored: 3)
expect(subject[:new_failures].count).to eq(0)
+ expect(subject[:new_errors].count).to eq(0)
expect(subject[:existing_failures].count).to eq(2)
+ expect(subject[:existing_errors].count).to eq(2)
expect(subject[:resolved_failures].count).to eq(1)
+ expect(subject[:resolved_errors].count).to eq(1)
end
end
context 'limits amount of resolved' do
before do
3.times { add_resolved_failure }
+ 3.times { add_resolved_error }
end
- it 'returns 2 resolved failures' do
- expect(subject[:summary]).to include(total: 3, resolved: 3, failed: 0)
+ it 'returns 2 of each resolved category' do
+ expect(subject[:summary]).to include(total: 6, resolved: 6, failed: 0, errored: 0)
expect(subject[:new_failures].count).to eq(0)
+ expect(subject[:new_errors].count).to eq(0)
expect(subject[:existing_failures].count).to eq(0)
+ expect(subject[:existing_errors].count).to eq(0)
expect(subject[:resolved_failures].count).to eq(2)
+ expect(subject[:resolved_errors].count).to eq(2)
end
end
@@ -134,19 +171,38 @@ describe TestSuiteComparerEntity do
head_suite.add_test_case(failed_case)
end
+ def add_new_error
+ error_case = create_test_case_rspec_error(SecureRandom.hex)
+ head_suite.add_test_case(error_case)
+ end
+
def add_existing_failure
failed_case = create_test_case_rspec_failed(SecureRandom.hex)
base_suite.add_test_case(failed_case)
head_suite.add_test_case(failed_case)
end
+ def add_existing_error
+ error_case = create_test_case_rspec_error(SecureRandom.hex)
+ base_suite.add_test_case(error_case)
+ head_suite.add_test_case(error_case)
+ end
+
def add_resolved_failure
case_name = SecureRandom.hex
- failed_case = create_test_case_rspec_failed(case_name)
- success_case = create_test_case_rspec_success(case_name)
+ failed_case = create_test_case_java_failed(case_name)
+ success_case = create_test_case_java_success(case_name)
base_suite.add_test_case(failed_case)
head_suite.add_test_case(success_case)
end
+
+ def add_resolved_error
+ case_name = SecureRandom.hex
+ error_case = create_test_case_java_error(case_name)
+ success_case = create_test_case_java_success(case_name)
+ base_suite.add_test_case(error_case)
+ head_suite.add_test_case(success_case)
+ end
end
end
end
diff --git a/spec/services/snippets/create_service_spec.rb b/spec/services/snippets/create_service_spec.rb
index 7aa8f0ebf8f..1cf1cff51ed 100644
--- a/spec/services/snippets/create_service_spec.rb
+++ b/spec/services/snippets/create_service_spec.rb
@@ -143,6 +143,34 @@ describe Snippets::CreateService do
end
end
+ shared_examples 'creates repository' do
+ it do
+ subject
+
+ expect(snippet.repository_exists?).to be_truthy
+ end
+
+ context 'when snippet creation fails' do
+ let(:extra_opts) { { content: nil } }
+
+ it 'does not create repository' do
+ subject
+
+ expect(snippet.repository_exists?).to be_falsey
+ end
+ end
+
+ context 'when feature flag :version_snippets is disabled' do
+ it 'does not create snippet repository' do
+ stub_feature_flags(version_snippets: false)
+
+ subject
+
+ expect(snippet.repository_exists?).to be_falsey
+ end
+ end
+ end
+
context 'when Project Snippet' do
let_it_be(:project) { create(:project) }
@@ -155,6 +183,7 @@ describe Snippets::CreateService do
it_behaves_like 'spam check is performed'
it_behaves_like 'snippet create data is tracked'
it_behaves_like 'an error service response when save fails'
+ it_behaves_like 'creates repository'
end
context 'when PersonalSnippet' do
@@ -165,6 +194,7 @@ describe Snippets::CreateService do
it_behaves_like 'spam check is performed'
it_behaves_like 'snippet create data is tracked'
it_behaves_like 'an error service response when save fails'
+ it_behaves_like 'creates repository'
end
end
end
diff --git a/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb b/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb
index 2548afc1570..8092f87383d 100644
--- a/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb
+++ b/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb
@@ -123,7 +123,7 @@ RSpec.shared_examples 'cycle analytics label based stage' do
})
expect(stage).to be_invalid
- expect(stage.errors[:start_event_label]).to include("can't be blank")
+ expect(stage.errors[:start_event_label_id]).to include("can't be blank")
end
it 'returns validation error when `end_event_label_id` is missing' do
@@ -135,7 +135,7 @@ RSpec.shared_examples 'cycle analytics label based stage' do
})
expect(stage).to be_invalid
- expect(stage.errors[:end_event_label]).to include("can't be blank")
+ expect(stage.errors[:end_event_label_id]).to include("can't be blank")
end
end
@@ -145,7 +145,7 @@ RSpec.shared_examples 'cycle analytics label based stage' do
name: 'My Stage',
parent: parent,
start_event_identifier: :issue_label_added,
- start_event_label: group_label,
+ start_event_label_id: group_label.id,
end_event_identifier: :issue_closed
})
@@ -159,7 +159,7 @@ RSpec.shared_examples 'cycle analytics label based stage' do
name: 'My Stage',
parent: parent_in_subgroup,
start_event_identifier: :issue_label_added,
- start_event_label: group_label,
+ start_event_label_id: group_label.id,
end_event_identifier: :issue_closed
})
@@ -170,30 +170,30 @@ RSpec.shared_examples 'cycle analytics label based stage' do
context 'when label is defined for a different group' do
let(:error_message) { s_('CycleAnalyticsStage|is not available for the selected group') }
- it 'returns validation for `start_event_label`' do
+ it 'returns validation for `start_event_label_id`' do
stage = described_class.new({
name: 'My Stage',
parent: parent_outside_of_group_label_scope,
start_event_identifier: :issue_label_added,
- start_event_label: group_label,
+ start_event_label_id: group_label.id,
end_event_identifier: :issue_closed
})
expect(stage).to be_invalid
- expect(stage.errors[:start_event_label]).to include(error_message)
+ expect(stage.errors[:start_event_label_id]).to include(error_message)
end
- it 'returns validation for `end_event_label`' do
+ it 'returns validation for `end_event_label_id`' do
stage = described_class.new({
name: 'My Stage',
parent: parent_outside_of_group_label_scope,
start_event_identifier: :issue_closed,
end_event_identifier: :issue_label_added,
- end_event_label: group_label
+ end_event_label_id: group_label.id
})
expect(stage).to be_invalid
- expect(stage.errors[:end_event_label]).to include(error_message)
+ expect(stage.errors[:end_event_label_id]).to include(error_message)
end
end