summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/features/issues/user_sorts_issues_spec.rb2
-rw-r--r--spec/finders/issues_finder_spec.rb30
-rw-r--r--spec/frontend/environments/deployment_spec.js23
-rw-r--r--spec/frontend/google_cloud/components/service_accounts_form_spec.js19
-rw-r--r--spec/frontend/lib/utils/number_utility_spec.js16
-rw-r--r--spec/frontend/sidebar/components/todo_toggle/sidebar_todo_widget_spec.js6
-rw-r--r--spec/frontend/vue_shared/issuable/list/components/issuable_tabs_spec.js86
-rw-r--r--spec/frontend/vue_shared/issuable/list/mock_data.js2
-rw-r--r--spec/graphql/types/ci/runner_type_spec.rb2
-rw-r--r--spec/lib/bitbucket_server/representation/repo_spec.rb5
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/ensure_environments_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb165
-rw-r--r--spec/models/container_repository_spec.rb64
-rw-r--r--spec/requests/api/graphql/ci/runner_spec.rb51
-rw-r--r--spec/requests/api/issues/issues_spec.rb28
-rw-r--r--spec/services/ci/retry_build_service_spec.rb17
-rw-r--r--spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb86
-rw-r--r--spec/uploaders/import_export_uploader_spec.rb28
-rw-r--r--spec/workers/concerns/application_worker_spec.rb39
21 files changed, 382 insertions, 323 deletions
diff --git a/spec/features/issues/user_sorts_issues_spec.rb b/spec/features/issues/user_sorts_issues_spec.rb
index 48297e9049e..00fdea69b60 100644
--- a/spec/features/issues/user_sorts_issues_spec.rb
+++ b/spec/features/issues/user_sorts_issues_spec.rb
@@ -141,7 +141,7 @@ RSpec.describe "User sorts issues" do
page.within '.issues-list' do
expect(page).to have_content('foo')
expect(page).to have_content('bar')
- expect(page).to have_content('baz')
+ expect(page).not_to have_content('baz')
end
end
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index 31563a6326d..c22e56c3b9e 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -1018,6 +1018,8 @@ RSpec.describe IssuesFinder do
end
context 'filtering by due date' do
+ let_it_be(:issue_due_today) { create(:issue, project: project1, due_date: Date.current) }
+ let_it_be(:issue_due_tomorrow) { create(:issue, project: project1, due_date: 1.day.from_now) }
let_it_be(:issue_overdue) { create(:issue, project: project1, due_date: 2.days.ago) }
let_it_be(:issue_due_soon) { create(:issue, project: project1, due_date: 2.days.from_now) }
@@ -1032,6 +1034,30 @@ RSpec.describe IssuesFinder do
end
end
+ context 'with param set to any due date' do
+ let(:params) { base_params.merge(due_date: Issue::AnyDueDate.name) }
+
+ it 'returns issues with any due date' do
+ expect(issues).to contain_exactly(issue_due_today, issue_due_tomorrow, issue_overdue, issue_due_soon)
+ end
+ end
+
+ context 'with param set to due today' do
+ let(:params) { base_params.merge(due_date: Issue::DueToday.name) }
+
+ it 'returns issues due today' do
+ expect(issues).to contain_exactly(issue_due_today)
+ end
+ end
+
+ context 'with param set to due tomorrow' do
+ let(:params) { base_params.merge(due_date: Issue::DueTomorrow.name) }
+
+ it 'returns issues due today' do
+ expect(issues).to contain_exactly(issue_due_tomorrow)
+ end
+ end
+
context 'with param set to overdue' do
let(:params) { base_params.merge(due_date: Issue::Overdue.name) }
@@ -1043,8 +1069,8 @@ RSpec.describe IssuesFinder do
context 'with param set to next month and previous two weeks' do
let(:params) { base_params.merge(due_date: Issue::DueNextMonthAndPreviousTwoWeeks.name) }
- it 'returns issues from the previous two weeks and next month' do
- expect(issues).to contain_exactly(issue_overdue, issue_due_soon)
+ it 'returns issues due in the previous two weeks and next month' do
+ expect(issues).to contain_exactly(issue_due_today, issue_due_tomorrow, issue_overdue, issue_due_soon)
end
end
diff --git a/spec/frontend/environments/deployment_spec.js b/spec/frontend/environments/deployment_spec.js
index a68e17fe6ac..a1b232d783e 100644
--- a/spec/frontend/environments/deployment_spec.js
+++ b/spec/frontend/environments/deployment_spec.js
@@ -1,11 +1,15 @@
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { __, s__ } from '~/locale';
+import { formatDate } from '~/lib/utils/datetime_utility';
+import { useFakeDate } from 'helpers/fake_date';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import Deployment from '~/environments/components/deployment.vue';
import DeploymentStatusBadge from '~/environments/components/deployment_status_badge.vue';
import { resolvedEnvironment } from './graphql/mock_data';
describe('~/environments/components/deployment.vue', () => {
+ useFakeDate(2022, 0, 8, 16);
+
const deployment = resolvedEnvironment.lastDeployment;
let wrapper;
@@ -125,4 +129,23 @@ describe('~/environments/components/deployment.vue', () => {
});
});
});
+
+ describe('created at time', () => {
+ describe('is present', () => {
+ it('shows the timestamp the deployment was deployed at', () => {
+ wrapper = createWrapper();
+ const date = wrapper.findByTitle(formatDate(deployment.createdAt));
+
+ expect(date.text()).toBe('1 day ago');
+ });
+ });
+ describe('is not present', () => {
+ it('does not show the timestamp', () => {
+ wrapper = createWrapper({ propsData: { deployment: { createdAt: null } } });
+ const date = wrapper.findByTitle(formatDate(deployment.createdAt));
+
+ expect(date.exists()).toBe(false);
+ });
+ });
+ });
});
diff --git a/spec/frontend/google_cloud/components/service_accounts_form_spec.js b/spec/frontend/google_cloud/components/service_accounts_form_spec.js
index 5394d0cdaef..7262e12c84d 100644
--- a/spec/frontend/google_cloud/components/service_accounts_form_spec.js
+++ b/spec/frontend/google_cloud/components/service_accounts_form_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlButton, GlFormGroup, GlFormSelect } from '@gitlab/ui';
+import { GlButton, GlFormGroup, GlFormSelect, GlFormCheckbox } from '@gitlab/ui';
import ServiceAccountsForm from '~/google_cloud/components/service_accounts_form.vue';
describe('ServiceAccountsForm component', () => {
@@ -9,11 +9,12 @@ describe('ServiceAccountsForm component', () => {
const findAllFormGroups = () => wrapper.findAllComponents(GlFormGroup);
const findAllFormSelects = () => wrapper.findAllComponents(GlFormSelect);
const findAllButtons = () => wrapper.findAllComponents(GlButton);
+ const findCheckbox = () => wrapper.findComponent(GlFormCheckbox);
const propsData = { gcpProjects: [], environments: [], cancelPath: '#cancel-url' };
beforeEach(() => {
- wrapper = shallowMount(ServiceAccountsForm, { propsData });
+ wrapper = shallowMount(ServiceAccountsForm, { propsData, stubs: { GlFormCheckbox } });
});
afterEach(() => {
@@ -35,8 +36,8 @@ describe('ServiceAccountsForm component', () => {
});
it('contains Environments form group', () => {
- const formGorup = findAllFormGroups().at(1);
- expect(formGorup.exists()).toBe(true);
+ const formGroup = findAllFormGroups().at(1);
+ expect(formGroup.exists()).toBe(true);
});
it('contains Environments dropdown', () => {
@@ -56,4 +57,14 @@ describe('ServiceAccountsForm component', () => {
expect(button.text()).toBe(ServiceAccountsForm.i18n.cancelLabel);
expect(button.attributes('href')).toBe('#cancel-url');
});
+
+ it('contains Confirmation checkbox', () => {
+ const checkbox = findCheckbox();
+ expect(checkbox.text()).toBe(ServiceAccountsForm.i18n.checkboxLabel);
+ });
+
+ it('checkbox must be required', () => {
+ const checkbox = findCheckbox();
+ expect(checkbox.attributes('required')).toBe('true');
+ });
});
diff --git a/spec/frontend/lib/utils/number_utility_spec.js b/spec/frontend/lib/utils/number_utility_spec.js
index e743678ea90..dc4aa0ea5ed 100644
--- a/spec/frontend/lib/utils/number_utility_spec.js
+++ b/spec/frontend/lib/utils/number_utility_spec.js
@@ -4,6 +4,7 @@ import {
bytesToMiB,
bytesToGiB,
numberToHumanSize,
+ numberToMetricPrefix,
sum,
isOdd,
median,
@@ -99,6 +100,21 @@ describe('Number Utils', () => {
});
});
+ describe('numberToMetricPrefix', () => {
+ it.each`
+ number | expected
+ ${123} | ${'123'}
+ ${1234} | ${'1.2k'}
+ ${12345} | ${'12.3k'}
+ ${123456} | ${'123.5k'}
+ ${1234567} | ${'1.2m'}
+ ${12345678} | ${'12.3m'}
+ ${123456789} | ${'123.5m'}
+ `('returns $expected given $number', ({ number, expected }) => {
+ expect(numberToMetricPrefix(number)).toBe(expected);
+ });
+ });
+
describe('sum', () => {
it('should add up two values', () => {
expect(sum(1, 2)).toEqual(3);
diff --git a/spec/frontend/sidebar/components/todo_toggle/sidebar_todo_widget_spec.js b/spec/frontend/sidebar/components/todo_toggle/sidebar_todo_widget_spec.js
index 23f1753c4bf..2fef3ab9293 100644
--- a/spec/frontend/sidebar/components/todo_toggle/sidebar_todo_widget_spec.js
+++ b/spec/frontend/sidebar/components/todo_toggle/sidebar_todo_widget_spec.js
@@ -1,4 +1,4 @@
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
@@ -103,7 +103,7 @@ describe('Sidebar Todo Widget', () => {
});
it('sets default tooltip title', () => {
- expect(wrapper.find(GlIcon).attributes('title')).toBe('Add a to do');
+ expect(wrapper.find(GlButton).attributes('title')).toBe('Add a to do');
});
it('when user has a to do', async () => {
@@ -113,7 +113,7 @@ describe('Sidebar Todo Widget', () => {
await waitForPromises();
expect(wrapper.find(GlIcon).props('name')).toBe('todo-done');
- expect(wrapper.find(GlIcon).attributes('title')).toBe('Mark as done');
+ expect(wrapper.find(GlButton).attributes('title')).toBe('Mark as done');
});
it('emits `todoUpdated` event on click on icon', async () => {
diff --git a/spec/frontend/vue_shared/issuable/list/components/issuable_tabs_spec.js b/spec/frontend/vue_shared/issuable/list/components/issuable_tabs_spec.js
index 5723e2da586..27985895c62 100644
--- a/spec/frontend/vue_shared/issuable/list/components/issuable_tabs_spec.js
+++ b/spec/frontend/vue_shared/issuable/list/components/issuable_tabs_spec.js
@@ -1,5 +1,6 @@
import { GlTab, GlBadge } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import { mount, shallowMount } from '@vue/test-utils';
import { setLanguage } from 'helpers/locale_helper';
import IssuableTabs from '~/vue_shared/issuable/list/components/issuable_tabs.vue';
@@ -10,17 +11,18 @@ const createComponent = ({
tabs = mockIssuableListProps.tabs,
tabCounts = mockIssuableListProps.tabCounts,
currentTab = mockIssuableListProps.currentTab,
+ truncateCounts = false,
+ mountFn = shallowMount,
} = {}) =>
- mount(IssuableTabs, {
+ mountFn(IssuableTabs, {
propsData: {
tabs,
tabCounts,
currentTab,
+ truncateCounts,
},
slots: {
- 'nav-actions': `
- <button class="js-new-issuable">New issuable</button>
- `,
+ 'nav-actions': `<button class="js-new-issuable">New issuable</button>`,
},
});
@@ -29,7 +31,6 @@ describe('IssuableTabs', () => {
beforeEach(() => {
setLanguage('en');
- wrapper = createComponent();
});
afterEach(() => {
@@ -40,60 +41,71 @@ describe('IssuableTabs', () => {
const findAllGlBadges = () => wrapper.findAllComponents(GlBadge);
const findAllGlTabs = () => wrapper.findAllComponents(GlTab);
- describe('methods', () => {
- describe('isTabActive', () => {
- it.each`
- tabName | currentTab | returnValue
- ${'opened'} | ${'opened'} | ${true}
- ${'opened'} | ${'closed'} | ${false}
- `(
- 'returns $returnValue when tab name is "$tabName" is current tab is "$currentTab"',
- async ({ tabName, currentTab, returnValue }) => {
- wrapper.setProps({
- currentTab,
- });
-
- await wrapper.vm.$nextTick();
-
- expect(wrapper.vm.isTabActive(tabName)).toBe(returnValue);
- },
- );
- });
+ describe('tabs', () => {
+ it.each`
+ currentTab | returnValue
+ ${'opened'} | ${'true'}
+ ${'closed'} | ${undefined}
+ `(
+ 'when "$currentTab" is the selected tab, the Open tab is active=$returnValue',
+ ({ currentTab, returnValue }) => {
+ wrapper = createComponent({ currentTab });
+
+ const openTab = findAllGlTabs().at(0);
+
+ expect(openTab.attributes('active')).toBe(returnValue);
+ },
+ );
});
describe('template', () => {
it('renders gl-tab for each tab within `tabs` array', () => {
- const tabsEl = findAllGlTabs();
+ wrapper = createComponent();
+
+ const tabs = findAllGlTabs();
- expect(tabsEl.exists()).toBe(true);
- expect(tabsEl).toHaveLength(mockIssuableListProps.tabs.length);
+ expect(tabs).toHaveLength(mockIssuableListProps.tabs.length);
});
- it('renders gl-badge component within a tab', () => {
+ it('renders gl-badge component within a tab', async () => {
+ wrapper = createComponent({ mountFn: mount });
+ await nextTick();
+
const badges = findAllGlBadges();
// Does not render `All` badge since it has an undefined count
expect(badges).toHaveLength(2);
- expect(badges.at(0).text()).toBe('5,000');
+ expect(badges.at(0).text()).toBe('5,678');
expect(badges.at(1).text()).toBe(`${mockIssuableListProps.tabCounts.closed}`);
});
it('renders contents for slot "nav-actions"', () => {
- const buttonEl = wrapper.find('button.js-new-issuable');
+ wrapper = createComponent();
- expect(buttonEl.exists()).toBe(true);
- expect(buttonEl.text()).toBe('New issuable');
+ const button = wrapper.find('button.js-new-issuable');
+
+ expect(button.text()).toBe('New issuable');
+ });
+ });
+
+ describe('counts', () => {
+ it('can display as truncated', async () => {
+ wrapper = createComponent({ truncateCounts: true, mountFn: mount });
+ await nextTick();
+
+ expect(findAllGlBadges().at(0).text()).toBe('5.7k');
});
});
describe('events', () => {
it('gl-tab component emits `click` event on `click` event', () => {
- const tabEl = findAllGlTabs().at(0);
+ wrapper = createComponent();
+
+ const openTab = findAllGlTabs().at(0);
- tabEl.vm.$emit('click', 'opened');
+ openTab.vm.$emit('click', 'opened');
- expect(wrapper.emitted('click')).toBeTruthy();
- expect(wrapper.emitted('click')[0]).toEqual(['opened']);
+ expect(wrapper.emitted('click')).toEqual([['opened']]);
});
});
});
diff --git a/spec/frontend/vue_shared/issuable/list/mock_data.js b/spec/frontend/vue_shared/issuable/list/mock_data.js
index cfc7937b412..8640f4a2cd5 100644
--- a/spec/frontend/vue_shared/issuable/list/mock_data.js
+++ b/spec/frontend/vue_shared/issuable/list/mock_data.js
@@ -133,7 +133,7 @@ export const mockTabs = [
];
export const mockTabCounts = {
- opened: 5000,
+ opened: 5678,
closed: 0,
all: undefined,
};
diff --git a/spec/graphql/types/ci/runner_type_spec.rb b/spec/graphql/types/ci/runner_type_spec.rb
index 1d8d3dd88bb..3f89058f44a 100644
--- a/spec/graphql/types/ci/runner_type_spec.rb
+++ b/spec/graphql/types/ci/runner_type_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe GitlabSchema.types['CiRunner'] do
id description created_at contacted_at maximum_timeout access_level active status
version short_sha revision locked run_untagged ip_address runner_type tag_list
project_count job_count admin_url edit_admin_url user_permissions executor_name
- groups
+ groups projects
]
expect(described_class).to include_graphql_fields(*expected_fields)
diff --git a/spec/lib/bitbucket_server/representation/repo_spec.rb b/spec/lib/bitbucket_server/representation/repo_spec.rb
index 7a773f47ca5..5de4360bbd0 100644
--- a/spec/lib/bitbucket_server/representation/repo_spec.rb
+++ b/spec/lib/bitbucket_server/representation/repo_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe BitbucketServer::Representation::Repo do
"slug": "rouge",
"id": 1,
"name": "rouge",
+ "description": "Rogue Repo",
"scmId": "git",
"state": "AVAILABLE",
"statusMessage": "Available",
@@ -17,7 +18,7 @@ RSpec.describe BitbucketServer::Representation::Repo do
"key": "TEST",
"id": 1,
"name": "test",
- "description": "Test",
+ "description": "Test Project",
"public": false,
"type": "NORMAL",
"links": {
@@ -73,7 +74,7 @@ RSpec.describe BitbucketServer::Representation::Repo do
end
describe '#description' do
- it { expect(subject.description).to eq('Test') }
+ it { expect(subject.description).to eq('Rogue Repo') }
end
describe '#full_name' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb
index 0a592395c3a..375841ce236 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb
@@ -47,18 +47,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::CreateDeployments do
expect(job.deployment).to be_nil
end
end
-
- context 'when create_deployment_in_separate_transaction feature flag is disabled' do
- before do
- stub_feature_flags(create_deployment_in_separate_transaction: false)
- end
-
- it 'does not create a deployment record' do
- expect { subject }.not_to change { Deployment.count }
-
- expect(job.deployment).to be_nil
- end
- end
end
context 'when a pipeline contains a teardown job' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/ensure_environments_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/ensure_environments_spec.rb
index 253928e1a19..6a7d9b58a05 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/ensure_environments_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/ensure_environments_spec.rb
@@ -57,18 +57,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::EnsureEnvironments do
expect(job.persisted_environment).to be_nil
end
end
-
- context 'when create_deployment_in_separate_transaction feature flag is disabled' do
- before do
- stub_feature_flags(create_deployment_in_separate_transaction: false)
- end
-
- it 'does not create any environments' do
- expect { subject }.not_to change { Environment.count }
-
- expect(job.persisted_environment).to be_nil
- end
- end
end
context 'when a pipeline contains a teardown job' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb
index 87df5a3e21b..571455d6279 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb
@@ -60,18 +60,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::EnsureResourceGroups do
expect(job.resource_group).to be_nil
end
end
-
- context 'when create_deployment_in_separate_transaction feature flag is disabled' do
- before do
- stub_feature_flags(create_deployment_in_separate_transaction: false)
- end
-
- it 'does not create any resource groups' do
- expect { subject }.not_to change { Ci::ResourceGroup.count }
-
- expect(job.resource_group).to be_nil
- end
- end
end
context 'when a pipeline does not contain a job that requires a resource group' do
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index 2f9fcd7caac..49505d397c2 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -411,171 +411,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
describe '#to_resource' do
subject { seed_build.to_resource }
- before do
- stub_feature_flags(create_deployment_in_separate_transaction: false)
- end
-
- context 'when job is Ci::Build' do
- it { is_expected.to be_a(::Ci::Build) }
- it { is_expected.to be_valid }
-
- shared_examples_for 'deployment job' do
- it 'returns a job with deployment' do
- expect { subject }.to change { Environment.count }.by(1)
-
- expect(subject.deployment).not_to be_nil
- expect(subject.deployment.deployable).to eq(subject)
- expect(subject.deployment.environment.name).to eq(expected_environment_name)
- end
- end
-
- shared_examples_for 'non-deployment job' do
- it 'returns a job without deployment' do
- expect(subject.deployment).to be_nil
- end
- end
-
- shared_examples_for 'ensures environment existence' do
- it 'has environment' do
- expect { subject }.to change { Environment.count }.by(1)
-
- expect(subject).to be_has_environment
- expect(subject.environment).to eq(environment_name)
- expect(subject.metadata.expanded_environment_name).to eq(expected_environment_name)
- expect(Environment.exists?(name: expected_environment_name)).to eq(true)
- end
- end
-
- shared_examples_for 'ensures environment inexistence' do
- it 'does not have environment' do
- expect { subject }.not_to change { Environment.count }
-
- expect(subject).not_to be_has_environment
- expect(subject.environment).to be_nil
- expect(subject.metadata&.expanded_environment_name).to be_nil
- expect(Environment.exists?(name: expected_environment_name)).to eq(false)
- end
- end
-
- context 'when job deploys to production' do
- let(:environment_name) { 'production' }
- let(:expected_environment_name) { 'production' }
- let(:attributes) { { name: 'deploy', ref: 'master', environment: 'production' } }
-
- it_behaves_like 'deployment job'
- it_behaves_like 'ensures environment existence'
-
- context 'when create_deployment_in_separate_transaction feature flag is enabled' do
- before do
- stub_feature_flags(create_deployment_in_separate_transaction: true)
- end
-
- it 'does not create any deployments nor environments' do
- expect(subject.deployment).to be_nil
- expect(Environment.count).to eq(0)
- expect(Deployment.count).to eq(0)
- end
- end
-
- context 'when the environment name is invalid' do
- let(:attributes) { { name: 'deploy', ref: 'master', environment: '!!!' } }
-
- it 'fails the job with a failure reason and does not create an environment' do
- expect(subject).to be_failed
- expect(subject).to be_environment_creation_failure
- expect(subject.metadata.expanded_environment_name).to be_nil
- expect(Environment.exists?(name: expected_environment_name)).to eq(false)
- end
- end
- end
-
- context 'when job starts a review app' do
- let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' }
- let(:expected_environment_name) { "review/#{pipeline.ref}" }
-
- let(:attributes) do
- {
- name: 'deploy', ref: 'master', environment: environment_name,
- options: { environment: { name: environment_name } }
- }
- end
-
- it_behaves_like 'deployment job'
- it_behaves_like 'ensures environment existence'
- end
-
- context 'when job stops a review app' do
- let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' }
- let(:expected_environment_name) { "review/#{pipeline.ref}" }
-
- let(:attributes) do
- {
- name: 'deploy', ref: 'master', environment: environment_name,
- options: { environment: { name: environment_name, action: 'stop' } }
- }
- end
-
- it 'returns a job without deployment' do
- expect(subject.deployment).to be_nil
- end
-
- it_behaves_like 'non-deployment job'
- it_behaves_like 'ensures environment existence'
- end
-
- context 'when job belongs to a resource group' do
- let(:resource_group) { 'iOS' }
- let(:attributes) { { name: 'rspec', ref: 'master', resource_group_key: resource_group, environment: 'production' }}
-
- it 'returns a job with resource group' do
- expect(subject.resource_group).not_to be_nil
- expect(subject.resource_group.key).to eq('iOS')
- expect(Ci::ResourceGroup.count).to eq(1)
- end
-
- context 'when create_deployment_in_separate_transaction feature flag is enabled' do
- before do
- stub_feature_flags(create_deployment_in_separate_transaction: true)
- end
-
- it 'does not create any resource groups' do
- expect(subject.resource_group).to be_nil
- expect(Ci::ResourceGroup.count).to eq(0)
- end
- end
-
- context 'when resource group has $CI_ENVIRONMENT_NAME in it' do
- let(:resource_group) { 'test/$CI_ENVIRONMENT_NAME' }
-
- it 'expands environment name' do
- expect(subject.resource_group.key).to eq('test/production')
- end
- end
- end
- end
-
- context 'when job is a bridge' do
- let(:base_attributes) do
- {
- name: 'rspec', ref: 'master', options: { trigger: 'my/project' }, scheduling_type: :stage
- }
- end
-
- let(:attributes) { base_attributes }
-
- it { is_expected.to be_a(::Ci::Bridge) }
- it { is_expected.to be_valid }
-
- context 'when job belongs to a resource group' do
- let(:attributes) { base_attributes.merge(resource_group_key: 'iOS') }
-
- it 'returns a job with resource group' do
- expect(subject.resource_group).not_to be_nil
- expect(subject.resource_group.key).to eq('iOS')
- end
- end
- end
-
it 'memoizes a resource object' do
expect(subject.object_id).to eq seed_build.to_resource.object_id
end
diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb
index 8f7c13d7ae6..6cfd7def013 100644
--- a/spec/models/container_repository_spec.rb
+++ b/spec/models/container_repository_spec.rb
@@ -330,6 +330,52 @@ RSpec.describe ContainerRepository do
end
end
+ describe '.find_by_path' do
+ let_it_be(:container_repository) { create(:container_repository) }
+ let_it_be(:repository_path) { container_repository.project.full_path }
+
+ let(:path) { ContainerRegistry::Path.new(repository_path + '/' + container_repository.name) }
+
+ subject { described_class.find_by_path(path) }
+
+ context 'when repository exists' do
+ it 'finds the repository' do
+ expect(subject).to eq(container_repository)
+ end
+ end
+
+ context 'when repository does not exist' do
+ let(:path) { ContainerRegistry::Path.new(repository_path + '/some/image') }
+
+ it 'returns nil' do
+ expect(subject).to be_nil
+ end
+ end
+ end
+
+ describe '.find_by_path!' do
+ let_it_be(:container_repository) { create(:container_repository) }
+ let_it_be(:repository_path) { container_repository.project.full_path }
+
+ let(:path) { ContainerRegistry::Path.new(repository_path + '/' + container_repository.name) }
+
+ subject { described_class.find_by_path!(path) }
+
+ context 'when repository exists' do
+ it 'finds the repository' do
+ expect(subject).to eq(container_repository)
+ end
+ end
+
+ context 'when repository does not exist' do
+ let(:path) { ContainerRegistry::Path.new(repository_path + '/some/image') }
+
+ it 'raises an exception' do
+ expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+ end
+
describe '.build_root_repository' do
let(:repository) do
described_class.build_root_repository(project)
@@ -458,6 +504,24 @@ RSpec.describe ContainerRepository do
it { is_expected.to eq([repository]) }
end
+ describe '#migration_importing?' do
+ let_it_be_with_reload(:container_repository) { create(:container_repository, migration_state: 'importing')}
+
+ subject { container_repository.migration_importing? }
+
+ it { is_expected.to eq(true) }
+
+ context 'when not importing' do
+ before do
+ # Technical debt: when the state machine is added, we should iterate through all possible states
+ # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78499
+ container_repository.update_column(:migration_state, 'default')
+ end
+
+ it { is_expected.to eq(false) }
+ end
+ end
+
context 'with repositories' do
let_it_be_with_reload(:repository) { create(:container_repository, :cleanup_unscheduled) }
let_it_be(:other_repository) { create(:container_repository, :cleanup_unscheduled) }
diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb
index 61f11952ddc..eb1f84e3ef9 100644
--- a/spec/requests/api/graphql/ci/runner_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_spec.rb
@@ -25,6 +25,8 @@ RSpec.describe 'Query.runner(id)' do
access_level: 0, tag_list: %w[tag1 tag2], run_untagged: true, executor_type: :shell)
end
+ let_it_be(:active_project_runner) { create(:ci_runner, :project) }
+
def get_runner(id)
case id
when :active_instance_runner
@@ -33,6 +35,8 @@ RSpec.describe 'Query.runner(id)' do
inactive_instance_runner
when :active_group_runner
active_group_runner
+ when :active_project_runner
+ active_project_runner
end
end
@@ -55,7 +59,7 @@ RSpec.describe 'Query.runner(id)' do
runner = get_runner(runner_id)
expect(runner_data).to match a_hash_including(
- 'id' => "gid://gitlab/Ci::Runner/#{runner.id}",
+ 'id' => runner.to_global_id.to_s,
'description' => runner.description,
'createdAt' => runner.created_at&.iso8601,
'contactedAt' => runner.contacted_at&.iso8601,
@@ -103,7 +107,7 @@ RSpec.describe 'Query.runner(id)' do
runner = get_runner(runner_id)
expect(runner_data).to match a_hash_including(
- 'id' => "gid://gitlab/Ci::Runner/#{runner.id}",
+ 'id' => runner.to_global_id.to_s,
'adminUrl' => nil
)
expect(runner_data['tagList']).to match_array runner.tag_list
@@ -179,7 +183,7 @@ RSpec.describe 'Query.runner(id)' do
runner_data = graphql_data_at(:runner)
expect(runner_data).to match a_hash_including(
- 'id' => "gid://gitlab/Ci::Runner/#{project_runner.id}",
+ 'id' => project_runner.to_global_id.to_s,
'locked' => is_locked
)
end
@@ -216,7 +220,7 @@ RSpec.describe 'Query.runner(id)' do
a_hash_including(
'webUrl' => "http://localhost/groups/#{group.full_path}/-/runners/#{active_group_runner.id}",
'node' => {
- 'id' => "gid://gitlab/Ci::Runner/#{active_group_runner.id}"
+ 'id' => active_group_runner.to_global_id.to_s
}
)
]
@@ -227,7 +231,7 @@ RSpec.describe 'Query.runner(id)' do
let(:query) do
%(
query {
- runner(id: "gid://gitlab/Ci::Runner/#{active_group_runner.id}") {
+ runner(id: "#{active_group_runner.to_global_id}") {
groups {
nodes {
id
@@ -302,21 +306,36 @@ RSpec.describe 'Query.runner(id)' do
let!(:job) { create(:ci_build, runner: project_runner1) }
- context 'requesting project and job counts' do
+ context 'requesting projects and counts for projects and jobs' do
let(:query) do
%(
query {
projectRunner1: runner(id: "#{project_runner1.to_global_id}") {
projectCount
jobCount
+ projects {
+ nodes {
+ id
+ }
+ }
}
projectRunner2: runner(id: "#{project_runner2.to_global_id}") {
projectCount
jobCount
+ projects {
+ nodes {
+ id
+ }
+ }
}
activeInstanceRunner: runner(id: "#{active_instance_runner.to_global_id}") {
projectCount
jobCount
+ projects {
+ nodes {
+ id
+ }
+ }
}
}
)
@@ -335,13 +354,23 @@ RSpec.describe 'Query.runner(id)' do
expect(runner1_data).to match a_hash_including(
'jobCount' => 1,
- 'projectCount' => 2)
+ 'projectCount' => 2,
+ 'projects' => {
+ 'nodes' => [
+ { 'id' => project1.to_global_id.to_s },
+ { 'id' => project2.to_global_id.to_s }
+ ]
+ })
expect(runner2_data).to match a_hash_including(
'jobCount' => 0,
- 'projectCount' => 0)
+ 'projectCount' => 0,
+ 'projects' => {
+ 'nodes' => []
+ })
expect(runner3_data).to match a_hash_including(
'jobCount' => 0,
- 'projectCount' => nil)
+ 'projectCount' => nil,
+ 'projects' => nil)
end
end
end
@@ -356,6 +385,10 @@ RSpec.describe 'Query.runner(id)' do
context 'on group runner' do
it_behaves_like 'retrieval by unauthorized user', :active_group_runner
end
+
+ context 'on project runner' do
+ it_behaves_like 'retrieval by unauthorized user', :active_project_runner
+ end
end
describe 'by non-admin user' do
diff --git a/spec/requests/api/issues/issues_spec.rb b/spec/requests/api/issues/issues_spec.rb
index 9204ee4d7f0..e15f847d866 100644
--- a/spec/requests/api/issues/issues_spec.rb
+++ b/spec/requests/api/issues/issues_spec.rb
@@ -488,6 +488,8 @@ RSpec.describe API::Issues do
let_it_be(:issue3) { create(:issue, project: project, author: user, due_date: frozen_time + 10.days) }
let_it_be(:issue4) { create(:issue, project: project, author: user, due_date: frozen_time + 34.days) }
let_it_be(:issue5) { create(:issue, project: project, author: user, due_date: frozen_time - 8.days) }
+ let_it_be(:issue6) { create(:issue, project: project, author: user, due_date: frozen_time) }
+ let_it_be(:issue7) { create(:issue, project: project, author: user, due_date: frozen_time + 1.day) }
before do
travel_to(frozen_time)
@@ -500,7 +502,13 @@ RSpec.describe API::Issues do
it 'returns them all when argument is empty' do
get api('/issues?due_date=', user)
- expect_paginated_array_response(issue5.id, issue4.id, issue3.id, issue2.id, issue.id, closed_issue.id)
+ expect_paginated_array_response(issue7.id, issue6.id, issue5.id, issue4.id, issue3.id, issue2.id, issue.id, closed_issue.id)
+ end
+
+ it 'returns issues with due date' do
+ get api('/issues?due_date=any', user)
+
+ expect_paginated_array_response(issue7.id, issue6.id, issue5.id, issue4.id, issue3.id, issue2.id)
end
it 'returns issues without due date' do
@@ -512,19 +520,31 @@ RSpec.describe API::Issues do
it 'returns issues due for this week' do
get api('/issues?due_date=week', user)
- expect_paginated_array_response(issue2.id)
+ expect_paginated_array_response(issue7.id, issue6.id, issue2.id)
end
it 'returns issues due for this month' do
get api('/issues?due_date=month', user)
- expect_paginated_array_response(issue3.id, issue2.id)
+ expect_paginated_array_response(issue7.id, issue6.id, issue3.id, issue2.id)
end
it 'returns issues that are due previous two weeks and next month' do
get api('/issues?due_date=next_month_and_previous_two_weeks', user)
- expect_paginated_array_response(issue5.id, issue4.id, issue3.id, issue2.id)
+ expect_paginated_array_response(issue7.id, issue6.id, issue5.id, issue4.id, issue3.id, issue2.id)
+ end
+
+ it 'returns issues that are due today' do
+ get api('/issues?due_date=today', user)
+
+ expect_paginated_array_response(issue6.id)
+ end
+
+ it 'returns issues that are due tomorrow' do
+ get api('/issues?due_date=tomorrow', user)
+
+ expect_paginated_array_response(issue7.id)
end
it 'returns issues that are overdue' do
diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb
index 4e8e41ca6e6..0f24883bd7b 100644
--- a/spec/services/ci/retry_build_service_spec.rb
+++ b/spec/services/ci/retry_build_service_spec.rb
@@ -370,23 +370,6 @@ RSpec.describe Ci::RetryBuildService do
it_behaves_like 'when build with deployment is retried'
it_behaves_like 'when build with dynamic environment is retried'
- context 'when create_deployment_in_separate_transaction feature flag is disabled' do
- let(:new_build) do
- travel_to(1.second.from_now) do
- ::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.allow_cross_database_modification_within_transaction(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/345668') do
- service.clone!(build)
- end
- end
- end
-
- before do
- stub_feature_flags(create_deployment_in_separate_transaction: false)
- end
-
- it_behaves_like 'when build with deployment is retried'
- it_behaves_like 'when build with dynamic environment is retried'
- end
-
context 'when build has needs' do
before do
create(:ci_build_need, build: build, name: 'build1')
diff --git a/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb b/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb
index 87bf134eeb8..4713e2fc789 100644
--- a/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb
@@ -167,7 +167,7 @@ RSpec.shared_examples 'a container registry auth service' do
stub_feature_flags(container_registry_cdn_redirect: false)
end
- describe '#full_access_token' do
+ describe '.full_access_token' do
let_it_be(:project) { create(:project) }
let(:token) { described_class.full_access_token(project.full_path) }
@@ -181,7 +181,21 @@ RSpec.shared_examples 'a container registry auth service' do
it_behaves_like 'not a container repository factory'
end
- describe '#pull_access_token' do
+ describe '.import_access_token' do
+ let_it_be(:project) { create(:project) }
+
+ let(:token) { described_class.import_access_token(project.full_path) }
+
+ subject { { token: token } }
+
+ it_behaves_like 'an accessible' do
+ let(:actions) { ['import'] }
+ end
+
+ it_behaves_like 'not a container repository factory'
+ end
+
+ describe '.pull_access_token' do
let_it_be(:project) { create(:project) }
let(:token) { described_class.pull_access_token(project.full_path) }
@@ -1126,4 +1140,72 @@ RSpec.shared_examples 'a container registry auth service' do
end
end
end
+
+ context 'when importing' do
+ let_it_be(:container_repository) { create(:container_repository, :root, migration_state: 'importing') }
+ let_it_be(:current_project) { container_repository.project }
+ let_it_be(:current_user) { create(:user) }
+
+ before do
+ current_project.add_developer(current_user)
+ end
+
+ shared_examples 'containing the import error' do
+ it 'includes a helpful error message' do
+ expect(subject[:errors].first).to include(message: /Your repository is currently being migrated/)
+ end
+ end
+
+ context 'push request' do
+ let(:current_params) do
+ { scopes: ["repository:#{container_repository.path}:push"] }
+ end
+
+ it_behaves_like 'a forbidden' do
+ it_behaves_like 'containing the import error'
+ end
+ end
+
+ context 'delete request' do
+ let(:current_params) do
+ { scopes: ["repository:#{container_repository.path}:delete"] }
+ end
+
+ it_behaves_like 'a forbidden' do
+ it_behaves_like 'containing the import error'
+ end
+ end
+
+ context '* request' do
+ let(:current_params) do
+ { scopes: ["repository:#{container_repository.path}:*"] }
+ end
+
+ it_behaves_like 'a forbidden' do
+ it_behaves_like 'containing the import error'
+ end
+ end
+
+ context 'pull request' do
+ let(:current_params) do
+ { scopes: ["repository:#{container_repository.path}:pull"] }
+ end
+
+ let(:project) { current_project }
+
+ it_behaves_like 'a pullable'
+ end
+
+ context 'mixed request' do
+ let(:current_params) do
+ { scopes: ["repository:#{container_repository.path}:pull,push"] }
+ end
+
+ let(:project) { current_project }
+
+ it_behaves_like 'a forbidden' do
+ it_behaves_like 'containing the import error'
+ end
+ end
+ end
end
diff --git a/spec/uploaders/import_export_uploader_spec.rb b/spec/uploaders/import_export_uploader_spec.rb
index cb7a89193e6..64e92f5d60e 100644
--- a/spec/uploaders/import_export_uploader_spec.rb
+++ b/spec/uploaders/import_export_uploader_spec.rb
@@ -10,6 +10,20 @@ RSpec.describe ImportExportUploader do
subject { described_class.new(model, :import_file) }
context 'local store' do
+ describe '#move_to_cache' do
+ it 'returns false' do
+ expect(subject.move_to_cache).to be false
+ end
+
+ context 'with project export' do
+ subject { described_class.new(model, :export_file) }
+
+ it 'returns true' do
+ expect(subject.move_to_cache).to be true
+ end
+ end
+ end
+
describe '#move_to_store' do
it 'returns true' do
expect(subject.move_to_store).to be true
@@ -33,6 +47,20 @@ RSpec.describe ImportExportUploader do
let(:fixture) { File.join('spec', 'fixtures', 'group_export.tar.gz') }
end
+ describe '#move_to_cache' do
+ it 'returns false' do
+ expect(subject.move_to_cache).to be false
+ end
+
+ context 'with project export' do
+ subject { described_class.new(model, :export_file) }
+
+ it 'returns true' do
+ expect(subject.move_to_cache).to be false
+ end
+ end
+ end
+
describe '#move_to_store' do
it 'returns false' do
expect(subject.move_to_store).to be false
diff --git a/spec/workers/concerns/application_worker_spec.rb b/spec/workers/concerns/application_worker_spec.rb
index 85731de2a45..95d9b982fc4 100644
--- a/spec/workers/concerns/application_worker_spec.rb
+++ b/spec/workers/concerns/application_worker_spec.rb
@@ -247,45 +247,6 @@ RSpec.describe ApplicationWorker do
end
end
- describe '.perform_async' do
- using RSpec::Parameterized::TableSyntax
-
- where(:primary_only?, :skip_scheduling_ff, :data_consistency, :schedules_job?) do
- true | false | :sticky | false
- true | false | :delayed | false
- true | false | :always | false
- true | true | :sticky | false
- true | true | :delayed | false
- true | true | :always | false
- false | false | :sticky | true
- false | false | :delayed | true
- false | false | :always | false
- false | true | :sticky | false
- false | true | :delayed | false
- false | true | :always | false
- end
-
- before do
- stub_const(worker.name, worker)
- worker.data_consistency(data_consistency)
-
- allow(Gitlab::Database::LoadBalancing).to receive(:primary_only?).and_return(primary_only?)
- stub_feature_flags(skip_scheduling_workers_for_replicas: skip_scheduling_ff)
- end
-
- with_them do
- it 'schedules or enqueues the job correctly' do
- if schedules_job?
- expect(worker).to receive(:perform_in).with(described_class::DEFAULT_DELAY_INTERVAL.seconds, 123)
- else
- expect(worker).not_to receive(:perform_in)
- end
-
- worker.perform_async(123)
- end
- end
- end
-
context 'different kinds of push_bulk' do
shared_context 'set safe limit beyond the number of jobs to be enqueued' do
before do