Path: blob/main/components/gitpod-db/go/personal_access_token_test.go
2498 views
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.1// Licensed under the GNU Affero General Public License (AGPL).2// See License.AGPL.txt in the project root for license information.34package db_test56import (7"context"8"strconv"9"testing"10"time"1112db "github.com/gitpod-io/gitpod/components/gitpod-db/go"13"github.com/gitpod-io/gitpod/components/gitpod-db/go/dbtest"14"github.com/google/uuid"15"github.com/stretchr/testify/require"16)1718func TestPersonalAccessToken_Get(t *testing.T) {19conn := dbtest.ConnectForTests(t)2021firstUserId := uuid.New()22secondUserId := uuid.New()2324token := dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{UserID: firstUserId})25token2 := dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{UserID: secondUserId})2627tokenEntries := []db.PersonalAccessToken{token, token2}2829dbtest.CreatePersonalAccessTokenRecords(t, conn, tokenEntries...)3031t.Run("nil token ID is rejected", func(t *testing.T) {32_, err := db.GetPersonalAccessTokenForUser(context.Background(), conn, uuid.Nil, token.UserID)33require.Error(t, err)34})3536t.Run("nil user ID is rejected", func(t *testing.T) {37_, err := db.GetPersonalAccessTokenForUser(context.Background(), conn, token.ID, uuid.Nil)38require.Error(t, err)39})4041t.Run("not matching user", func(t *testing.T) {42_, err := db.GetPersonalAccessTokenForUser(context.Background(), conn, token.ID, token2.UserID)43require.Error(t, err, db.ErrorNotFound)44})4546t.Run("not matching token", func(t *testing.T) {47_, err := db.GetPersonalAccessTokenForUser(context.Background(), conn, token2.ID, token.UserID)48require.Error(t, err, db.ErrorNotFound)49})5051t.Run("both token and user don't exist in the DB", func(t *testing.T) {52_, err := db.GetPersonalAccessTokenForUser(context.Background(), conn, uuid.New(), uuid.New())53require.Error(t, err, db.ErrorNotFound)54})5556t.Run("valid", func(t *testing.T) {57returned, err := db.GetPersonalAccessTokenForUser(context.Background(), conn, token.ID, token.UserID)58require.NoError(t, err)59require.Equal(t, token.ID, returned.ID)60require.Equal(t, token.UserID, returned.UserID)61})6263}6465func TestPersonalAccessToken_Create(t *testing.T) {66conn := dbtest.ConnectForTests(t)6768request := db.PersonalAccessToken{69ID: uuid.New(),70UserID: uuid.New(),71Hash: "another-secure-hash",72Name: "another-name",73Scopes: []string{"read", "write"},74ExpirationTime: time.Now().Add(5),75CreatedAt: time.Now(),76LastModified: time.Now(),77}7879result, err := db.CreatePersonalAccessToken(context.Background(), conn, request)80require.NoError(t, err)8182require.Equal(t, request.ID, result.ID)83}8485func TestPersonalAccessToken_UpdateHash(t *testing.T) {86conn := dbtest.ConnectForTests(t)8788firstUserId := uuid.New()89secondUserId := uuid.New()9091token := dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{UserID: firstUserId})92token2 := dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{UserID: secondUserId})9394tokenEntries := []db.PersonalAccessToken{token, token2}9596dbtest.CreatePersonalAccessTokenRecords(t, conn, tokenEntries...)9798var newHash = "another-secure-hash"99var newExpirationTime = time.Now().Add(24 * time.Hour).UTC().Truncate(time.Millisecond)100101t.Run("not matching user", func(t *testing.T) {102_, err := db.UpdatePersonalAccessTokenHash(context.Background(), conn, token.ID, token2.UserID, newHash, newExpirationTime)103require.Error(t, err, db.ErrorNotFound)104})105106t.Run("not matching token", func(t *testing.T) {107_, err := db.UpdatePersonalAccessTokenHash(context.Background(), conn, token2.ID, token.UserID, newHash, newExpirationTime)108require.Error(t, err, db.ErrorNotFound)109})110111t.Run("both token and user don't exist in the DB", func(t *testing.T) {112_, err := db.UpdatePersonalAccessTokenHash(context.Background(), conn, uuid.New(), uuid.New(), newHash, newExpirationTime)113require.Error(t, err, db.ErrorNotFound)114})115116t.Run("valid", func(t *testing.T) {117returned, err := db.UpdatePersonalAccessTokenHash(context.Background(), conn, token.ID, token.UserID, newHash, newExpirationTime)118require.NoError(t, err)119require.Equal(t, token.ID, returned.ID)120require.Equal(t, token.UserID, returned.UserID)121require.Equal(t, newHash, returned.Hash)122require.Equal(t, token.Name, returned.Name)123require.Equal(t, token.Scopes, returned.Scopes)124require.Equal(t, newExpirationTime, returned.ExpirationTime)125require.Equal(t, token.CreatedAt, returned.CreatedAt)126})127}128129func TestPersonalAccessToken_Delete(t *testing.T) {130conn := dbtest.ConnectForTests(t)131132firstUserId := uuid.New()133secondUserId := uuid.New()134135token := dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{UserID: firstUserId})136token2 := dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{UserID: secondUserId})137138tokenEntries := []db.PersonalAccessToken{token, token2}139140dbtest.CreatePersonalAccessTokenRecords(t, conn, tokenEntries...)141142t.Run("not matching user", func(t *testing.T) {143count, err := db.DeletePersonalAccessTokenForUser(context.Background(), conn, token.ID, token2.UserID)144require.Error(t, err, db.ErrorNotFound)145require.Equal(t, int64(0), count)146})147148t.Run("not matching token", func(t *testing.T) {149count, err := db.DeletePersonalAccessTokenForUser(context.Background(), conn, token2.ID, token.UserID)150require.Error(t, err, db.ErrorNotFound)151require.Equal(t, int64(0), count)152})153154t.Run("both token and user don't exist in the DB", func(t *testing.T) {155count, err := db.DeletePersonalAccessTokenForUser(context.Background(), conn, uuid.New(), uuid.New())156require.Error(t, err, db.ErrorNotFound)157require.Equal(t, int64(0), count)158})159160t.Run("valid", func(t *testing.T) {161count, err := db.DeletePersonalAccessTokenForUser(context.Background(), conn, token.ID, token.UserID)162require.NoError(t, err)163require.Equal(t, int64(1), count)164_, err = db.GetPersonalAccessTokenForUser(context.Background(), conn, token.ID, token.UserID)165require.Error(t, err, db.ErrorNotFound)166})167}168169func TestListPersonalAccessTokensForUser(t *testing.T) {170ctx := context.Background()171conn := dbtest.ConnectForTests(t)172pagination := db.Pagination{173Page: 1,174PageSize: 10,175}176177userA := uuid.New()178userB := uuid.New()179180now := time.Now().UTC()181182dbtest.CreatePersonalAccessTokenRecords(t, conn,183dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{184UserID: userA,185CreatedAt: now.Add(-1 * time.Minute),186}),187dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{188UserID: userA,189CreatedAt: now,190}),191dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{192UserID: userB,193}),194)195196tokensForUserA, err := db.ListPersonalAccessTokensForUser(ctx, conn, userA, pagination)197require.NoError(t, err)198require.Len(t, tokensForUserA.Results, 2)199200tokensForUserB, err := db.ListPersonalAccessTokensForUser(ctx, conn, userB, pagination)201require.NoError(t, err)202require.Len(t, tokensForUserB.Results, 1)203204tokensForUserWithNoData, err := db.ListPersonalAccessTokensForUser(ctx, conn, uuid.New(), pagination)205require.NoError(t, err)206require.Len(t, tokensForUserWithNoData.Results, 0)207}208209func TestListPersonalAccessTokens_DeletedTokensAreNotListed(t *testing.T) {210conn := dbtest.ConnectForTests(t)211212token := dbtest.CreatePersonalAccessTokenRecords(t, conn,213dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{}),214)[0]215216_, err := db.DeletePersonalAccessTokenForUser(context.Background(), conn, token.ID, token.UserID)217require.NoError(t, err)218219listed, err := db.ListPersonalAccessTokensForUser(context.Background(), conn, token.UserID, db.Pagination{220Page: 1,221PageSize: 10,222})223require.NoError(t, err)224require.Empty(t, listed.Results)225require.EqualValues(t, 0, listed.Total)226}227228func TestListPersonalAccessTokensForUser_PaginateThroughResults(t *testing.T) {229ctx := context.Background()230conn := dbtest.ConnectForTests(t).Debug()231232userA := uuid.New()233234total := 11235var toCreate []db.PersonalAccessToken236for i := 0; i < total; i++ {237toCreate = append(toCreate, dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{238UserID: userA,239Name: strconv.Itoa(i),240}))241}242243dbtest.CreatePersonalAccessTokenRecords(t, conn, toCreate...)244245batch1, err := db.ListPersonalAccessTokensForUser(ctx, conn, userA, db.Pagination{246Page: 1,247PageSize: 5,248})249require.NoError(t, err)250require.Len(t, batch1.Results, 5)251require.EqualValues(t, batch1.Total, total)252253batch2, err := db.ListPersonalAccessTokensForUser(ctx, conn, userA, db.Pagination{254Page: 2,255PageSize: 5,256})257require.NoError(t, err)258require.Len(t, batch2.Results, 5)259require.EqualValues(t, batch2.Total, total)260261batch3, err := db.ListPersonalAccessTokensForUser(ctx, conn, userA, db.Pagination{262Page: 3,263PageSize: 5,264})265require.NoError(t, err)266require.Len(t, batch3.Results, 1)267require.EqualValues(t, batch3.Total, total)268}269270func TestUpdatePersonalAccessTokenForUser(t *testing.T) {271272newName := "second"273newScopes := db.Scopes([]string{})274275t.Run("not found when record does not exist", func(t *testing.T) {276conn := dbtest.ConnectForTests(t)277278_, err := db.UpdatePersonalAccessTokenForUser(context.Background(), conn, db.UpdatePersonalAccessTokenOpts{279TokenID: uuid.New(),280UserID: uuid.New(),281Name: &newName,282})283require.Error(t, err)284require.ErrorIs(t, err, db.ErrorNotFound)285})286287t.Run("no modified field completes gracefully", func(t *testing.T) {288conn := dbtest.ConnectForTests(t)289name := "first"290291created := dbtest.CreatePersonalAccessTokenRecords(t, conn, dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{292Name: name,293}))[0]294295udpated, err := db.UpdatePersonalAccessTokenForUser(context.Background(), conn, db.UpdatePersonalAccessTokenOpts{296TokenID: created.ID,297UserID: created.UserID,298Name: &name,299})300require.NoError(t, err)301require.Equal(t, name, udpated.Name)302require.Len(t, udpated.Scopes, 0)303})304305t.Run("no update when all options are nil", func(t *testing.T) {306conn := dbtest.ConnectForTests(t)307308created := dbtest.CreatePersonalAccessTokenRecords(t, conn, dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{309Name: "first",310}))[0]311312udpated, err := db.UpdatePersonalAccessTokenForUser(context.Background(), conn, db.UpdatePersonalAccessTokenOpts{313TokenID: created.ID,314UserID: created.UserID,315})316require.NoError(t, err)317require.Equal(t, created, udpated)318})319320t.Run("updates name when it is not nil", func(t *testing.T) {321conn := dbtest.ConnectForTests(t)322323created := dbtest.CreatePersonalAccessTokenRecords(t, conn, dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{324Name: "first",325}))[0]326327udpated, err := db.UpdatePersonalAccessTokenForUser(context.Background(), conn, db.UpdatePersonalAccessTokenOpts{328TokenID: created.ID,329UserID: created.UserID,330Name: &newName,331})332require.NoError(t, err)333require.Equal(t, newName, udpated.Name)334require.Equal(t, created.Scopes, udpated.Scopes)335})336337t.Run("updates scopes when it is not nil", func(t *testing.T) {338conn := dbtest.ConnectForTests(t)339340created := dbtest.CreatePersonalAccessTokenRecords(t, conn, dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{341Name: "first",342Scopes: db.Scopes([]string{"foo"}),343}))[0]344345udpated, err := db.UpdatePersonalAccessTokenForUser(context.Background(), conn, db.UpdatePersonalAccessTokenOpts{346TokenID: created.ID,347UserID: created.UserID,348Scopes: &newScopes,349})350require.NoError(t, err)351require.Equal(t, created.Name, udpated.Name)352require.Len(t, udpated.Scopes, len(newScopes))353})354}355356357