summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/profiles/personal_access_tokens_spec.rb30
-rw-r--r--spec/factories/personal_access_tokens.rb17
-rw-r--r--spec/features/admin/admin_users_impersonation_tokens_spec.rb72
-rw-r--r--spec/features/profiles/personal_access_tokens_spec.rb20
-rw-r--r--spec/finders/personal_access_tokens_finder_spec.rb196
-rw-r--r--spec/helpers/events_helper_spec.rb7
-rw-r--r--spec/lib/gitlab/auth_spec.rb34
-rw-r--r--spec/models/personal_access_token_spec.rb36
-rw-r--r--spec/requests/api/users_spec.rb185
9 files changed, 571 insertions, 26 deletions
diff --git a/spec/controllers/profiles/personal_access_tokens_spec.rb b/spec/controllers/profiles/personal_access_tokens_spec.rb
index 19572ce53b7..e1353406b32 100644
--- a/spec/controllers/profiles/personal_access_tokens_spec.rb
+++ b/spec/controllers/profiles/personal_access_tokens_spec.rb
@@ -4,14 +4,15 @@ describe Profiles::PersonalAccessTokensController do
let(:user) { create(:user) }
let(:token_attributes) { attributes_for(:personal_access_token) }
+ before { sign_in(user) }
+
describe '#create' do
def created_token
PersonalAccessToken.order(:created_at).last
end
- before { sign_in(user) }
-
it "allows creation of a token with scopes" do
+ name = FFaker::Product.brand
scopes = %w[api read_user]
post :create, personal_access_token: token_attributes.merge(scopes: scopes)
@@ -23,12 +24,33 @@ describe Profiles::PersonalAccessTokensController do
end
it "allows creation of a token with an expiry date" do
- expires_at = 5.days.from_now
+ expires_at = 5.days.from_now.to_date
post :create, personal_access_token: token_attributes.merge(expires_at: expires_at)
expect(created_token).not_to be_nil
- expect(created_token.expires_at.to_i).to eq(expires_at.to_i)
+ expect(created_token.expires_at).to eq(expires_at)
+ end
+ end
+
+ describe '#index' do
+ let!(:active_personal_access_token) { create(:personal_access_token, user: user) }
+ let!(:inactive_personal_access_token) { create(:personal_access_token, :revoked, user: user) }
+ let!(:impersonation_personal_access_token) { create(:personal_access_token, :impersonation, user: user) }
+
+ before { get :index }
+
+ it "retrieves active personal access tokens" do
+ expect(assigns(:active_personal_access_tokens)).to include(active_personal_access_token)
+ end
+
+ it "retrieves inactive personal access tokens" do
+ expect(assigns(:inactive_personal_access_tokens)).to include(inactive_personal_access_token)
+ end
+
+ it "does not retrieve impersonation personal access tokens" do
+ expect(assigns(:active_personal_access_tokens)).not_to include(impersonation_personal_access_token)
+ expect(assigns(:inactive_personal_access_tokens)).not_to include(impersonation_personal_access_token)
end
end
end
diff --git a/spec/factories/personal_access_tokens.rb b/spec/factories/personal_access_tokens.rb
index 811eab7e15b..7b15ba47de1 100644
--- a/spec/factories/personal_access_tokens.rb
+++ b/spec/factories/personal_access_tokens.rb
@@ -6,5 +6,22 @@ FactoryGirl.define do
revoked false
expires_at { 5.days.from_now }
scopes ['api']
+ impersonation false
+
+ trait :impersonation do
+ impersonation true
+ end
+
+ trait :revoked do
+ revoked true
+ end
+
+ trait :expired do
+ expires_at { 1.day.ago }
+ end
+
+ trait :invalid do
+ token nil
+ end
end
end
diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
new file mode 100644
index 00000000000..9ff5c2f9d40
--- /dev/null
+++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
@@ -0,0 +1,72 @@
+require 'spec_helper'
+
+describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do
+ let(:admin) { create(:admin) }
+ let!(:user) { create(:user) }
+
+ def active_impersonation_tokens
+ find(".table.active-tokens")
+ end
+
+ def inactive_impersonation_tokens
+ find(".table.inactive-tokens")
+ end
+
+ before { login_as(admin) }
+
+ describe "token creation" do
+ it "allows creation of a token" do
+ name = FFaker::Product.brand
+
+ visit admin_user_impersonation_tokens_path(user_id: user.username)
+ fill_in "Name", with: name
+
+ # Set date to 1st of next month
+ find_field("Expires at").trigger('focus')
+ find(".pika-next").click
+ click_on "1"
+
+ # Scopes
+ check "api"
+ check "read_user"
+
+ expect { click_on "Create Impersonation Token" }.to change { PersonalAccessTokensFinder.new(impersonation: true).execute.count }
+ expect(active_impersonation_tokens).to have_text(name)
+ expect(active_impersonation_tokens).to have_text('In')
+ expect(active_impersonation_tokens).to have_text('api')
+ expect(active_impersonation_tokens).to have_text('read_user')
+ end
+ end
+
+ describe 'active tokens' do
+ let!(:impersonation_token) { create(:personal_access_token, :impersonation, user: user) }
+ let!(:personal_access_token) { create(:personal_access_token, user: user) }
+
+ it 'only shows impersonation tokens' do
+ visit admin_user_impersonation_tokens_path(user_id: user.username)
+
+ expect(active_impersonation_tokens).to have_text(impersonation_token.name)
+ expect(active_impersonation_tokens).not_to have_text(personal_access_token.name)
+ end
+ end
+
+ describe "inactive tokens" do
+ let!(:impersonation_token) { create(:personal_access_token, :impersonation, user: user) }
+
+ it "allows revocation of an active impersonation token" do
+ visit admin_user_impersonation_tokens_path(user_id: user.username)
+
+ click_on "Revoke"
+
+ expect(inactive_impersonation_tokens).to have_text(impersonation_token.name)
+ end
+
+ it "moves expired tokens to the 'inactive' section" do
+ impersonation_token.update(expires_at: 5.days.ago)
+
+ visit admin_user_impersonation_tokens_path(user_id: user.username)
+
+ expect(inactive_impersonation_tokens).to have_text(impersonation_token.name)
+ end
+ end
+end
diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb
index eb7b8a24669..0917d4dc3ef 100644
--- a/spec/features/profiles/personal_access_tokens_spec.rb
+++ b/spec/features/profiles/personal_access_tokens_spec.rb
@@ -4,11 +4,11 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do
let(:user) { create(:user) }
def active_personal_access_tokens
- find(".table.active-personal-access-tokens")
+ find(".table.active-tokens")
end
def inactive_personal_access_tokens
- find(".table.inactive-personal-access-tokens")
+ find(".table.inactive-tokens")
end
def created_personal_access_token
@@ -26,7 +26,7 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do
end
describe "token creation" do
- it "allows creation of a token" do
+ it "allows creation of a personal access token" do
name = FFaker::Product.brand
visit profile_personal_access_tokens_path
@@ -43,7 +43,7 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do
click_on "Create Personal Access Token"
expect(active_personal_access_tokens).to have_text(name)
- expect(active_personal_access_tokens).to have_text(Date.today.next_month.at_beginning_of_month.to_s(:medium))
+ expect(active_personal_access_tokens).to have_text('In')
expect(active_personal_access_tokens).to have_text('api')
expect(active_personal_access_tokens).to have_text('read_user')
end
@@ -60,6 +60,18 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do
end
end
+ describe 'active tokens' do
+ let!(:impersonation_token) { create(:personal_access_token, :impersonation, user: user) }
+ let!(:personal_access_token) { create(:personal_access_token, user: user) }
+
+ it 'only shows personal access tokens' do
+ visit profile_personal_access_tokens_path
+
+ expect(active_personal_access_tokens).to have_text(personal_access_token.name)
+ expect(active_personal_access_tokens).not_to have_text(impersonation_token.name)
+ end
+ end
+
describe "inactive tokens" do
let!(:personal_access_token) { create(:personal_access_token, user: user) }
diff --git a/spec/finders/personal_access_tokens_finder_spec.rb b/spec/finders/personal_access_tokens_finder_spec.rb
new file mode 100644
index 00000000000..fd92664ca24
--- /dev/null
+++ b/spec/finders/personal_access_tokens_finder_spec.rb
@@ -0,0 +1,196 @@
+require 'spec_helper'
+
+describe PersonalAccessTokensFinder do
+ def finder(options = {})
+ described_class.new(options)
+ end
+
+ describe '#execute' do
+ let(:user) { create(:user) }
+ let(:params) { {} }
+ let!(:active_personal_access_token) { create(:personal_access_token, user: user) }
+ let!(:expired_personal_access_token) { create(:personal_access_token, :expired, user: user) }
+ let!(:revoked_personal_access_token) { create(:personal_access_token, :revoked, user: user) }
+ let!(:active_impersonation_token) { create(:personal_access_token, :impersonation, user: user) }
+ let!(:expired_impersonation_token) { create(:personal_access_token, :expired, :impersonation, user: user) }
+ let!(:revoked_impersonation_token) { create(:personal_access_token, :revoked, :impersonation, user: user) }
+
+ subject { finder(params).execute }
+
+ describe 'without user' do
+ it do
+ is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token,
+ revoked_personal_access_token, expired_personal_access_token,
+ revoked_impersonation_token, expired_impersonation_token)
+ end
+
+ describe 'without impersonation' do
+ before { params[:impersonation] = false }
+
+ it { is_expected.to contain_exactly(active_personal_access_token, revoked_personal_access_token, expired_personal_access_token) }
+
+ describe 'with active state' do
+ before { params[:state] = 'active' }
+
+ it { is_expected.to contain_exactly(active_personal_access_token) }
+ end
+
+ describe 'with inactive state' do
+ before { params[:state] = 'inactive' }
+
+ it { is_expected.to contain_exactly(revoked_personal_access_token, expired_personal_access_token) }
+ end
+ end
+
+ describe 'with impersonation' do
+ before { params[:impersonation] = true }
+
+ it { is_expected.to contain_exactly(active_impersonation_token, revoked_impersonation_token, expired_impersonation_token) }
+
+ describe 'with active state' do
+ before { params[:state] = 'active' }
+
+ it { is_expected.to contain_exactly(active_impersonation_token) }
+ end
+
+ describe 'with inactive state' do
+ before { params[:state] = 'inactive' }
+
+ it { is_expected.to contain_exactly(revoked_impersonation_token, expired_impersonation_token) }
+ end
+ end
+
+ describe 'with active state' do
+ before { params[:state] = 'active' }
+
+ it { is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token) }
+ end
+
+ describe 'with inactive state' do
+ before { params[:state] = 'inactive' }
+
+ it do
+ is_expected.to contain_exactly(expired_personal_access_token, revoked_personal_access_token,
+ expired_impersonation_token, revoked_impersonation_token)
+ end
+ end
+
+ describe 'with id' do
+ subject { finder(params).find_by(id: active_personal_access_token.id) }
+
+ it { is_expected.to eq(active_personal_access_token) }
+
+ describe 'with impersonation' do
+ before { params[:impersonation] = true }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe 'with token' do
+ subject { finder(params).find_by(token: active_personal_access_token.token) }
+
+ it { is_expected.to eq(active_personal_access_token) }
+
+ describe 'with impersonation' do
+ before { params[:impersonation] = true }
+
+ it { is_expected.to be_nil }
+ end
+ end
+ end
+
+ describe 'with user' do
+ let(:user2) { create(:user) }
+ let!(:other_user_active_personal_access_token) { create(:personal_access_token, user: user2) }
+ let!(:other_user_expired_personal_access_token) { create(:personal_access_token, :expired, user: user2) }
+ let!(:other_user_revoked_personal_access_token) { create(:personal_access_token, :revoked, user: user2) }
+ let!(:other_user_active_impersonation_token) { create(:personal_access_token, :impersonation, user: user2) }
+ let!(:other_user_expired_impersonation_token) { create(:personal_access_token, :expired, :impersonation, user: user2) }
+ let!(:other_user_revoked_impersonation_token) { create(:personal_access_token, :revoked, :impersonation, user: user2) }
+
+ before { params[:user] = user }
+
+ it do
+ is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token,
+ revoked_personal_access_token, expired_personal_access_token,
+ revoked_impersonation_token, expired_impersonation_token)
+ end
+
+ describe 'without impersonation' do
+ before { params[:impersonation] = false }
+
+ it { is_expected.to contain_exactly(active_personal_access_token, revoked_personal_access_token, expired_personal_access_token) }
+
+ describe 'with active state' do
+ before { params[:state] = 'active' }
+
+ it { is_expected.to contain_exactly(active_personal_access_token) }
+ end
+
+ describe 'with inactive state' do
+ before { params[:state] = 'inactive' }
+
+ it { is_expected.to contain_exactly(revoked_personal_access_token, expired_personal_access_token) }
+ end
+ end
+
+ describe 'with impersonation' do
+ before { params[:impersonation] = true }
+
+ it { is_expected.to contain_exactly(active_impersonation_token, revoked_impersonation_token, expired_impersonation_token) }
+
+ describe 'with active state' do
+ before { params[:state] = 'active' }
+
+ it { is_expected.to contain_exactly(active_impersonation_token) }
+ end
+
+ describe 'with inactive state' do
+ before { params[:state] = 'inactive' }
+
+ it { is_expected.to contain_exactly(revoked_impersonation_token, expired_impersonation_token) }
+ end
+ end
+
+ describe 'with active state' do
+ before { params[:state] = 'active' }
+
+ it { is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token) }
+ end
+
+ describe 'with inactive state' do
+ before { params[:state] = 'inactive' }
+
+ it do
+ is_expected.to contain_exactly(expired_personal_access_token, revoked_personal_access_token,
+ expired_impersonation_token, revoked_impersonation_token)
+ end
+ end
+
+ describe 'with id' do
+ subject { finder(params).find_by(id: active_personal_access_token.id) }
+
+ it { is_expected.to eq(active_personal_access_token) }
+
+ describe 'with impersonation' do
+ before { params[:impersonation] = true }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe 'with token' do
+ subject { finder(params).find_by(token: active_personal_access_token.token) }
+
+ it { is_expected.to eq(active_personal_access_token) }
+
+ describe 'with impersonation' do
+ before { params[:impersonation] = true }
+
+ it { is_expected.to be_nil }
+ end
+ end
+ end
+ end
+end
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
index 594b40303bc..81ba693f2f3 100644
--- a/spec/helpers/events_helper_spec.rb
+++ b/spec/helpers/events_helper_spec.rb
@@ -61,6 +61,13 @@ describe EventsHelper do
'</code></pre>'
expect(helper.event_note(input)).to eq(expected)
end
+
+ it 'preserves style attribute within a tag' do
+ input = '<span class="" style="background-color: #44ad8e; color: #FFFFFF;"></span>'
+ expected = '<p><span style="background-color: #44ad8e; color: #FFFFFF;"></span></p>'
+
+ expect(helper.event_note(input)).to eq(expected)
+ end
end
describe '#event_commit_title' do
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index 0609ca78b3c..03c4879ed6f 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -136,25 +136,37 @@ describe Gitlab::Auth, lib: true do
end
context 'while using personal access tokens as passwords' do
- let(:user) { create(:user) }
- let(:token_w_api_scope) { create(:personal_access_token, user: user, scopes: ['api']) }
-
it 'succeeds for personal access tokens with the `api` scope' do
- expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: user.email)
- expect(gl_auth.find_for_git_client(user.email, token_w_api_scope.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :personal_token, full_authentication_abilities))
+ personal_access_token = create(:personal_access_token, scopes: ['api'])
+
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '')
+ expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(personal_access_token.user, nil, :personal_token, full_authentication_abilities))
+ end
+
+ it 'succeeds if it is an impersonation token' do
+ impersonation_token = create(:personal_access_token, :impersonation, scopes: ['api'])
+
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '')
+ expect(gl_auth.find_for_git_client('', impersonation_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(impersonation_token.user, nil, :personal_token, full_authentication_abilities))
end
it 'fails for personal access tokens with other scopes' do
- personal_access_token = create(:personal_access_token, user: user, scopes: ['read_user'])
+ personal_access_token = create(:personal_access_token, scopes: ['read_user'])
- expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: user.email)
- expect(gl_auth.find_for_git_client(user.email, personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: '')
+ expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
end
- it 'does not try password auth before personal access tokens' do
- expect(gl_auth).not_to receive(:find_with_user_password)
+ it 'fails for impersonation token with other scopes' do
+ impersonation_token = create(:personal_access_token, scopes: ['read_user'])
+
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: '')
+ expect(gl_auth.find_for_git_client('', impersonation_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
+ end
- gl_auth.find_for_git_client(user.email, token_w_api_scope.token, project: nil, ip: 'ip')
+ it 'fails if password is nil' do
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: '')
+ expect(gl_auth.find_for_git_client('', nil, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
end
end
diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb
index 50f61ec18fd..823623d96fa 100644
--- a/spec/models/personal_access_token_spec.rb
+++ b/spec/models/personal_access_token_spec.rb
@@ -1,15 +1,37 @@
require 'spec_helper'
describe PersonalAccessToken, models: true do
- describe ".generate" do
- it "generates a random token" do
- personal_access_token = PersonalAccessToken.generate({})
- expect(personal_access_token.token).to be_present
+ describe '.build' do
+ let(:personal_access_token) { build(:personal_access_token) }
+ let(:invalid_personal_access_token) { build(:personal_access_token, :invalid) }
+
+ it 'is a valid personal access token' do
+ expect(personal_access_token).to be_valid
+ end
+
+ it 'ensures that the token is generated' do
+ invalid_personal_access_token.save!
+
+ expect(invalid_personal_access_token).to be_valid
+ expect(invalid_personal_access_token.token).not_to be_nil
+ end
+ end
+
+ describe ".active?" do
+ let(:active_personal_access_token) { build(:personal_access_token) }
+ let(:revoked_personal_access_token) { build(:personal_access_token, :revoked) }
+ let(:expired_personal_access_token) { build(:personal_access_token, :expired) }
+
+ it "returns false if the personal_access_token is revoked" do
+ expect(revoked_personal_access_token).not_to be_active
+ end
+
+ it "returns false if the personal_access_token is expired" do
+ expect(expired_personal_access_token).not_to be_active
end
- it "doesn't save the record" do
- personal_access_token = PersonalAccessToken.generate({})
- expect(personal_access_token).not_to be_persisted
+ it "returns true if the personal_access_token is not revoked and not expired" do
+ expect(active_personal_access_token).to be_active
end
end
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 881c48c75e0..04e7837fd7a 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -10,6 +10,8 @@ describe API::Users, api: true do
let(:omniauth_user) { create(:omniauth_user) }
let(:ldap_user) { create(:omniauth_user, provider: 'ldapmain') }
let(:ldap_blocked_user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') }
+ let(:not_existing_user_id) { (User.maximum('id') || 0 ) + 10 }
+ let(:not_existing_pat_id) { (PersonalAccessToken.maximum('id') || 0 ) + 10 }
describe "GET /users" do
context "when unauthenticated" do
@@ -1155,4 +1157,187 @@ describe API::Users, api: true do
expect(json_response['message']).to eq('404 User Not Found')
end
end
+
+ describe 'GET /users/:user_id/impersonation_tokens' do
+ let!(:active_personal_access_token) { create(:personal_access_token, user: user) }
+ let!(:revoked_personal_access_token) { create(:personal_access_token, :revoked, user: user) }
+ let!(:expired_personal_access_token) { create(:personal_access_token, :expired, user: user) }
+ let!(:impersonation_token) { create(:personal_access_token, :impersonation, user: user) }
+ let!(:revoked_impersonation_token) { create(:personal_access_token, :impersonation, :revoked, user: user) }
+
+ it 'returns a 404 error if user not found' do
+ get api("/users/#{not_existing_user_id}/impersonation_tokens", admin)
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 User Not Found')
+ end
+
+ it 'returns a 403 error when authenticated as normal user' do
+ get api("/users/#{not_existing_user_id}/impersonation_tokens", user)
+
+ expect(response).to have_http_status(403)
+ expect(json_response['message']).to eq('403 Forbidden')
+ end
+
+ it 'returns an array of all impersonated tokens' do
+ get api("/users/#{user.id}/impersonation_tokens", admin)
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(2)
+ end
+
+ it 'returns an array of active impersonation tokens if state active' do
+ get api("/users/#{user.id}/impersonation_tokens?state=active", admin)
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(1)
+ expect(json_response).to all(include('active' => true))
+ end
+
+ it 'returns an array of inactive personal access tokens if active is set to false' do
+ get api("/users/#{user.id}/impersonation_tokens?state=inactive", admin)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(1)
+ expect(json_response).to all(include('active' => false))
+ end
+ end
+
+ describe 'POST /users/:user_id/impersonation_tokens' do
+ let(:name) { 'my new pat' }
+ let(:expires_at) { '2016-12-28' }
+ let(:scopes) { %w(api read_user) }
+ let(:impersonation) { true }
+
+ it 'returns validation error if impersonation token misses some attributes' do
+ post api("/users/#{user.id}/impersonation_tokens", admin)
+
+ expect(response).to have_http_status(400)
+ expect(json_response['error']).to eq('name is missing')
+ end
+
+ it 'returns a 404 error if user not found' do
+ post api("/users/#{not_existing_user_id}/impersonation_tokens", admin),
+ name: name,
+ expires_at: expires_at
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 User Not Found')
+ end
+
+ it 'returns a 403 error when authenticated as normal user' do
+ post api("/users/#{user.id}/impersonation_tokens", user),
+ name: name,
+ expires_at: expires_at
+
+ expect(response).to have_http_status(403)
+ expect(json_response['message']).to eq('403 Forbidden')
+ end
+
+ it 'creates a impersonation token' do
+ post api("/users/#{user.id}/impersonation_tokens", admin),
+ name: name,
+ expires_at: expires_at,
+ scopes: scopes,
+ impersonation: impersonation
+
+ expect(response).to have_http_status(201)
+ expect(json_response['name']).to eq(name)
+ expect(json_response['scopes']).to eq(scopes)
+ expect(json_response['expires_at']).to eq(expires_at)
+ expect(json_response['id']).to be_present
+ expect(json_response['created_at']).to be_present
+ expect(json_response['active']).to be_falsey
+ expect(json_response['revoked']).to be_falsey
+ expect(json_response['token']).to be_present
+ expect(json_response['impersonation']).to eq(impersonation)
+ end
+ end
+
+ describe 'GET /users/:user_id/impersonation_tokens/:impersonation_token_id' do
+ let!(:personal_access_token) { create(:personal_access_token, user: user) }
+ let!(:impersonation_token) { create(:personal_access_token, :impersonation, user: user) }
+
+ it 'returns 404 error if user not found' do
+ get api("/users/#{not_existing_user_id}/impersonation_tokens/1", admin)
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 User Not Found')
+ end
+
+ it 'returns a 404 error if impersonation token not found' do
+ get api("/users/#{user.id}/impersonation_tokens/#{not_existing_pat_id}", admin)
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Impersonation Token Not Found')
+ end
+
+ it 'returns a 404 error if token is not impersonation token' do
+ get api("/users/#{user.id}/impersonation_tokens/#{personal_access_token.id}", admin)
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Impersonation Token Not Found')
+ end
+
+ it 'returns a 403 error when authenticated as normal user' do
+ get api("/users/#{user.id}/impersonation_tokens/#{impersonation_token.id}", user)
+
+ expect(response).to have_http_status(403)
+ expect(json_response['message']).to eq('403 Forbidden')
+ end
+
+ it 'returns a personal access token' do
+ get api("/users/#{user.id}/impersonation_tokens/#{impersonation_token.id}", admin)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['token']).to be_present
+ expect(json_response['impersonation']).to be_truthy
+ end
+ end
+
+ describe 'DELETE /users/:user_id/impersonation_tokens/:impersonation_token_id' do
+ let!(:personal_access_token) { create(:personal_access_token, user: user) }
+ let!(:impersonation_token) { create(:personal_access_token, :impersonation, user: user) }
+
+ it 'returns a 404 error if user not found' do
+ delete api("/users/#{not_existing_user_id}/impersonation_tokens/1", admin)
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 User Not Found')
+ end
+
+ it 'returns a 404 error if impersonation token not found' do
+ delete api("/users/#{user.id}/impersonation_tokens/#{not_existing_pat_id}", admin)
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Impersonation Token Not Found')
+ end
+
+ it 'returns a 404 error if token is not impersonation token' do
+ delete api("/users/#{user.id}/impersonation_tokens/#{personal_access_token.id}", admin)
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Impersonation Token Not Found')
+ end
+
+ it 'returns a 403 error when authenticated as normal user' do
+ delete api("/users/#{user.id}/impersonation_tokens/#{impersonation_token.id}", user)
+
+ expect(response).to have_http_status(403)
+ expect(json_response['message']).to eq('403 Forbidden')
+ end
+
+ it 'revokes a impersonation token' do
+ delete api("/users/#{user.id}/impersonation_tokens/#{impersonation_token.id}", admin)
+
+ expect(response).to have_http_status(204)
+ expect(impersonation_token.revoked).to be_falsey
+ expect(impersonation_token.reload.revoked).to be_truthy
+ end
+ end
end