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>2022-07-05 18:08:48 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-07-05 18:08:48 +0300
commit205b6baf2677879c35968d2b659225b58e8a1227 (patch)
tree10ed06185aae2f6ed6e7c61349a92acab605daca /spec
parentf34077e88198da754b4efecd1ce1d996ce982286 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/db/schema_spec.rb10
-rw-r--r--spec/factories/clusters/applications/helm.rb4
-rw-r--r--spec/factories/clusters/clusters.rb1
-rw-r--r--spec/factories/clusters/integrations/elastic_stack.rb12
-rw-r--r--spec/factories/import_states.rb4
-rw-r--r--spec/factories/projects.rb4
-rw-r--r--spec/finders/groups/user_groups_finder_spec.rb30
-rw-r--r--spec/frontend/fixtures/jobs.rb32
-rw-r--r--spec/frontend/jobs/components/table/cells/actions_cell_spec.js41
-rw-r--r--spec/frontend/jobs/components/table/cells/job_cell_spec.js33
-rw-r--r--spec/frontend/jobs/components/table/job_table_app_spec.js17
-rw-r--r--spec/frontend/jobs/components/table/jobs_table_spec.js10
-rw-r--r--spec/frontend/jobs/mock_data.js411
-rw-r--r--spec/graphql/resolvers/users/groups_resolver_spec.rb19
-rw-r--r--spec/helpers/environments_helper_spec.rb1
-rw-r--r--spec/models/clusters/applications/elastic_stack_spec.rb177
-rw-r--r--spec/models/clusters/cluster_spec.rb17
-rw-r--r--spec/models/clusters/integrations/elastic_stack_spec.rb19
-rw-r--r--spec/models/environment_spec.rb19
-rw-r--r--spec/models/project_import_state_spec.rb41
-rw-r--r--spec/requests/api/graphql/current_user/groups_query_spec.rb34
-rw-r--r--spec/requests/api/project_import_spec.rb10
-rw-r--r--spec/services/clusters/applications/create_service_spec.rb23
-rw-r--r--spec/services/clusters/integrations/create_service_spec.rb1
-rw-r--r--spec/workers/concerns/gitlab/github_import/object_importer_spec.rb22
-rw-r--r--spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb32
-rw-r--r--spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb3
-rw-r--r--spec/workers/gitlab/github_import/import_issue_event_worker_spec.rb4
-rw-r--r--spec/workers/gitlab/github_import/import_issue_worker_spec.rb3
-rw-r--r--spec/workers/gitlab/github_import/import_note_worker_spec.rb3
-rw-r--r--spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb3
31 files changed, 306 insertions, 734 deletions
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index 8070e17b7af..bd13f86034a 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -114,11 +114,17 @@ RSpec.describe 'Database schema' do
context 'all foreign keys' do
# for index to be effective, the FK constraint has to be at first place
it 'are indexed' do
- first_indexed_column = indexes.map(&:columns).map do |columns|
+ first_indexed_column = indexes.filter_map do |index|
+ columns = index.columns
+
# In cases of complex composite indexes, a string is returned eg:
# "lower((extern_uid)::text), group_id"
columns = columns.split(',') if columns.is_a?(String)
- columns.first.chomp
+ column = columns.first.chomp
+
+ # A partial index is not suitable for a foreign key column, unless
+ # the only condition is for the presence of the foreign key itself
+ column if index.where.nil? || index.where == "(#{column} IS NOT NULL)"
end
foreign_keys_columns = all_foreign_keys.map(&:column)
required_indexed_columns = foreign_keys_columns - ignored_index_columns(table)
diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb
index 919b45e57e2..6a21df943f5 100644
--- a/spec/factories/clusters/applications/helm.rb
+++ b/spec/factories/clusters/applications/helm.rb
@@ -103,10 +103,6 @@ FactoryBot.define do
cluster factory: %i(cluster with_installed_helm provided_by_gcp)
end
- factory :clusters_applications_elastic_stack, class: 'Clusters::Applications::ElasticStack' do
- cluster factory: %i(cluster with_installed_helm provided_by_gcp)
- end
-
factory :clusters_applications_crossplane, class: 'Clusters::Applications::Crossplane' do
stack { 'gcp' }
cluster factory: %i(cluster with_installed_helm provided_by_gcp)
diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb
index 7666533691e..72424a3c321 100644
--- a/spec/factories/clusters/clusters.rb
+++ b/spec/factories/clusters/clusters.rb
@@ -100,7 +100,6 @@ FactoryBot.define do
application_runner factory: %i(clusters_applications_runner installed)
application_jupyter factory: %i(clusters_applications_jupyter installed)
application_knative factory: %i(clusters_applications_knative installed)
- application_elastic_stack factory: %i(clusters_applications_elastic_stack installed)
application_cilium factory: %i(clusters_applications_cilium installed)
end
diff --git a/spec/factories/clusters/integrations/elastic_stack.rb b/spec/factories/clusters/integrations/elastic_stack.rb
deleted file mode 100644
index 1ab3256845b..00000000000
--- a/spec/factories/clusters/integrations/elastic_stack.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :clusters_integrations_elastic_stack, class: 'Clusters::Integrations::ElasticStack' do
- cluster factory: %i(cluster provided_by_gcp)
- enabled { true }
-
- trait :disabled do
- enabled { false }
- end
- end
-end
diff --git a/spec/factories/import_states.rb b/spec/factories/import_states.rb
index 4dca78b1059..0c73082be57 100644
--- a/spec/factories/import_states.rb
+++ b/spec/factories/import_states.rb
@@ -34,6 +34,10 @@ FactoryBot.define do
status { :failed }
end
+ trait :canceled do
+ status { :canceled }
+ end
+
after(:create) do |import_state, evaluator|
columns = {}
columns[:import_url] = evaluator.import_url unless evaluator.import_url.blank?
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 2ed71975d0c..76fa0c4c047 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -151,6 +151,10 @@ FactoryBot.define do
import_status { :failed }
end
+ trait :import_canceled do
+ import_status { :canceled }
+ end
+
trait :jira_dvcs_cloud do
before(:create) do |project|
create(:project_feature_usage, :dvcs_cloud, project: project)
diff --git a/spec/finders/groups/user_groups_finder_spec.rb b/spec/finders/groups/user_groups_finder_spec.rb
index a4a9b8d16d0..9339741da79 100644
--- a/spec/finders/groups/user_groups_finder_spec.rb
+++ b/spec/finders/groups/user_groups_finder_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe Groups::UserGroupsFinder do
let_it_be(:private_maintainer_group) { create(:group, :private, name: 'b private maintainer', path: 'b-private-maintainer') }
let_it_be(:public_developer_group) { create(:group, project_creation_level: nil, name: 'c public developer', path: 'c-public-developer') }
let_it_be(:public_maintainer_group) { create(:group, name: 'a public maintainer', path: 'a-public-maintainer') }
+ let_it_be(:public_owner_group) { create(:group, name: 'a public owner', path: 'a-public-owner') }
subject { described_class.new(current_user, target_user, arguments).execute }
@@ -21,12 +22,14 @@ RSpec.describe Groups::UserGroupsFinder do
private_maintainer_group.add_maintainer(user)
public_developer_group.add_developer(user)
public_maintainer_group.add_maintainer(user)
+ public_owner_group.add_owner(user)
end
it 'returns all groups where the user is a direct member' do
is_expected.to match(
[
public_maintainer_group,
+ public_owner_group,
private_maintainer_group,
public_developer_group,
guest_group
@@ -53,6 +56,7 @@ RSpec.describe Groups::UserGroupsFinder do
is_expected.to match(
[
public_maintainer_group,
+ public_owner_group,
private_maintainer_group,
public_developer_group
]
@@ -73,6 +77,32 @@ RSpec.describe Groups::UserGroupsFinder do
end
end
+ context 'when permission is :transfer_projects' do
+ let(:arguments) { { permission_scope: :transfer_projects } }
+
+ specify do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ public_owner_group,
+ private_maintainer_group
+ ]
+ )
+ end
+
+ context 'when search is provided' do
+ let(:arguments) { { permission_scope: :transfer_projects, search: 'owner' } }
+
+ specify do
+ is_expected.to match(
+ [
+ public_owner_group
+ ]
+ )
+ end
+ end
+ end
+
context 'when search is provided' do
let(:arguments) { { search: 'maintainer' } }
diff --git a/spec/frontend/fixtures/jobs.rb b/spec/frontend/fixtures/jobs.rb
index c76b06bd39e..2e15eefdce6 100644
--- a/spec/frontend/fixtures/jobs.rb
+++ b/spec/frontend/fixtures/jobs.rb
@@ -35,13 +35,21 @@ RSpec.describe 'Jobs (JavaScript fixtures)' do
end
describe GraphQL::Query, type: :request do
+ let(:artifact) { create(:ci_job_artifact, file_type: :archive, file_format: :zip) }
+
let!(:build) { create(:ci_build, :success, name: 'build', pipeline: pipeline) }
+ let!(:cancelable) { create(:ci_build, :cancelable, name: 'cancelable', pipeline: pipeline) }
let!(:created_by_tag) { create(:ci_build, :success, name: 'created_by_tag', tag: true, pipeline: pipeline) }
+ let!(:pending) { create(:ci_build, :pending, name: 'pending', pipeline: pipeline) }
+ let!(:playable) { create(:ci_build, :playable, name: 'playable', pipeline: pipeline) }
+ let!(:retryable) { create(:ci_build, :retryable, name: 'retryable', pipeline: pipeline) }
+ let!(:scheduled) { create(:ci_build, :scheduled, name: 'scheduled', pipeline: pipeline) }
+ let!(:with_artifact) { create(:ci_build, :success, name: 'with_artifact', job_artifacts: [artifact], pipeline: pipeline) }
let!(:with_coverage) { create(:ci_build, :success, name: 'with_coverage', coverage: 40.0, pipeline: pipeline) }
- let!(:stuck) { create(:ci_build, :pending, name: 'stuck', pipeline: pipeline) }
fixtures_path = 'graphql/jobs/'
get_jobs_query = 'get_jobs.query.graphql'
+ full_path = 'frontend-fixtures/builds-project'
let_it_be(:query) do
get_graphql_query_as_string("jobs/components/table/graphql/queries/#{get_jobs_query}")
@@ -49,7 +57,7 @@ RSpec.describe 'Jobs (JavaScript fixtures)' do
it "#{fixtures_path}#{get_jobs_query}.json" do
post_graphql(query, current_user: user, variables: {
- fullPath: 'frontend-fixtures/builds-project'
+ fullPath: full_path
})
expect_graphql_errors_to_be_empty
@@ -60,7 +68,25 @@ RSpec.describe 'Jobs (JavaScript fixtures)' do
project.add_guest(guest)
post_graphql(query, current_user: guest, variables: {
- fullPath: 'frontend-fixtures/builds-project'
+ fullPath: full_path
+ })
+
+ expect_graphql_errors_to_be_empty
+ end
+
+ it "#{fixtures_path}#{get_jobs_query}.paginated.json" do
+ post_graphql(query, current_user: user, variables: {
+ fullPath: full_path,
+ first: 2
+ })
+
+ expect_graphql_errors_to_be_empty
+ end
+
+ it "#{fixtures_path}#{get_jobs_query}.empty.json" do
+ post_graphql(query, current_user: user, variables: {
+ fullPath: full_path,
+ first: 0
})
expect_graphql_errors_to_be_empty
diff --git a/spec/frontend/jobs/components/table/cells/actions_cell_spec.js b/spec/frontend/jobs/components/table/cells/actions_cell_spec.js
index 976b128532d..7cc008f332d 100644
--- a/spec/frontend/jobs/components/table/cells/actions_cell_spec.js
+++ b/spec/frontend/jobs/components/table/cells/actions_cell_spec.js
@@ -12,17 +12,12 @@ import JobRetryMutation from '~/jobs/components/table/graphql/mutations/job_retr
import JobUnscheduleMutation from '~/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql';
import JobCancelMutation from '~/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql';
import {
- playableJob,
- retryableJob,
- cancelableJob,
- scheduledJob,
- cannotRetryJob,
- cannotPlayJob,
- cannotPlayScheduledJob,
- retryMutationResponse,
+ mockJobsNodes,
+ mockJobsNodesAsGuest,
playMutationResponse,
- cancelMutationResponse,
+ retryMutationResponse,
unscheduleMutationResponse,
+ cancelMutationResponse,
} from '../../../mock_data';
jest.mock('~/lib/utils/url_utility');
@@ -32,6 +27,22 @@ Vue.use(VueApollo);
describe('Job actions cell', () => {
let wrapper;
+ const findMockJob = (jobName, nodes = mockJobsNodes) => {
+ const job = nodes.find(({ name }) => name === jobName);
+ expect(job).toBeDefined(); // ensure job is present
+ return job;
+ };
+
+ const mockJob = findMockJob('build');
+ const cancelableJob = findMockJob('cancelable');
+ const playableJob = findMockJob('playable');
+ const retryableJob = findMockJob('retryable');
+ const scheduledJob = findMockJob('scheduled');
+ const jobWithArtifact = findMockJob('with_artifact');
+ const cannotPlayJob = findMockJob('playable', mockJobsNodesAsGuest);
+ const cannotRetryJob = findMockJob('retryable', mockJobsNodesAsGuest);
+ const cannotPlayScheduledJob = findMockJob('scheduled', mockJobsNodesAsGuest);
+
const findRetryButton = () => wrapper.findByTestId('retry');
const findPlayButton = () => wrapper.findByTestId('play');
const findCancelButton = () => wrapper.findByTestId('cancel-button');
@@ -55,10 +66,10 @@ describe('Job actions cell', () => {
return createMockApollo(requestHandlers);
};
- const createComponent = (jobType, requestHandlers, props = {}) => {
+ const createComponent = (job, requestHandlers, props = {}) => {
wrapper = shallowMountExtended(ActionsCell, {
propsData: {
- job: jobType,
+ job,
...props,
},
apolloProvider: createMockApolloProvider(requestHandlers),
@@ -73,15 +84,15 @@ describe('Job actions cell', () => {
});
it('displays the artifacts download button with correct link', () => {
- createComponent(playableJob);
+ createComponent(jobWithArtifact);
expect(findDownloadArtifactsButton().attributes('href')).toBe(
- playableJob.artifacts.nodes[0].downloadPath,
+ jobWithArtifact.artifacts.nodes[0].downloadPath,
);
});
it('does not display an artifacts download button', () => {
- createComponent(retryableJob);
+ createComponent(mockJob);
expect(findDownloadArtifactsButton().exists()).toBe(false);
});
@@ -101,7 +112,7 @@ describe('Job actions cell', () => {
button | action | jobType
${findPlayButton} | ${'play'} | ${playableJob}
${findRetryButton} | ${'retry'} | ${retryableJob}
- ${findDownloadArtifactsButton} | ${'download artifacts'} | ${playableJob}
+ ${findDownloadArtifactsButton} | ${'download artifacts'} | ${jobWithArtifact}
${findCancelButton} | ${'cancel'} | ${cancelableJob}
`('displays the $action button', ({ button, jobType }) => {
createComponent(jobType);
diff --git a/spec/frontend/jobs/components/table/cells/job_cell_spec.js b/spec/frontend/jobs/components/table/cells/job_cell_spec.js
index e3bef17b6fa..ddc196129a7 100644
--- a/spec/frontend/jobs/components/table/cells/job_cell_spec.js
+++ b/spec/frontend/jobs/components/table/cells/job_cell_spec.js
@@ -2,13 +2,22 @@ import { shallowMount } from '@vue/test-utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import JobCell from '~/jobs/components/table/cells/job_cell.vue';
-import { mockJobsInTable, mockJobsAsGuestInTable } from '../../../mock_data';
-
-const getMockJob = (name) => mockJobsInTable.find((job) => job.name === name);
+import { mockJobsNodes, mockJobsNodesAsGuest } from '../../../mock_data';
describe('Job Cell', () => {
let wrapper;
+ const findMockJob = (jobName, nodes = mockJobsNodes) => {
+ const job = nodes.find(({ name }) => name === jobName);
+ expect(job).toBeDefined(); // ensure job is present
+ return job;
+ };
+
+ const mockJob = findMockJob('build');
+ const jobCreatedByTag = findMockJob('created_by_tag');
+ const pendingJob = findMockJob('pending');
+ const jobAsGuest = findMockJob('build', mockJobsNodesAsGuest);
+
const findJobIdLink = () => wrapper.findByTestId('job-id-link');
const findJobIdNoLink = () => wrapper.findByTestId('job-id-limited-access');
const findJobRef = () => wrapper.findByTestId('job-ref');
@@ -20,13 +29,11 @@ describe('Job Cell', () => {
const findBadgeById = (id) => wrapper.findByTestId(id);
- const mockJob = getMockJob('build');
-
- const createComponent = (jobData = mockJob) => {
+ const createComponent = (job = mockJob) => {
wrapper = extendedWrapper(
shallowMount(JobCell, {
propsData: {
- job: jobData,
+ job,
},
}),
);
@@ -48,11 +55,9 @@ describe('Job Cell', () => {
});
it('display the job id with no link', () => {
- const mockJobAsGuest = mockJobsAsGuestInTable[0];
-
- createComponent(mockJobAsGuest);
+ createComponent(jobAsGuest);
- const expectedJobId = `#${getIdFromGraphQLId(mockJobAsGuest.id)}`;
+ const expectedJobId = `#${getIdFromGraphQLId(jobAsGuest.id)}`;
expect(findJobIdNoLink().text()).toBe(expectedJobId);
expect(findJobIdNoLink().exists()).toBe(true);
@@ -76,7 +81,7 @@ describe('Job Cell', () => {
});
it('displays label icon when job is created by a tag', () => {
- createComponent(getMockJob('created_by_tag'));
+ createComponent(jobCreatedByTag);
expect(findLabelIcon().exists()).toBe(true);
expect(findForkIcon().exists()).toBe(false);
@@ -131,8 +136,8 @@ describe('Job Cell', () => {
expect(findStuckIcon().exists()).toBe(false);
});
- it('stuck icon is shown if job is stuck', () => {
- createComponent(getMockJob('stuck'));
+ it('stuck icon is shown if job is pending', () => {
+ createComponent(pendingJob);
expect(findStuckIcon().exists()).toBe(true);
expect(findStuckIcon().attributes('name')).toBe('warning');
diff --git a/spec/frontend/jobs/components/table/job_table_app_spec.js b/spec/frontend/jobs/components/table/job_table_app_spec.js
index 986fba21fb9..963112fbd5e 100644
--- a/spec/frontend/jobs/components/table/job_table_app_spec.js
+++ b/spec/frontend/jobs/components/table/job_table_app_spec.js
@@ -18,8 +18,8 @@ import JobsTableApp from '~/jobs/components/table/jobs_table_app.vue';
import JobsTableTabs from '~/jobs/components/table/jobs_table_tabs.vue';
import JobsFilteredSearch from '~/jobs/components/filtered_search/jobs_filtered_search.vue';
import {
- mockJobsQueryResponse,
- mockJobsQueryEmptyResponse,
+ mockJobsResponsePaginated,
+ mockJobsResponseEmpty,
mockFailedSearchToken,
} from '../../mock_data';
@@ -32,9 +32,9 @@ describe('Job table app', () => {
let wrapper;
let jobsTableVueSearch = true;
- const successHandler = jest.fn().mockResolvedValue(mockJobsQueryResponse);
+ const successHandler = jest.fn().mockResolvedValue(mockJobsResponsePaginated);
const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
- const emptyHandler = jest.fn().mockResolvedValue(mockJobsQueryEmptyResponse);
+ const emptyHandler = jest.fn().mockResolvedValue(mockJobsResponseEmpty);
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
@@ -128,15 +128,18 @@ describe('Job table app', () => {
});
it('handles infinite scrolling by calling fetch more', async () => {
+ const pageSize = 30;
+
expect(findLoadingSpinner().exists()).toBe(true);
await waitForPromises();
expect(findLoadingSpinner().exists()).toBe(false);
- expect(successHandler).toHaveBeenCalledWith({
- after: 'eyJpZCI6IjIzMTcifQ',
- fullPath: 'gitlab-org/gitlab',
+ expect(successHandler).toHaveBeenLastCalledWith({
+ first: pageSize,
+ fullPath: projectPath,
+ after: mockJobsResponsePaginated.data.project.jobs.pageInfo.endCursor,
});
});
});
diff --git a/spec/frontend/jobs/components/table/jobs_table_spec.js b/spec/frontend/jobs/components/table/jobs_table_spec.js
index ac8bef675f8..803df3df37f 100644
--- a/spec/frontend/jobs/components/table/jobs_table_spec.js
+++ b/spec/frontend/jobs/components/table/jobs_table_spec.js
@@ -3,7 +3,7 @@ import { mount } from '@vue/test-utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import JobsTable from '~/jobs/components/table/jobs_table.vue';
import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
-import { mockJobsInTable } from '../../mock_data';
+import { mockJobsNodes } from '../../mock_data';
describe('Jobs Table', () => {
let wrapper;
@@ -19,7 +19,7 @@ describe('Jobs Table', () => {
wrapper = extendedWrapper(
mount(JobsTable, {
propsData: {
- jobs: mockJobsInTable,
+ jobs: mockJobsNodes,
...props,
},
}),
@@ -39,7 +39,7 @@ describe('Jobs Table', () => {
});
it('displays correct number of job rows', () => {
- expect(findTableRows()).toHaveLength(mockJobsInTable.length);
+ expect(findTableRows()).toHaveLength(mockJobsNodes.length);
});
it('displays job status', () => {
@@ -47,14 +47,14 @@ describe('Jobs Table', () => {
});
it('displays the job stage and name', () => {
- const firstJob = mockJobsInTable[0];
+ const firstJob = mockJobsNodes[0];
expect(findJobStage().text()).toBe(firstJob.stage.name);
expect(findJobName().text()).toBe(firstJob.name);
});
it('displays the coverage for only jobs that have coverage', () => {
- const jobsThatHaveCoverage = mockJobsInTable.filter((job) => job.coverage !== null);
+ const jobsThatHaveCoverage = mockJobsNodes.filter((job) => job.coverage !== null);
jobsThatHaveCoverage.forEach((job, index) => {
expect(findAllCoverageJobs().at(index).text()).toBe(`${job.coverage}%`);
diff --git a/spec/frontend/jobs/mock_data.js b/spec/frontend/jobs/mock_data.js
index cc5fd92615a..4d7ea6a46bd 100644
--- a/spec/frontend/jobs/mock_data.js
+++ b/spec/frontend/jobs/mock_data.js
@@ -1,3 +1,5 @@
+import mockJobsEmpty from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.empty.json';
+import mockJobsPaginated from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.paginated.json';
import mockJobs from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.json';
import mockJobsAsGuest from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.as_guest.json';
import { TEST_HOST } from 'spec/test_constants';
@@ -6,8 +8,10 @@ const threeWeeksAgo = new Date();
threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
// Fixtures generated at spec/frontend/fixtures/jobs.rb
-export const mockJobsInTable = mockJobs.data.project.jobs.nodes;
-export const mockJobsAsGuestInTable = mockJobsAsGuest.data.project.jobs.nodes;
+export const mockJobsResponsePaginated = mockJobsPaginated;
+export const mockJobsResponseEmpty = mockJobsEmpty;
+export const mockJobsNodes = mockJobs.data.project.jobs.nodes;
+export const mockJobsNodesAsGuest = mockJobsAsGuest.data.project.jobs.nodes;
export const stages = [
{
@@ -1289,409 +1293,6 @@ export const mockPipelineDetached = {
},
};
-export const mockJobsQueryResponse = {
- data: {
- project: {
- id: '1',
- jobs: {
- count: 1,
- pageInfo: {
- endCursor: 'eyJpZCI6IjIzMTcifQ',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'eyJpZCI6IjIzMzYifQ',
- __typename: 'PageInfo',
- },
- nodes: [
- {
- artifacts: {
- nodes: [
- {
- downloadPath: '/root/ci-project/-/jobs/2336/artifacts/download?file_type=trace',
- fileType: 'TRACE',
- __typename: 'CiJobArtifact',
- },
- {
- downloadPath:
- '/root/ci-project/-/jobs/2336/artifacts/download?file_type=metadata',
- fileType: 'METADATA',
- __typename: 'CiJobArtifact',
- },
- {
- downloadPath: '/root/ci-project/-/jobs/2336/artifacts/download?file_type=archive',
- fileType: 'ARCHIVE',
- __typename: 'CiJobArtifact',
- },
- ],
- __typename: 'CiJobArtifactConnection',
- },
- allowFailure: false,
- status: 'SUCCESS',
- scheduledAt: null,
- manualJob: false,
- triggered: null,
- createdByTag: false,
- detailedStatus: {
- id: 'status-1',
- detailsPath: '/root/ci-project/-/jobs/2336',
- group: 'success',
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- action: {
- id: 'action-1',
- buttonTitle: 'Retry this job',
- icon: 'retry',
- method: 'post',
- path: '/root/ci-project/-/jobs/2336/retry',
- title: 'Retry',
- __typename: 'StatusAction',
- },
- __typename: 'DetailedStatus',
- },
- id: 'gid://gitlab/Ci::Build/2336',
- refName: 'main',
- refPath: '/root/ci-project/-/commits/main',
- tags: [],
- shortSha: '4408fa2a',
- commitPath: '/root/ci-project/-/commit/4408fa2a27aaadfdf42d8dda3d6a9c01ce6cad78',
- pipeline: {
- id: 'gid://gitlab/Ci::Pipeline/473',
- path: '/root/ci-project/-/pipelines/473',
- user: {
- id: 'user-1',
- webPath: '/root',
- avatarUrl:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- __typename: 'UserCore',
- },
- __typename: 'Pipeline',
- },
- stage: {
- id: 'stage-1',
- name: 'deploy',
- __typename: 'CiStage',
- },
- name: 'artifact_job',
- duration: 3,
- finishedAt: '2021-04-29T14:19:50Z',
- coverage: null,
- retryable: true,
- playable: false,
- cancelable: false,
- active: false,
- stuck: false,
- userPermissions: {
- readBuild: true,
- readJobArtifacts: true,
- updateBuild: true,
- __typename: 'JobPermissions',
- },
- __typename: 'CiJob',
- },
- ],
- __typename: 'CiJobConnection',
- },
- __typename: 'Project',
- },
- },
-};
-
-export const mockJobsQueryEmptyResponse = {
- data: {
- project: {
- id: '1',
- jobs: [],
- },
- },
-};
-
-export const retryableJob = {
- artifacts: {
- nodes: [
- {
- downloadPath: '/root/ci-project/-/jobs/847/artifacts/download?file_type=trace',
- fileType: 'TRACE',
- __typename: 'CiJobArtifact',
- },
- ],
- __typename: 'CiJobArtifactConnection',
- },
- allowFailure: false,
- status: 'SUCCESS',
- scheduledAt: null,
- manualJob: false,
- triggered: null,
- createdByTag: false,
- detailedStatus: {
- detailsPath: '/root/test-job-artifacts/-/jobs/1981',
- group: 'success',
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- action: {
- buttonTitle: 'Retry this job',
- icon: 'retry',
- method: 'post',
- path: '/root/test-job-artifacts/-/jobs/1981/retry',
- title: 'Retry',
- __typename: 'StatusAction',
- },
- __typename: 'DetailedStatus',
- },
- id: 'gid://gitlab/Ci::Build/1981',
- refName: 'main',
- refPath: '/root/test-job-artifacts/-/commits/main',
- tags: [],
- shortSha: '75daf01b',
- commitPath: '/root/test-job-artifacts/-/commit/75daf01b465e7eab5a04a315e44660c9a17c8055',
- pipeline: {
- id: 'gid://gitlab/Ci::Pipeline/288',
- path: '/root/test-job-artifacts/-/pipelines/288',
- user: {
- webPath: '/root',
- avatarUrl:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- __typename: 'UserCore',
- },
- __typename: 'Pipeline',
- },
- stage: { name: 'test', __typename: 'CiStage' },
- name: 'hello_world',
- duration: 7,
- finishedAt: '2021-08-30T20:33:56Z',
- coverage: null,
- retryable: true,
- playable: false,
- cancelable: false,
- active: false,
- stuck: false,
- userPermissions: { readBuild: true, updateBuild: true, __typename: 'JobPermissions' },
- __typename: 'CiJob',
-};
-
-export const cancelableJob = {
- artifacts: {
- nodes: [],
- __typename: 'CiJobArtifactConnection',
- },
- allowFailure: false,
- status: 'PENDING',
- scheduledAt: null,
- manualJob: false,
- triggered: null,
- createdByTag: false,
- detailedStatus: {
- id: 'pending-1305-1305',
- detailsPath: '/root/lots-of-jobs-project/-/jobs/1305',
- group: 'pending',
- icon: 'status_pending',
- label: 'pending',
- text: 'pending',
- tooltip: 'pending',
- action: {
- id: 'Ci::Build-pending-1305',
- buttonTitle: 'Cancel this job',
- icon: 'cancel',
- method: 'post',
- path: '/root/lots-of-jobs-project/-/jobs/1305/cancel',
- title: 'Cancel',
- __typename: 'StatusAction',
- },
- __typename: 'DetailedStatus',
- },
- id: 'gid://gitlab/Ci::Build/1305',
- refName: 'main',
- refPath: '/root/lots-of-jobs-project/-/commits/main',
- tags: [],
- shortSha: '750605f2',
- commitPath: '/root/lots-of-jobs-project/-/commit/750605f29530778cf0912779eba6d073128962a5',
- stage: {
- id: 'gid://gitlab/Ci::Stage/181',
- name: 'deploy',
- __typename: 'CiStage',
- },
- name: 'job_212',
- duration: null,
- finishedAt: null,
- coverage: null,
- retryable: false,
- playable: false,
- cancelable: true,
- active: true,
- stuck: false,
- userPermissions: {
- readBuild: true,
- readJobArtifacts: true,
- updateBuild: true,
- __typename: 'JobPermissions',
- },
- __typename: 'CiJob',
-};
-
-export const cannotRetryJob = {
- ...retryableJob,
- userPermissions: { readBuild: true, updateBuild: false, __typename: 'JobPermissions' },
-};
-
-export const playableJob = {
- artifacts: {
- nodes: [
- {
- downloadPath: '/root/ci-project/-/jobs/621/artifacts/download?file_type=archive',
- fileType: 'ARCHIVE',
- __typename: 'CiJobArtifact',
- },
- {
- downloadPath: '/root/ci-project/-/jobs/621/artifacts/download?file_type=metadata',
- fileType: 'METADATA',
- __typename: 'CiJobArtifact',
- },
- {
- downloadPath: '/root/ci-project/-/jobs/621/artifacts/download?file_type=trace',
- fileType: 'TRACE',
- __typename: 'CiJobArtifact',
- },
- ],
- __typename: 'CiJobArtifactConnection',
- },
- allowFailure: false,
- status: 'SUCCESS',
- scheduledAt: null,
- manualJob: true,
- triggered: null,
- createdByTag: false,
- detailedStatus: {
- detailsPath: '/root/test-job-artifacts/-/jobs/1982',
- group: 'success',
- icon: 'status_success',
- label: 'manual play action',
- text: 'passed',
- tooltip: 'passed',
- action: {
- buttonTitle: 'Trigger this manual action',
- icon: 'play',
- method: 'post',
- path: '/root/test-job-artifacts/-/jobs/1982/play',
- title: 'Play',
- __typename: 'StatusAction',
- },
- __typename: 'DetailedStatus',
- },
- id: 'gid://gitlab/Ci::Build/1982',
- refName: 'main',
- refPath: '/root/test-job-artifacts/-/commits/main',
- tags: [],
- shortSha: '75daf01b',
- commitPath: '/root/test-job-artifacts/-/commit/75daf01b465e7eab5a04a315e44660c9a17c8055',
- pipeline: {
- id: 'gid://gitlab/Ci::Pipeline/288',
- path: '/root/test-job-artifacts/-/pipelines/288',
- user: {
- webPath: '/root',
- avatarUrl:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- __typename: 'UserCore',
- },
- __typename: 'Pipeline',
- },
- stage: { name: 'test', __typename: 'CiStage' },
- name: 'hello_world_delayed',
- duration: 6,
- finishedAt: '2021-08-30T20:36:12Z',
- coverage: null,
- retryable: true,
- playable: true,
- cancelable: false,
- active: false,
- stuck: false,
- userPermissions: {
- readBuild: true,
- readJobArtifacts: true,
- updateBuild: true,
- __typename: 'JobPermissions',
- },
- __typename: 'CiJob',
-};
-
-export const cannotPlayJob = {
- ...playableJob,
- userPermissions: {
- readBuild: true,
- readJobArtifacts: true,
- updateBuild: false,
- __typename: 'JobPermissions',
- },
-};
-
-export const scheduledJob = {
- artifacts: { nodes: [], __typename: 'CiJobArtifactConnection' },
- allowFailure: false,
- status: 'SCHEDULED',
- scheduledAt: '2021-08-31T22:36:05Z',
- manualJob: true,
- triggered: null,
- createdByTag: false,
- detailedStatus: {
- detailsPath: '/root/test-job-artifacts/-/jobs/1986',
- group: 'scheduled',
- icon: 'status_scheduled',
- label: 'unschedule action',
- text: 'delayed',
- tooltip: 'delayed manual action (%{remainingTime})',
- action: {
- buttonTitle: 'Unschedule job',
- icon: 'time-out',
- method: 'post',
- path: '/root/test-job-artifacts/-/jobs/1986/unschedule',
- title: 'Unschedule',
- __typename: 'StatusAction',
- },
- __typename: 'DetailedStatus',
- },
- id: 'gid://gitlab/Ci::Build/1986',
- refName: 'main',
- refPath: '/root/test-job-artifacts/-/commits/main',
- tags: [],
- shortSha: '75daf01b',
- commitPath: '/root/test-job-artifacts/-/commit/75daf01b465e7eab5a04a315e44660c9a17c8055',
- pipeline: {
- id: 'gid://gitlab/Ci::Pipeline/290',
- path: '/root/test-job-artifacts/-/pipelines/290',
- user: {
- webPath: '/root',
- avatarUrl:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- __typename: 'UserCore',
- },
- __typename: 'Pipeline',
- },
- stage: { name: 'test', __typename: 'CiStage' },
- name: 'hello_world_delayed',
- duration: null,
- finishedAt: null,
- coverage: null,
- retryable: false,
- playable: true,
- cancelable: false,
- active: false,
- stuck: false,
- userPermissions: { readBuild: true, updateBuild: true, __typename: 'JobPermissions' },
- __typename: 'CiJob',
-};
-
-export const cannotPlayScheduledJob = {
- ...scheduledJob,
- userPermissions: {
- readBuild: true,
- readJobArtifacts: true,
- updateBuild: false,
- __typename: 'JobPermissions',
- },
-};
-
export const CIJobConnectionIncomingCache = {
__typename: 'CiJobConnection',
pageInfo: {
diff --git a/spec/graphql/resolvers/users/groups_resolver_spec.rb b/spec/graphql/resolvers/users/groups_resolver_spec.rb
index bbe9b6371cf..1e0e001fbf7 100644
--- a/spec/graphql/resolvers/users/groups_resolver_spec.rb
+++ b/spec/graphql/resolvers/users/groups_resolver_spec.rb
@@ -12,6 +12,7 @@ RSpec.describe Resolvers::Users::GroupsResolver do
let_it_be(:private_maintainer_group) { create(:group, :private, name: 'b private maintainer', path: 'b-private-maintainer') }
let_it_be(:public_developer_group) { create(:group, project_creation_level: nil, name: 'c public developer', path: 'c-public-developer') }
let_it_be(:public_maintainer_group) { create(:group, name: 'a public maintainer', path: 'a-public-maintainer') }
+ let_it_be(:public_owner_group) { create(:group, name: 'a public owner', path: 'a-public-owner') }
subject(:resolved_items) { resolve_groups(args: group_arguments, current_user: current_user, obj: resolver_object) }
@@ -24,6 +25,7 @@ RSpec.describe Resolvers::Users::GroupsResolver do
private_maintainer_group.add_maintainer(user)
public_developer_group.add_developer(user)
public_maintainer_group.add_maintainer(user)
+ public_owner_group.add_owner(user)
end
context 'when resolver object is current user' do
@@ -34,6 +36,7 @@ RSpec.describe Resolvers::Users::GroupsResolver do
is_expected.to match(
[
public_maintainer_group,
+ public_owner_group,
private_maintainer_group,
public_developer_group
]
@@ -41,10 +44,25 @@ RSpec.describe Resolvers::Users::GroupsResolver do
end
end
+ context 'when permission is :transfer_projects' do
+ let(:group_arguments) { { permission_scope: :transfer_projects } }
+
+ specify do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ public_owner_group,
+ private_maintainer_group
+ ]
+ )
+ end
+ end
+
specify do
is_expected.to match(
[
public_maintainer_group,
+ public_owner_group,
private_maintainer_group,
public_developer_group,
guest_group
@@ -82,6 +100,7 @@ RSpec.describe Resolvers::Users::GroupsResolver do
is_expected.to match(
[
public_maintainer_group,
+ public_owner_group,
private_maintainer_group,
public_developer_group,
guest_group
diff --git a/spec/helpers/environments_helper_spec.rb b/spec/helpers/environments_helper_spec.rb
index e4d4f18ad68..c1eaf1b1bcd 100644
--- a/spec/helpers/environments_helper_spec.rb
+++ b/spec/helpers/environments_helper_spec.rb
@@ -129,7 +129,6 @@ RSpec.describe EnvironmentsHelper do
"environment_name": environment.name,
"environments_path": api_v4_projects_environments_path(id: project.id),
"environment_id": environment.id,
- "cluster_applications_documentation_path" => help_page_path('user/clusters/integrations.md', anchor: 'elastic-stack-cluster-integration'),
"clusters_path": project_clusters_path(project, format: :json)
}
diff --git a/spec/models/clusters/applications/elastic_stack_spec.rb b/spec/models/clusters/applications/elastic_stack_spec.rb
deleted file mode 100644
index af2802d5e47..00000000000
--- a/spec/models/clusters/applications/elastic_stack_spec.rb
+++ /dev/null
@@ -1,177 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::ElasticStack do
- include KubernetesHelpers
-
- include_examples 'cluster application core specs', :clusters_applications_elastic_stack
- include_examples 'cluster application status specs', :clusters_applications_elastic_stack
- include_examples 'cluster application version specs', :clusters_applications_elastic_stack
- include_examples 'cluster application helm specs', :clusters_applications_elastic_stack
-
- describe 'cluster.integration_elastic_stack state synchronization' do
- let!(:application) { create(:clusters_applications_elastic_stack) }
- let(:cluster) { application.cluster }
- let(:integration) { cluster.integration_elastic_stack }
-
- describe 'after_destroy' do
- it 'disables the corresponding integration' do
- application.destroy!
-
- expect(integration).not_to be_enabled
- end
- end
-
- describe 'on install' do
- it 'enables the corresponding integration' do
- application.make_scheduled!
- application.make_installing!
- application.make_installed!
-
- expect(integration).to be_enabled
- end
- end
-
- describe 'on uninstall' do
- it 'disables the corresponding integration' do
- application.make_scheduled!
- application.make_installing!
- application.make_installed!
- application.make_externally_uninstalled!
-
- expect(integration).not_to be_enabled
- end
- end
- end
-
- describe '#install_command' do
- let!(:elastic_stack) { create(:clusters_applications_elastic_stack) }
-
- subject { elastic_stack.install_command }
-
- it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) }
-
- it 'is initialized with elastic stack arguments' do
- expect(subject.name).to eq('elastic-stack')
- expect(subject.chart).to eq('elastic-stack/elastic-stack')
- expect(subject.version).to eq('3.0.0')
- expect(subject.repository).to eq('https://charts.gitlab.io')
- expect(subject).to be_rbac
- expect(subject.files).to eq(elastic_stack.files)
- expect(subject.preinstall).to be_empty
- end
-
- context 'within values.yaml' do
- let(:values_yaml_content) {subject.files[:"values.yaml"]}
-
- it 'contains the disabled index lifecycle management' do
- expect(values_yaml_content).to include "setup.ilm.enabled: false"
- end
-
- it 'contains daily indices with respective template' do
- expect(values_yaml_content).to include "index: \"filebeat-%{[agent.version]}-%{+yyyy.MM.dd}\""
- expect(values_yaml_content).to include "setup.template.name: 'filebeat'"
- expect(values_yaml_content).to include "setup.template.pattern: 'filebeat-*'"
- end
- end
-
- context 'on a non rbac enabled cluster' do
- before do
- elastic_stack.cluster.platform_kubernetes.abac!
- end
-
- it { is_expected.not_to be_rbac }
- end
-
- context 'on versions older than 2' do
- before do
- elastic_stack.status = elastic_stack.status_states[:updating]
- elastic_stack.version = "1.9.0"
- end
-
- it 'includes a preinstall script' do
- expect(subject.preinstall).not_to be_empty
- expect(subject.preinstall.first).to include("helm uninstall")
- end
- end
-
- context 'on versions older than 3' do
- before do
- elastic_stack.status = elastic_stack.status_states[:updating]
- elastic_stack.version = "2.9.0"
- end
-
- it 'includes a preinstall script' do
- expect(subject.preinstall).not_to be_empty
- expect(subject.preinstall.first).to include("helm uninstall")
- end
- end
-
- context 'application failed to install previously' do
- let(:elastic_stack) { create(:clusters_applications_elastic_stack, :errored, version: '0.0.1') }
-
- it 'is initialized with the locked version' do
- expect(subject.version).to eq('3.0.0')
- end
- end
- end
-
- describe '#chart_above_v2?' do
- let(:elastic_stack) { create(:clusters_applications_elastic_stack, version: version) }
-
- subject { elastic_stack.chart_above_v2? }
-
- context 'on v1.9.0' do
- let(:version) { '1.9.0' }
-
- it { is_expected.to be_falsy }
- end
-
- context 'on v2.0.0' do
- let(:version) { '2.0.0' }
-
- it { is_expected.to be_truthy }
- end
- end
-
- describe '#chart_above_v3?' do
- let(:elastic_stack) { create(:clusters_applications_elastic_stack, version: version) }
-
- subject { elastic_stack.chart_above_v3? }
-
- context 'on v1.9.0' do
- let(:version) { '1.9.0' }
-
- it { is_expected.to be_falsy }
- end
-
- context 'on v3.0.0' do
- let(:version) { '3.0.0' }
-
- it { is_expected.to be_truthy }
- end
- end
-
- describe '#uninstall_command' do
- let!(:elastic_stack) { create(:clusters_applications_elastic_stack) }
-
- subject { elastic_stack.uninstall_command }
-
- it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::DeleteCommand) }
-
- it 'is initialized with elastic stack arguments' do
- expect(subject.name).to eq('elastic-stack')
- expect(subject).to be_rbac
- expect(subject.files).to eq(elastic_stack.files)
- end
-
- it 'specifies a post delete command to remove custom resource definitions' do
- expect(subject.postdelete).to eq([
- 'kubectl delete pvc --selector app\\=elastic-stack-elasticsearch-master --namespace gitlab-managed-apps'
- ])
- end
- end
-
- it_behaves_like 'cluster-based #elasticsearch_client', :clusters_applications_elastic_stack
-end
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index 30591a3ff5d..65ead01a2bd 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -42,7 +42,6 @@ RSpec.describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
it { is_expected.to delegate_method(:available?).to(:application_helm).with_prefix }
it { is_expected.to delegate_method(:available?).to(:application_ingress).with_prefix }
it { is_expected.to delegate_method(:available?).to(:application_knative).with_prefix }
- it { is_expected.to delegate_method(:available?).to(:integration_elastic_stack).with_prefix }
it { is_expected.to delegate_method(:available?).to(:integration_prometheus).with_prefix }
it { is_expected.to delegate_method(:external_ip).to(:application_ingress).with_prefix }
it { is_expected.to delegate_method(:external_hostname).to(:application_ingress).with_prefix }
@@ -200,22 +199,6 @@ RSpec.describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
end
end
- describe '.with_available_elasticstack' do
- subject { described_class.with_available_elasticstack }
-
- let_it_be(:cluster) { create(:cluster) }
-
- context 'cluster has ElasticStack application' do
- let!(:application) { create(:clusters_applications_elastic_stack, :installed, cluster: cluster) }
-
- it { is_expected.to include(cluster) }
- end
-
- context 'cluster does not have ElasticStack application' do
- it { is_expected.not_to include(cluster) }
- end
- end
-
describe '.distinct_with_deployed_environments' do
subject { described_class.distinct_with_deployed_environments }
diff --git a/spec/models/clusters/integrations/elastic_stack_spec.rb b/spec/models/clusters/integrations/elastic_stack_spec.rb
deleted file mode 100644
index be4d59b52a2..00000000000
--- a/spec/models/clusters/integrations/elastic_stack_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Integrations::ElasticStack do
- include KubernetesHelpers
- include StubRequests
-
- describe 'associations' do
- it { is_expected.to belong_to(:cluster).class_name('Clusters::Cluster') }
- end
-
- describe 'validations' do
- it { is_expected.to validate_presence_of(:cluster) }
- it { is_expected.not_to allow_value(nil).for(:enabled) }
- end
-
- it_behaves_like 'cluster-based #elasticsearch_client', :clusters_integrations_elastic_stack
-end
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index fd89a3a2e22..92af1c3d571 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -1711,25 +1711,6 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
end
end
- describe '#elastic_stack_available?' do
- let!(:cluster) { create(:cluster, :project, :provided_by_user, projects: [project]) }
- let!(:deployment) { create(:deployment, :success, environment: environment, project: project, cluster: cluster) }
-
- context 'when integration does not exist' do
- it 'returns false' do
- expect(environment.elastic_stack_available?).to be(false)
- end
- end
-
- context 'when integration is enabled' do
- let!(:integration) { create(:clusters_integrations_elastic_stack, cluster: cluster) }
-
- it 'returns true' do
- expect(environment.elastic_stack_available?).to be(true)
- end
- end
- end
-
describe '#destroy' do
it 'remove the deployment refs from gitaly' do
deployment = create(:deployment, :success, environment: environment, project: project)
diff --git a/spec/models/project_import_state_spec.rb b/spec/models/project_import_state_spec.rb
index f6e398bd23c..db79185d759 100644
--- a/spec/models/project_import_state_spec.rb
+++ b/spec/models/project_import_state_spec.rb
@@ -156,7 +156,7 @@ RSpec.describe ProjectImportState, type: :model do
project.import_state.finish
end
- it 'does not qneueue housekeeping when project does not have a valid import type' do
+ it 'does not enqueue housekeeping when project does not have a valid import type' do
project = create(:project, :import_started, import_type: nil)
expect(Projects::AfterImportWorker).not_to receive(:perform_async)
@@ -164,6 +164,43 @@ RSpec.describe ProjectImportState, type: :model do
project.import_state.finish
end
end
+
+ context 'state transition: [:none, :scheduled, :started] => [:canceled]' do
+ it 'updates the import status' do
+ import_state = create(:import_state, :none)
+ expect { import_state.cancel }
+ .to change { import_state.status }
+ .from('none').to('canceled')
+ end
+
+ it 'unsets the JID' do
+ import_state = create(:import_state, :started, jid: '123')
+
+ expect(Gitlab::SidekiqStatus)
+ .to receive(:unset)
+ .with('123')
+ .and_call_original
+
+ import_state.cancel!
+
+ expect(import_state.jid).to be_nil
+ end
+
+ it 'removes import data' do
+ import_data = ProjectImportData.new(data: { 'test' => 'some data' })
+ project = create(:project, :import_scheduled, import_data: import_data)
+
+ expect(project)
+ .to receive(:remove_import_data)
+ .and_call_original
+
+ expect do
+ project.import_state.cancel
+ project.reload
+ end.to change { project.import_data }
+ .from(import_data).to(nil)
+ end
+ end
end
describe 'clearing `jid` after finish', :clean_gitlab_redis_cache do
@@ -178,7 +215,7 @@ RSpec.describe ProjectImportState, type: :model do
end
end
- context 'with an JID' do
+ context 'with a JID' do
it 'unsets the JID' do
import_state = create(:import_state, :started, jid: '123')
diff --git a/spec/requests/api/graphql/current_user/groups_query_spec.rb b/spec/requests/api/graphql/current_user/groups_query_spec.rb
index 39f323b21a3..ef0f32bacf0 100644
--- a/spec/requests/api/graphql/current_user/groups_query_spec.rb
+++ b/spec/requests/api/graphql/current_user/groups_query_spec.rb
@@ -8,8 +8,9 @@ RSpec.describe 'Query current user groups' do
let_it_be(:user) { create(:user) }
let_it_be(:guest_group) { create(:group, name: 'public guest', path: 'public-guest') }
let_it_be(:private_maintainer_group) { create(:group, :private, name: 'b private maintainer', path: 'b-private-maintainer') }
- let_it_be(:public_developer_group) { create(:group, :private, project_creation_level: nil, name: 'c public developer', path: 'c-public-developer') }
- let_it_be(:public_maintainer_group) { create(:group, :private, name: 'a public maintainer', path: 'a-public-maintainer') }
+ let_it_be(:public_developer_group) { create(:group, project_creation_level: nil, name: 'c public developer', path: 'c-public-developer') }
+ let_it_be(:public_maintainer_group) { create(:group, name: 'a public maintainer', path: 'a-public-maintainer') }
+ let_it_be(:public_owner_group) { create(:group, name: 'a public owner', path: 'a-public-owner') }
let(:group_arguments) { {} }
let(:current_user) { user }
@@ -29,6 +30,7 @@ RSpec.describe 'Query current user groups' do
private_maintainer_group.add_maintainer(user)
public_developer_group.add_developer(user)
public_maintainer_group.add_maintainer(user)
+ public_owner_group.add_owner(user)
end
subject { graphql_data.dig('currentUser', 'groups', 'nodes') }
@@ -52,6 +54,7 @@ RSpec.describe 'Query current user groups' do
is_expected.to match(
expected_group_hash(
public_maintainer_group,
+ public_owner_group,
private_maintainer_group,
public_developer_group,
guest_group
@@ -66,6 +69,7 @@ RSpec.describe 'Query current user groups' do
is_expected.to match(
expected_group_hash(
public_maintainer_group,
+ public_owner_group,
private_maintainer_group,
public_developer_group
)
@@ -86,6 +90,32 @@ RSpec.describe 'Query current user groups' do
end
end
+ context 'when permission_scope is TRANSFER_PROJECTS' do
+ let(:group_arguments) { { permission_scope: :TRANSFER_PROJECTS } }
+
+ specify do
+ is_expected.to match(
+ expected_group_hash(
+ public_maintainer_group,
+ public_owner_group,
+ private_maintainer_group
+ )
+ )
+ end
+
+ context 'when search is provided' do
+ let(:group_arguments) { { permission_scope: :TRANSFER_PROJECTS, search: 'owner' } }
+
+ specify do
+ is_expected.to match(
+ expected_group_hash(
+ public_owner_group
+ )
+ )
+ end
+ end
+ end
+
context 'when search is provided' do
let(:group_arguments) { { search: 'maintainer' } }
diff --git a/spec/requests/api/project_import_spec.rb b/spec/requests/api/project_import_spec.rb
index 7e6d80c047c..8655e5b0238 100644
--- a/spec/requests/api/project_import_spec.rb
+++ b/spec/requests/api/project_import_spec.rb
@@ -462,6 +462,16 @@ RSpec.describe API::ProjectImport, :aggregate_failures do
expect(json_response).to include('import_status' => 'failed',
'import_error' => 'error')
end
+
+ it 'returns the import status if canceled' do
+ project = create(:project, :import_canceled)
+ project.add_maintainer(user)
+
+ get api("/projects/#{project.id}/import", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to include('import_status' => 'canceled')
+ end
end
describe 'POST /projects/import/authorize' do
diff --git a/spec/services/clusters/applications/create_service_spec.rb b/spec/services/clusters/applications/create_service_spec.rb
index eb907377ca8..00a67a9b2ef 100644
--- a/spec/services/clusters/applications/create_service_spec.rb
+++ b/spec/services/clusters/applications/create_service_spec.rb
@@ -168,29 +168,6 @@ RSpec.describe Clusters::Applications::CreateService do
subject
end
end
-
- context 'elastic stack application' do
- let(:params) do
- {
- application: 'elastic_stack'
- }
- end
-
- before do
- create(:clusters_applications_ingress, :installed, external_ip: "127.0.0.0", cluster: cluster)
- expect_any_instance_of(Clusters::Applications::ElasticStack)
- .to receive(:make_scheduled!)
- .and_call_original
- end
-
- it 'creates the application' do
- expect do
- subject
-
- cluster.reload
- end.to change(cluster, :application_elastic_stack)
- end
- end
end
context 'invalid application' do
diff --git a/spec/services/clusters/integrations/create_service_spec.rb b/spec/services/clusters/integrations/create_service_spec.rb
index 6dac97ebf8f..016511a3c01 100644
--- a/spec/services/clusters/integrations/create_service_spec.rb
+++ b/spec/services/clusters/integrations/create_service_spec.rb
@@ -61,7 +61,6 @@ RSpec.describe Clusters::Integrations::CreateService, '#execute' do
end
it_behaves_like 'a cluster integration', 'prometheus'
- it_behaves_like 'a cluster integration', 'elastic_stack'
context 'when application_type is invalid' do
let(:params) do
diff --git a/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb b/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
index 3cd82b8bf4d..5a32c1b40bb 100644
--- a/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
@@ -22,6 +22,7 @@ RSpec.describe Gitlab::GithubImport::ObjectImporter, :aggregate_failures do
end
let_it_be(:project) { create(:project, :import_started) }
+ let_it_be(:project2) { create(:project, :import_canceled) }
let(:importer_class) { double(:importer_class, name: 'klass_name') }
let(:importer_instance) { double(:importer_instance) }
@@ -110,6 +111,27 @@ RSpec.describe Gitlab::GithubImport::ObjectImporter, :aggregate_failures do
})
end
+ it 'logs info if the import state is canceled' do
+ expect(project2.import_state.status).to eq('canceled')
+
+ expect(importer_class).not_to receive(:new)
+
+ expect(importer_instance).not_to receive(:execute)
+
+ expect(Gitlab::GithubImport::Logger)
+ .to receive(:info)
+ .with(
+ {
+ github_identifiers: nil,
+ message: 'project import canceled',
+ project_id: project2.id,
+ importer: 'klass_name'
+ }
+ )
+
+ worker.import(project2, client, { 'number' => 11, 'github_id' => 2 } )
+ end
+
it 'logs error when the import fails' do
expect(importer_class)
.to receive(:new)
diff --git a/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb b/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb
index 1e088929f66..0ac1733781a 100644
--- a/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Gitlab::GithubImport::StageMethods do
let_it_be(:project) { create(:project, :import_started, import_url: 'https://t0ken@github.com/repo/repo.git') }
+ let_it_be(:project2) { create(:project, :import_canceled) }
let(:worker) do
Class.new do
@@ -22,6 +23,37 @@ RSpec.describe Gitlab::GithubImport::StageMethods do
worker.perform(-1)
end
+ it 'returns if the import state is canceled' do
+ allow(worker)
+ .to receive(:find_project)
+ .with(project2.id)
+ .and_return(project2)
+
+ expect(worker).not_to receive(:try_import)
+
+ expect(Gitlab::GithubImport::Logger)
+ .to receive(:info)
+ .with(
+ {
+ message: 'starting stage',
+ project_id: project2.id,
+ import_stage: 'DummyStage'
+ }
+ )
+
+ expect(Gitlab::GithubImport::Logger)
+ .to receive(:info)
+ .with(
+ {
+ message: 'project import canceled',
+ project_id: project2.id,
+ import_stage: 'DummyStage'
+ }
+ )
+
+ worker.perform(project2.id)
+ end
+
it 'imports the data when the project exists' do
allow(worker)
.to receive(:find_project)
diff --git a/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb b/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb
index af15f465107..15bc55c1526 100644
--- a/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb
@@ -7,7 +7,8 @@ RSpec.describe Gitlab::GithubImport::ImportDiffNoteWorker do
describe '#import' do
it 'imports a diff note' do
- project = double(:project, full_path: 'foo/bar', id: 1, import_state: nil)
+ import_state = create(:import_state, :started)
+ project = double(:project, full_path: 'foo/bar', id: 1, import_state: import_state)
client = double(:client)
importer = double(:importer)
hash = {
diff --git a/spec/workers/gitlab/github_import/import_issue_event_worker_spec.rb b/spec/workers/gitlab/github_import/import_issue_event_worker_spec.rb
index 6af450151e3..03a6503fb84 100644
--- a/spec/workers/gitlab/github_import/import_issue_event_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_issue_event_worker_spec.rb
@@ -6,8 +6,10 @@ RSpec.describe Gitlab::GithubImport::ImportIssueEventWorker do
subject(:worker) { described_class.new }
describe '#import' do
+ let(:import_state) { create(:import_state, :started) }
+
let(:project) do
- instance_double('Project', full_path: 'foo/bar', id: 1, import_state: nil)
+ instance_double('Project', full_path: 'foo/bar', id: 1, import_state: import_state)
end
let(:client) { instance_double('Gitlab::GithubImport::Client') }
diff --git a/spec/workers/gitlab/github_import/import_issue_worker_spec.rb b/spec/workers/gitlab/github_import/import_issue_worker_spec.rb
index 29f21c1d184..c2a7639fde4 100644
--- a/spec/workers/gitlab/github_import/import_issue_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_issue_worker_spec.rb
@@ -7,7 +7,8 @@ RSpec.describe Gitlab::GithubImport::ImportIssueWorker do
describe '#import' do
it 'imports an issue' do
- project = double(:project, full_path: 'foo/bar', id: 1, import_state: nil)
+ import_state = create(:import_state, :started)
+ project = double(:project, full_path: 'foo/bar', id: 1, import_state: import_state)
client = double(:client)
importer = double(:importer)
hash = {
diff --git a/spec/workers/gitlab/github_import/import_note_worker_spec.rb b/spec/workers/gitlab/github_import/import_note_worker_spec.rb
index f4598340938..16ca5658f77 100644
--- a/spec/workers/gitlab/github_import/import_note_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_note_worker_spec.rb
@@ -7,7 +7,8 @@ RSpec.describe Gitlab::GithubImport::ImportNoteWorker do
describe '#import' do
it 'imports a note' do
- project = double(:project, full_path: 'foo/bar', id: 1, import_state: nil)
+ import_state = create(:import_state, :started)
+ project = double(:project, full_path: 'foo/bar', id: 1, import_state: import_state)
client = double(:client)
importer = double(:importer)
hash = {
diff --git a/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb b/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb
index faed2f8f340..59f45b437c4 100644
--- a/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb
@@ -7,7 +7,8 @@ RSpec.describe Gitlab::GithubImport::ImportPullRequestWorker do
describe '#import' do
it 'imports a pull request' do
- project = double(:project, full_path: 'foo/bar', id: 1, import_state: nil)
+ import_state = create(:import_state, :started)
+ project = double(:project, full_path: 'foo/bar', id: 1, import_state: import_state)
client = double(:client)
importer = double(:importer)
hash = {