summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-09-20 09:10:52 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-09-20 09:10:52 +0000
commita7b422860c90eecd1b98845d234a8347686fbdcf (patch)
treef4a63124ef328ce146a82453b091e10f8189da36 /spec
parentb2362c5f21e373820afc7d7a01ed104eaedd0e49 (diff)
downloadgitlab-ce-a7b422860c90eecd1b98845d234a8347686fbdcf.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/finders/personal_access_tokens_finder_spec.rb44
-rw-r--r--spec/frontend/__mocks__/monaco-editor/index.js2
-rw-r--r--spec/frontend/__mocks__/monaco-yaml/index.js4
-rw-r--r--spec/frontend/editor/source_editor_ci_schema_ext_spec.js12
-rw-r--r--spec/frontend/ide/utils_spec.js4
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js (renamed from spec/frontend/projects/settings/branch_rules/branch_dropdown_spec.js)2
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/edit/index_spec.js (renamed from spec/frontend/projects/settings/branch_rules/rule_edit_spec.js)6
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/edit/protections/index_spec.js (renamed from spec/frontend/projects/settings/branch_rules/components/protections/index_spec.js)8
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/edit/protections/merge_protections_spec.js (renamed from spec/frontend/projects/settings/branch_rules/components/protections/merge_protections_spec.js)4
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/edit/protections/push_protections_spec.js (renamed from spec/frontend/projects/settings/branch_rules/components/protections/push_protections_spec.js)4
-rw-r--r--spec/models/personal_access_token_spec.rb25
-rw-r--r--spec/models/preloaders/project_root_ancestor_preloader_spec.rb48
-rw-r--r--spec/requests/api/personal_access_tokens_spec.rb367
13 files changed, 468 insertions, 62 deletions
diff --git a/spec/finders/personal_access_tokens_finder_spec.rb b/spec/finders/personal_access_tokens_finder_spec.rb
index f22bff62082..21380cb6632 100644
--- a/spec/finders/personal_access_tokens_finder_spec.rb
+++ b/spec/finders/personal_access_tokens_finder_spec.rb
@@ -7,6 +7,50 @@ RSpec.describe PersonalAccessTokensFinder do
described_class.new(options, current_user)
end
+ describe '# searches PATs' do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:time_token) do
+ create(:personal_access_token, created_at: DateTime.new(2022, 01, 02),
+ last_used_at: DateTime.new(2022, 01, 02))
+ end
+
+ let_it_be(:name_token) { create(:personal_access_token, name: 'test_1') }
+
+ let_it_be(:impersonated_token) do
+ create(:personal_access_token, :impersonation,
+ created_at: DateTime.new(2022, 01, 02),
+ last_used_at: DateTime.new(2022, 01, 02),
+ name: 'imp_token'
+ )
+ end
+
+ shared_examples 'finding tokens by user and options' do
+ subject { finder(option, user).execute }
+
+ it 'finds exactly' do
+ subject
+
+ is_expected.to contain_exactly(*result)
+ end
+ end
+
+ context 'by' do
+ where(:option, :user, :result) do
+ { created_before: DateTime.new(2022, 01, 03) } | create(:admin) | lazy { [time_token, impersonated_token] }
+ { created_after: DateTime.new(2022, 01, 01) } | create(:admin) | lazy { [time_token, name_token, impersonated_token] }
+ { last_used_before: DateTime.new(2022, 01, 03) } | create(:admin) | lazy { [time_token, impersonated_token] }
+ { last_used_before: DateTime.new(2022, 01, 03) } | create(:admin) | lazy { [time_token, impersonated_token] }
+ { impersonation: true } | create(:admin) | lazy { [impersonated_token] }
+ { search: 'test' } | create(:admin) | lazy { [name_token] }
+ end
+
+ with_them do
+ it_behaves_like 'finding tokens by user and options'
+ end
+ end
+ end
+
describe '#execute' do
let(:user) { create(:user) }
let(:params) { {} }
diff --git a/spec/frontend/__mocks__/monaco-editor/index.js b/spec/frontend/__mocks__/monaco-editor/index.js
index 384f9993150..d09672a4ecf 100644
--- a/spec/frontend/__mocks__/monaco-editor/index.js
+++ b/spec/frontend/__mocks__/monaco-editor/index.js
@@ -8,10 +8,8 @@ import 'monaco-editor/esm/vs/language/css/monaco.contribution';
import 'monaco-editor/esm/vs/language/json/monaco.contribution';
import 'monaco-editor/esm/vs/language/html/monaco.contribution';
import 'monaco-editor/esm/vs/basic-languages/monaco.contribution';
-import 'monaco-yaml/lib/esm/monaco.contribution';
// This language starts trying to spin up web workers which obviously breaks in Jest environment
jest.mock('monaco-editor/esm/vs/language/typescript/tsMode');
-jest.mock('monaco-yaml/lib/esm/yamlMode');
export * from 'monaco-editor/esm/vs/editor/editor.api';
diff --git a/spec/frontend/__mocks__/monaco-yaml/index.js b/spec/frontend/__mocks__/monaco-yaml/index.js
new file mode 100644
index 00000000000..36681854d0b
--- /dev/null
+++ b/spec/frontend/__mocks__/monaco-yaml/index.js
@@ -0,0 +1,4 @@
+const setDiagnosticsOptions = jest.fn();
+const yamlDefaults = {};
+
+export { setDiagnosticsOptions, yamlDefaults };
diff --git a/spec/frontend/editor/source_editor_ci_schema_ext_spec.js b/spec/frontend/editor/source_editor_ci_schema_ext_spec.js
index 9a14e1a55eb..21f8979f1a9 100644
--- a/spec/frontend/editor/source_editor_ci_schema_ext_spec.js
+++ b/spec/frontend/editor/source_editor_ci_schema_ext_spec.js
@@ -1,4 +1,4 @@
-import { languages } from 'monaco-editor';
+import { setDiagnosticsOptions } from 'monaco-yaml';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import { TEST_HOST } from 'helpers/test_constants';
import { CiSchemaExtension } from '~/editor/extensions/source_editor_ci_schema_ext';
@@ -52,16 +52,12 @@ describe('~/editor/editor_ci_config_ext', () => {
});
describe('registerCiSchema', () => {
- beforeEach(() => {
- jest.spyOn(languages.yaml.yamlDefaults, 'setDiagnosticsOptions');
- });
-
describe('register validations options with monaco for yaml language', () => {
const mockProjectNamespace = 'namespace1';
const mockProjectPath = 'project1';
const getConfiguredYmlSchema = () => {
- return languages.yaml.yamlDefaults.setDiagnosticsOptions.mock.calls[0][0].schemas[0];
+ return setDiagnosticsOptions.mock.calls[0][0].schemas[0];
};
it('with expected basic validation configuration', () => {
@@ -77,8 +73,8 @@ describe('~/editor/editor_ci_config_ext', () => {
completion: true,
};
- expect(languages.yaml.yamlDefaults.setDiagnosticsOptions).toHaveBeenCalledTimes(1);
- expect(languages.yaml.yamlDefaults.setDiagnosticsOptions).toHaveBeenCalledWith(
+ expect(setDiagnosticsOptions).toHaveBeenCalledTimes(1);
+ expect(setDiagnosticsOptions).toHaveBeenCalledWith(
expect.objectContaining(expectedOptions),
);
});
diff --git a/spec/frontend/ide/utils_spec.js b/spec/frontend/ide/utils_spec.js
index fd9d481251d..4efc0ac6028 100644
--- a/spec/frontend/ide/utils_spec.js
+++ b/spec/frontend/ide/utils_spec.js
@@ -1,4 +1,5 @@
import { languages } from 'monaco-editor';
+import { setDiagnosticsOptions as yamlDiagnosticsOptions } from 'monaco-yaml';
import {
isTextFile,
registerLanguages,
@@ -203,7 +204,6 @@ describe('WebIDE utils', () => {
};
jest.spyOn(languages.json.jsonDefaults, 'setDiagnosticsOptions');
- jest.spyOn(languages.yaml.yamlDefaults, 'setDiagnosticsOptions');
});
it('registers the given schemas with monaco for both json and yaml languages', () => {
@@ -212,7 +212,7 @@ describe('WebIDE utils', () => {
expect(languages.json.jsonDefaults.setDiagnosticsOptions).toHaveBeenCalledWith(
expect.objectContaining({ schemas: [schema] }),
);
- expect(languages.yaml.yamlDefaults.setDiagnosticsOptions).toHaveBeenCalledWith(
+ expect(yamlDiagnosticsOptions).toHaveBeenCalledWith(
expect.objectContaining({ schemas: [schema] }),
);
});
diff --git a/spec/frontend/projects/settings/branch_rules/branch_dropdown_spec.js b/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js
index 79bce5a4b3f..11f219c1f90 100644
--- a/spec/frontend/projects/settings/branch_rules/branch_dropdown_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js
@@ -4,7 +4,7 @@ import { GlDropdown, GlSearchBoxByType, GlDropdownItem, GlSprintf } from '@gitla
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import BranchDropdown, {
i18n,
-} from '~/projects/settings/branch_rules/components/branch_dropdown.vue';
+} from '~/projects/settings/branch_rules/components/edit/branch_dropdown.vue';
import createMockApollo from 'helpers/mock_apollo_helper';
import branchesQuery from '~/projects/settings/branch_rules/queries/branches.query.graphql';
import waitForPromises from 'helpers/wait_for_promises';
diff --git a/spec/frontend/projects/settings/branch_rules/rule_edit_spec.js b/spec/frontend/projects/settings/branch_rules/components/edit/index_spec.js
index b0b2b9191d4..21e63fdb24d 100644
--- a/spec/frontend/projects/settings/branch_rules/rule_edit_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/edit/index_spec.js
@@ -1,9 +1,9 @@
import { nextTick } from 'vue';
import { getParameterByName } from '~/lib/utils/url_utility';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import RuleEdit from '~/projects/settings/branch_rules/components/rule_edit.vue';
-import BranchDropdown from '~/projects/settings/branch_rules/components/branch_dropdown.vue';
-import Protections from '~/projects/settings/branch_rules/components/protections/index.vue';
+import RuleEdit from '~/projects/settings/branch_rules/components/edit/index.vue';
+import BranchDropdown from '~/projects/settings/branch_rules/components/edit/branch_dropdown.vue';
+import Protections from '~/projects/settings/branch_rules/components/edit/protections/index.vue';
jest.mock('~/lib/utils/url_utility', () => ({
getParameterByName: jest.fn().mockImplementation(() => 'main'),
diff --git a/spec/frontend/projects/settings/branch_rules/components/protections/index_spec.js b/spec/frontend/projects/settings/branch_rules/components/edit/protections/index_spec.js
index 3592fa50622..ee90ff8318f 100644
--- a/spec/frontend/projects/settings/branch_rules/components/protections/index_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/edit/protections/index_spec.js
@@ -3,10 +3,10 @@ import { GlLink } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import Protections, {
i18n,
-} from '~/projects/settings/branch_rules/components/protections/index.vue';
-import PushProtections from '~/projects/settings/branch_rules/components/protections/push_protections.vue';
-import MergeProtections from '~/projects/settings/branch_rules/components/protections/merge_protections.vue';
-import { protections } from '../../mock_data';
+} from '~/projects/settings/branch_rules/components/edit/protections/index.vue';
+import PushProtections from '~/projects/settings/branch_rules/components/edit/protections/push_protections.vue';
+import MergeProtections from '~/projects/settings/branch_rules/components/edit/protections/merge_protections.vue';
+import { protections } from '../../../mock_data';
describe('Branch Protections', () => {
let wrapper;
diff --git a/spec/frontend/projects/settings/branch_rules/components/protections/merge_protections_spec.js b/spec/frontend/projects/settings/branch_rules/components/edit/protections/merge_protections_spec.js
index 0e168a2ad78..b5fdc46d600 100644
--- a/spec/frontend/projects/settings/branch_rules/components/protections/merge_protections_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/edit/protections/merge_protections_spec.js
@@ -2,8 +2,8 @@ import { GlFormGroup, GlFormCheckbox } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import MergeProtections, {
i18n,
-} from '~/projects/settings/branch_rules/components/protections/merge_protections.vue';
-import { membersAllowedToMerge, requireCodeOwnersApproval } from '../../mock_data';
+} from '~/projects/settings/branch_rules/components/edit/protections/merge_protections.vue';
+import { membersAllowedToMerge, requireCodeOwnersApproval } from '../../../mock_data';
describe('Merge Protections', () => {
let wrapper;
diff --git a/spec/frontend/projects/settings/branch_rules/components/protections/push_protections_spec.js b/spec/frontend/projects/settings/branch_rules/components/edit/protections/push_protections_spec.js
index d54dad08338..60bb7a51dcb 100644
--- a/spec/frontend/projects/settings/branch_rules/components/protections/push_protections_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/edit/protections/push_protections_spec.js
@@ -2,8 +2,8 @@ import { GlFormGroup, GlSprintf, GlFormCheckbox } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import PushProtections, {
i18n,
-} from '~/projects/settings/branch_rules/components/protections/push_protections.vue';
-import { membersAllowedToPush, allowForcePush } from '../../mock_data';
+} from '~/projects/settings/branch_rules/components/edit/protections/push_protections.vue';
+import { membersAllowedToPush, allowForcePush } from '../../../mock_data';
describe('Push Protections', () => {
let wrapper;
diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb
index 5bce6a2cc3f..67e7d444d25 100644
--- a/spec/models/personal_access_token_spec.rb
+++ b/spec/models/personal_access_token_spec.rb
@@ -105,6 +105,31 @@ RSpec.describe PersonalAccessToken do
end
end
+ describe '.last_used_before' do
+ context 'last_used_*' do
+ let_it_be(:date) { DateTime.new(2022, 01, 01) }
+ let_it_be(:token) { create(:personal_access_token, last_used_at: date ) }
+ # This token should never occur in the following tests and indicates that filtering was done correctly with it
+ let_it_be(:never_used_token) { create(:personal_access_token) }
+
+ describe '.last_used_before' do
+ it 'returns personal access tokens used before the specified date only' do
+ expect(described_class.last_used_before(date + 1)).to contain_exactly(token)
+ end
+ end
+
+ it 'does not return token that is last_used_at after given date' do
+ expect(described_class.last_used_before(date + 1)).not_to contain_exactly(never_used_token)
+ end
+
+ describe '.last_used_after' do
+ it 'returns personal access tokens used after the specified date only' do
+ expect(described_class.last_used_after(date - 1)).to contain_exactly(token)
+ end
+ end
+ end
+ end
+
describe '.last_used_before_or_unused' do
let(:last_used_at) { 1.month.ago.beginning_of_hour }
let!(:unused_token) { create(:personal_access_token) }
diff --git a/spec/models/preloaders/project_root_ancestor_preloader_spec.rb b/spec/models/preloaders/project_root_ancestor_preloader_spec.rb
index 30036a6a033..bb0de24abe5 100644
--- a/spec/models/preloaders/project_root_ancestor_preloader_spec.rb
+++ b/spec/models/preloaders/project_root_ancestor_preloader_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Preloaders::ProjectRootAncestorPreloader do
let_it_be(:root_parent1) { create(:group, :private, name: 'root-1', path: 'root-1') }
- let_it_be(:root_parent2) { create(:group, :private, name: 'root-2', path: 'root-2') }
+ let_it_be(:root_parent2) { create(:group, name: 'root-2', path: 'root-2') }
let_it_be(:guest_project) { create(:project, name: 'public guest', path: 'public-guest') }
let_it_be(:private_maintainer_project) do
create(:project, :private, name: 'b private maintainer', path: 'b-private-maintainer', namespace: root_parent1)
@@ -15,7 +15,7 @@ RSpec.describe Preloaders::ProjectRootAncestorPreloader do
end
let_it_be(:public_maintainer_project) do
- create(:project, :private, name: 'a public maintainer', path: 'a-public-maintainer', namespace: root_parent2)
+ create(:project, name: 'a public maintainer', path: 'a-public-maintainer', namespace: root_parent2)
end
let(:root_query_regex) { /\ASELECT.+FROM "namespaces" WHERE "namespaces"."id" = \d+/ }
@@ -36,20 +36,20 @@ RSpec.describe Preloaders::ProjectRootAncestorPreloader do
it 'strong_memoizes the correct root_ancestor' do
pristine_projects.each do |project|
- expected_parent_id = project.root_ancestor&.id
+ preloaded_parent_id = project.root_ancestor&.id
- expect(project.parent_id).to eq(expected_parent_id)
+ expect(preloaded_parent_id).to eq(project.parent_id)
end
end
end
context 'when use_traversal_ids FF is enabled' do
context 'when the preloader is used' do
- before do
- preload_ancestors
- end
-
context 'when no additional preloads are provided' do
+ before do
+ preload_ancestors(:group)
+ end
+
it_behaves_like 'executes N matching DB queries', 0
end
@@ -57,6 +57,10 @@ RSpec.describe Preloaders::ProjectRootAncestorPreloader do
let(:additional_preloads) { [:route] }
let(:root_query_regex) { /\ASELECT.+FROM "routes" WHERE "routes"."source_id" = \d+/ }
+ before do
+ preload_ancestors
+ end
+
it_behaves_like 'executes N matching DB queries', 0, :full_path
end
end
@@ -64,6 +68,17 @@ RSpec.describe Preloaders::ProjectRootAncestorPreloader do
context 'when the preloader is not used' do
it_behaves_like 'executes N matching DB queries', 4
end
+
+ context 'when using a :group sti name and passing projects in a user namespace' do
+ let(:projects) { [private_developer_project] }
+ let(:additional_preloads) { [:ip_restrictions, :saml_provider] }
+
+ it 'does not load a nil value for root_ancestor' do
+ preload_ancestors(:group)
+
+ expect(pristine_projects.first.root_ancestor).to eq(private_developer_project.root_ancestor)
+ end
+ end
end
context 'when use_traversal_ids FF is disabled' do
@@ -91,9 +106,22 @@ RSpec.describe Preloaders::ProjectRootAncestorPreloader do
context 'when the preloader is not used' do
it_behaves_like 'executes N matching DB queries', 4
end
+
+ context 'when using a :group sti name and passing projects in a user namespace' do
+ let(:projects) { [private_developer_project] }
+ let(:additional_preloads) { [:ip_restrictions, :saml_provider] }
+
+ it 'does not load a nil value for root_ancestor' do
+ preload_ancestors(:group)
+
+ expect(pristine_projects.first.root_ancestor).to eq(private_developer_project.root_ancestor)
+ end
+ end
end
- def preload_ancestors
- described_class.new(pristine_projects, :namespace, additional_preloads).execute
+ private
+
+ def preload_ancestors(namespace_sti_name = :namespace)
+ described_class.new(pristine_projects, namespace_sti_name, additional_preloads).execute
end
end
diff --git a/spec/requests/api/personal_access_tokens_spec.rb b/spec/requests/api/personal_access_tokens_spec.rb
index 37b5a594f2a..31c4e8803e3 100644
--- a/spec/requests/api/personal_access_tokens_spec.rb
+++ b/spec/requests/api/personal_access_tokens_spec.rb
@@ -4,14 +4,34 @@ require 'spec_helper'
RSpec.describe API::PersonalAccessTokens do
let_it_be(:path) { '/personal_access_tokens' }
- let_it_be(:token1) { create(:personal_access_token) }
- let_it_be(:token2) { create(:personal_access_token) }
- let_it_be(:token_impersonated) { create(:personal_access_token, impersonation: true, user: token1.user) }
- let_it_be(:current_user) { create(:user) }
describe 'GET /personal_access_tokens' do
+ using RSpec::Parameterized::TableSyntax
+
+ def map_id(json_resonse)
+ json_response.map { |pat| pat['id'] }
+ end
+
+ shared_examples 'response as expected' do |params|
+ subject { get api(path, personal_access_token: current_users_token), params: params }
+
+ it "status, count and result as expected" do
+ subject
+
+ if status == :bad_request
+ expect(json_response).to eq(result)
+ elsif status == :ok
+ expect(map_id(json_response)).to a_collection_containing_exactly(*result)
+ end
+
+ expect(response).to have_gitlab_http_status(status)
+ expect(json_response.count).to eq(result_count)
+ end
+ end
+
context 'logged in as an Administrator' do
let_it_be(:current_user) { create(:admin) }
+ let_it_be(:current_users_token) { create(:personal_access_token, user: current_user) }
it 'returns all PATs by default' do
get api(path, current_user)
@@ -21,60 +41,348 @@ RSpec.describe API::PersonalAccessTokens do
end
context 'filtered with user_id parameter' do
+ let_it_be(:token) { create(:personal_access_token) }
+ let_it_be(:token_impersonated) { create(:personal_access_token, impersonation: true, user: token.user) }
+
it 'returns only PATs belonging to that user' do
- get api(path, current_user), params: { user_id: token1.user.id }
+ get api(path, current_user), params: { user_id: token.user.id }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.count).to eq(2)
- expect(json_response.first['user_id']).to eq(token1.user.id)
+ expect(json_response.first['user_id']).to eq(token.user.id)
expect(json_response.last['id']).to eq(token_impersonated.id)
end
end
- context 'logged in as a non-Administrator' do
- let_it_be(:current_user) { create(:user) }
+ context 'filter with revoked parameter' do
+ let_it_be(:revoked_token) { create(:personal_access_token, revoked: true) }
+ let_it_be(:not_revoked_token1) { create(:personal_access_token, revoked: false) }
+ let_it_be(:not_revoked_token2) { create(:personal_access_token, revoked: false) }
+
+ where(:revoked, :status, :result_count, :result) do
+ true | :ok | 1 | lazy { [revoked_token.id] }
+ false | :ok | 3 | lazy { [not_revoked_token1.id, not_revoked_token2.id, current_users_token.id] }
+ 'asdf' | :bad_request | 1 | { "error" => "revoked is invalid" }
+ end
+
+ with_them do
+ it_behaves_like 'response as expected', revoked: params[:revoked]
+ end
+ end
+
+ context 'filter with active parameter' do
+ let_it_be(:inactive_token1) { create(:personal_access_token, revoked: true) }
+ let_it_be(:inactive_token2) { create(:personal_access_token, expires_at: Time.new(2022, 01, 01, 00, 00, 00)) }
+ let_it_be(:active_token) { create(:personal_access_token) }
+
+ where(:state, :status, :result_count, :result) do
+ 'inactive' | :ok | 2 | lazy { [inactive_token1.id, inactive_token2.id] }
+ 'active' | :ok | 2 | lazy { [active_token.id, current_users_token.id] }
+ 'asdf' | :bad_request | 1 | { "error" => "state does not have a valid value" }
+ end
+
+ with_them do
+ it_behaves_like 'response as expected', state: params[:state]
+ end
+ end
+
+ context 'filter with created parameter' do
+ let_it_be(:token1) { create(:personal_access_token, created_at: DateTime.new(2022, 01, 01, 12, 30, 25) ) }
+
+ context 'test created_before' do
+ where(:created_at, :status, :result_count, :result) do
+ '2022-01-02' | :ok | 1 | lazy { [token1.id] }
+ '2022-01-01' | :ok | 0 | lazy { [] }
+ '2022-01-01T12:30:24' | :ok | 0 | lazy { [] }
+ '2022-01-01T12:30:25' | :ok | 1 | lazy { [token1.id] }
+ '2022-01-01T:12:30:26' | :ok | 1 | lazy { [token1.id] }
+ 'asdf' | :bad_request | 1 | { "error" => "created_before is invalid" }
+ end
+
+ with_them do
+ it_behaves_like 'response as expected', created_before: params[:created_at]
+ end
+ end
+
+ context 'test created_after' do
+ where(:created_at, :status, :result_count, :result) do
+ '2022-01-03' | :ok | 1 | lazy { [current_users_token.id] }
+ '2022-01-01' | :ok | 2 | lazy { [token1.id, current_users_token.id] }
+ '2022-01-01T12:30:25' | :ok | 2 | lazy { [token1.id, current_users_token.id] }
+ '2022-01-01T12:30:26' | :ok | 1 | lazy { [current_users_token.id] }
+ (DateTime.now + 1).to_s | :ok | 0 | lazy { [] }
+ 'asdf' | :bad_request | 1 | { "error" => "created_after is invalid" }
+ end
+
+ with_them do
+ it_behaves_like 'response as expected', created_after: params[:created_at]
+ end
+ end
+ end
+
+ context 'filter with last_used parameter' do
+ let_it_be(:token1) { create(:personal_access_token, last_used_at: DateTime.new(2022, 01, 01, 12, 30, 25) ) }
+ let_it_be(:never_used_token) { create(:personal_access_token) }
+
+ context 'test last_used_before' do
+ where(:last_used_at, :status, :result_count, :result) do
+ '2022-01-02' | :ok | 1 | lazy { [token1.id] }
+ '2022-01-01' | :ok | 0 | lazy { [] }
+ '2022-01-01T12:30:24' | :ok | 0 | lazy { [] }
+ '2022-01-01T12:30:25' | :ok | 1 | lazy { [token1.id] }
+ '2022-01-01T12:30:26' | :ok | 1 | lazy { [token1.id] }
+ 'asdf' | :bad_request | 1 | { "error" => "last_used_before is invalid" }
+ end
+
+ with_them do
+ it_behaves_like 'response as expected', last_used_before: params[:last_used_at]
+ end
+ end
+
+ context 'test last_used_after' do
+ where(:last_used_at, :status, :result_count, :result) do
+ '2022-01-03' | :ok | 1 | lazy { [current_users_token.id] }
+ '2022-01-01' | :ok | 2 | lazy { [token1.id, current_users_token.id] }
+ '2022-01-01T12:30:26' | :ok | 1 | lazy { [current_users_token.id] }
+ '2022-01-01T12:30:25' | :ok | 2 | lazy { [token1.id, current_users_token.id] }
+ (DateTime.now + 1).to_s | :ok | 0 | lazy { [] }
+ 'asdf' | :bad_request | 1 | { "error" => "last_used_after is invalid" }
+ end
+
+ with_them do
+ it_behaves_like 'response as expected', last_used_after: params[:last_used_at]
+ end
+ end
+ end
+
+ context 'filter with search parameter' do
+ let_it_be(:token1) { create(:personal_access_token, name: 'test_1') }
+ let_it_be(:token2) { create(:personal_access_token, name: 'test_2') }
+ let_it_be(:token3) { create(:personal_access_token, name: '') }
+
+ where(:pattern, :status, :result_count, :result) do
+ 'test' | :ok | 2 | lazy { [token1.id, token2.id] }
+ '' | :ok | 4 | lazy { [token1.id, token2.id, token3.id, current_users_token.id] }
+ 'test_1' | :ok | 1 | lazy { [token1.id] }
+ 'asdf' | :ok | 0 | lazy { [] }
+ end
+
+ with_them do
+ it_behaves_like 'response as expected', search: params[:pattern]
+ end
+ end
+
+ context 'filter created_before/created_after combined with last_used_before/last_used_after' do
+ let_it_be(:date) { DateTime.new(2022, 01, 02) }
+ let_it_be(:token1) { create(:personal_access_token, created_at: date, last_used_at: date) }
+
+ where(:date_before, :date_after, :status, :result_count, :result) do
+ '2022-01-03' | '2022-01-01' | :ok | 1 | lazy { [token1.id] }
+ '2022-01-01' | '2022-01-03' | :ok | 0 | lazy { [] }
+ '2022-01-03' | nil | :ok | 1 | lazy { [token1.id] }
+ nil | '2022-01-01' | :ok | 2 | lazy { [token1.id, current_users_token.id] }
+ end
+
+ with_them do
+ it_behaves_like 'response as expected', { created_before: params[:date_before],
+ created_after: params[:date_after] }
+ it_behaves_like 'response as expected', { last_used_before: params[:date_before],
+ last_used_after: params[:date_after] }
+ end
+ end
+
+ context 'filter created_before and created_after combined is valid' do
+ let_it_be(:token1) { create(:personal_access_token, created_at: DateTime.new(2022, 01, 02)) }
+
+ where(:created_before, :created_after, :status, :result) do
+ '2022-01-02' | '2022-01-02' | :ok | lazy { [token1.id] }
+ '2022-01-03' | '2022-01-01' | :ok | lazy { [token1.id] }
+ '2022-01-01' | '2022-01-03' | :ok | lazy { [] }
+ '2022-01-03' | nil | :ok | lazy { [token1.id] }
+ nil | '2022-01-01' | :ok | lazy { [token1.id] }
+ end
+
+ with_them do
+ it "returns all valid tokens" do
+ get api(path, personal_access_token: current_users_token),
+ params: { created_before: created_before, created_after: created_after }
+
+ expect(response).to have_gitlab_http_status(status)
+
+ expect(json_response.map { |pat| pat['id'] } ).to include(*result) if status == :ok
+ end
+ end
+ end
+
+ context 'filter last_used_before and last_used_after combined is valid' do
+ let_it_be(:token1) { create(:personal_access_token, last_used_at: DateTime.new(2022, 01, 02) ) }
+
+ where(:last_used_before, :last_used_after, :status, :result) do
+ '2022-01-02' | '2022-01-02' | :ok | lazy { [token1.id] }
+ '2022-01-03' | '2022-01-01' | :ok | lazy { [token1.id] }
+ '2022-01-01' | '2022-01-03' | :ok | lazy { [] }
+ '2022-01-03' | nil | :ok | lazy { [token1.id] }
+ nil | '2022-01-01' | :ok | lazy { [token1.id] }
+ end
+
+ with_them do
+ it "returns all valid tokens" do
+ get api(path, personal_access_token: current_users_token),
+ params: { last_used_before: last_used_before, last_used_after: last_used_after }
+
+ expect(response).to have_gitlab_http_status(status)
+
+ expect(json_response.map { |pat| pat['id'] } ).to include(*result) if status == :ok
+ end
+ end
+ end
+ end
+
+ context 'logged in as a non-Administrator' do
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:current_users_token) { create(:personal_access_token, user: current_user) }
+
+ it 'returns all PATs belonging to the signed-in user' do
+ get api(path, personal_access_token: current_users_token)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.count).to eq(1)
+ expect(json_response.map { |r| r['id'] }.uniq).to contain_exactly(current_users_token.id)
+ expect(json_response.map { |r| r['user_id'] }.uniq).to contain_exactly(current_user.id)
+ end
+
+ context 'filtered with user_id parameter' do
let_it_be(:user) { create(:user) }
- let_it_be(:token) { create(:personal_access_token, user: current_user) }
- let_it_be(:other_token) { create(:personal_access_token, user: user) }
- let_it_be(:token_impersonated) { create(:personal_access_token, impersonation: true, user: current_user) }
- it 'returns all PATs belonging to the signed-in user' do
- get api(path, current_user, personal_access_token: token)
+ it 'returns PATs belonging to the specific user' do
+ get api(path, current_user, personal_access_token: current_users_token), params: { user_id: current_user.id }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.count).to eq(1)
+ expect(json_response.map { |r| r['id'] }.uniq).to contain_exactly(current_users_token.id)
expect(json_response.map { |r| r['user_id'] }.uniq).to contain_exactly(current_user.id)
end
- context 'filtered with user_id parameter' do
- it 'returns PATs belonging to the specific user' do
- get api(path, current_user, personal_access_token: token), params: { user_id: current_user.id }
+ it 'is unauthorized if filtered by a user other than current_user' do
+ get api(path, current_user, personal_access_token: current_users_token), params: { user_id: user.id }
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response.count).to eq(1)
- expect(json_response.map { |r| r['user_id'] }.uniq).to contain_exactly(current_user.id)
- end
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
- it 'is unauthorized if filtered by a user other than current_user' do
- get api(path, current_user, personal_access_token: token), params: { user_id: user.id }
+ context 'filter with revoked parameter' do
+ let_it_be(:users_revoked_token) { create(:personal_access_token, revoked: true, user: current_user) }
+ let_it_be(:not_revoked_token) { create(:personal_access_token, revoked: false) }
+ let_it_be(:oter_revoked_token) { create(:personal_access_token, revoked: true) }
- expect(response).to have_gitlab_http_status(:unauthorized)
- end
+ where(:revoked, :status, :result_count, :result) do
+ true | :ok | 1 | lazy { [users_revoked_token.id] }
+ false | :ok | 1 | lazy { [current_users_token.id] }
+ end
+
+ with_them do
+ it_behaves_like 'response as expected', revoked: params[:revoked]
end
end
- context 'not authenticated' do
- it 'is forbidden' do
- get api(path)
+ context 'filter with active parameter' do
+ let_it_be(:users_inactive_token) { create(:personal_access_token, revoked: true, user: current_user) }
+ let_it_be(:inactive_token) { create(:personal_access_token, expires_at: Time.new(2022, 01, 01, 00, 00, 00)) }
+ let_it_be(:other_active_token) { create(:personal_access_token) }
- expect(response).to have_gitlab_http_status(:unauthorized)
+ where(:state, :status, :result_count, :result) do
+ 'inactive' | :ok | 1 | lazy { [users_inactive_token.id] }
+ 'active' | :ok | 1 | lazy { [current_users_token.id] }
+ end
+
+ with_them do
+ it_behaves_like 'response as expected', state: params[:state]
+ end
+ end
+
+ # The created_before filter has been extensively tested in the 'logged in as administrator' section.
+ # Here it is only tested whether PATs to which the user has no access right are excluded from the filter function.
+ context 'filter with created parameter' do
+ let_it_be(:token1) do
+ create(:personal_access_token, created_at: DateTime.new(2022, 01, 02, 12, 30, 25), user: current_user )
+ end
+
+ let_it_be(:token2) { create(:personal_access_token, created_at: DateTime.new(2022, 01, 02, 12, 30, 25)) }
+ let_it_be(:status) { :ok }
+
+ context 'created_before' do
+ let_it_be(:result_count) { 1 }
+ let_it_be(:result) { [token1.id] }
+
+ it_behaves_like 'response as expected', created_before: '2022-01-03'
+ end
+
+ context 'created_after' do
+ let_it_be(:result_count) { 2 }
+ let_it_be(:result) { [token1.id, current_users_token.id] }
+
+ it_behaves_like 'response as expected', created_after: '2022-01-01'
+ end
+ end
+
+ # The last_used_before filter has been extensively tested in the 'logged in as administrator' section.
+ # Here it is only tested whether PATs to which the user has no access right are excluded from the filter function.
+ context 'filter with last_used' do
+ let_it_be(:token1) do
+ create(:personal_access_token, last_used_at: DateTime.new(2022, 01, 01, 12, 30, 25), user: current_user)
+ end
+
+ let_it_be(:token2) { create(:personal_access_token, last_used_at: DateTime.new(2022, 01, 01, 12, 30, 25) ) }
+ let_it_be(:never_used_token) { create(:personal_access_token) }
+ let_it_be(:status) { :ok }
+
+ context 'last_used_before' do
+ let_it_be(:result_count) { 1 }
+ let_it_be(:result) { [token1.id] }
+
+ it_behaves_like 'response as expected', last_used_before: '2022-01-02'
+ end
+
+ context 'last_used_after' do
+ let_it_be(:result_count) { 2 }
+ let_it_be(:result) { [token1.id, current_users_token.id] }
+
+ it_behaves_like 'response as expected', last_used_after: '2022-01-01'
+ end
+ end
+
+ # The search filter has been extensively tested in the 'logged in as administrator' section.
+ # Here it is only tested whether PATs to which the user has no access right are excluded from the filter function.
+ context 'filter with search parameter' do
+ let_it_be(:token1) { create(:personal_access_token, name: 'test_1', user: current_user) }
+ let_it_be(:token2) { create(:personal_access_token, name: 'test_1') }
+ let_it_be(:token3) { create(:personal_access_token, name: '') }
+
+ where(:pattern, :status, :result_count, :result) do
+ 'test' | :ok | 1 | lazy { [token1.id] }
+ '' | :ok | 2 | lazy { [token1.id, current_users_token.id] }
+ 'test_1' | :ok | 1 | lazy { [token1.id] }
+ end
+
+ with_them do
+ it_behaves_like 'response as expected', search: params[:pattern]
end
end
end
+
+ context 'not authenticated' do
+ it 'is forbidden' do
+ get api(path)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
end
describe 'GET /personal_access_tokens/:id' do
+ let_it_be(:current_user) { create(:user) }
let_it_be(:user_token) { create(:personal_access_token, user: current_user) }
+ let_it_be(:token1) { create(:personal_access_token) }
let_it_be(:user_read_only_token) { create(:personal_access_token, scopes: ['read_repository'], user: current_user) }
let_it_be(:user_token_path) { "/personal_access_tokens/#{user_token.id}" }
let_it_be(:invalid_path) { "/personal_access_tokens/#{non_existing_record_id}" }
@@ -136,6 +444,9 @@ RSpec.describe API::PersonalAccessTokens do
end
describe 'DELETE /personal_access_tokens/:id' do
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:token1) { create(:personal_access_token) }
+
let(:path) { "/personal_access_tokens/#{token1.id}" }
context 'when current_user is an administrator', :enable_admin_mode do