mirror of
https://github.com/harness/drone.git
synced 2025-05-07 02:30:08 +08:00

This change adds the following: - Space UID + Custom harness validation (accountId for top level space, harness identifier for child spaces) - Repo UID + Custom harness validation (harness identifier) - Store Unique casing of space / repo path and add Path.ValueUnique (with Unique index) to allow for application layer controlling the case sensitivity (case insensitive standalone vs partially case sensitive harness) - Token UID (unique index over ownertype + ownerID + tokenUID) - Add DisplayName for principals (replaces Name to avoid confustion) - Store Unique casing of principal UID and add Principal.ValueUnique (with unique index) to allow for application layer, per principal type control of case sensitivity (required in embedded mode) - Generate serviceAccount UID (+Email) Randomly (sa-{space|repo}-{ID}-{random}) - Allows to have a unique UID across all principals while reducing likelyhood of overlaps with users + avoid overlap across spaces / repos. - Sync casing of space names (accountId orgId projectId) when creating spaces on the fly (to ensure case sensitivity of - harness code) or use the existing space to update casing. - Update serviceaccount client to match updated NG Manager API - in embedded mode create spaces for harness resources owning the service account
253 lines
6.1 KiB
Go
253 lines
6.1 KiB
Go
// Copyright 2022 Harness Inc. All rights reserved.
|
|
// Use of this source code is governed by the Polyform Free Trial License
|
|
// that can be found in the LICENSE.md file for this repository.
|
|
|
|
package database
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/jmoiron/sqlx"
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/harness/gitness/internal/store"
|
|
"github.com/harness/gitness/types"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
)
|
|
|
|
// user fields to ignore in test comparisons.
|
|
var userIgnore = cmpopts.IgnoreFields(types.User{},
|
|
"ID", "Salt", "Created", "Updated")
|
|
|
|
func TestUser(t *testing.T) {
|
|
db, err := connect()
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
defer func(db *sqlx.DB) {
|
|
_ = db.Close()
|
|
}(db)
|
|
if err = seed(db); err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
|
|
userStoreSync := NewUserStoreSync(NewUserStore(db, store.ToLowerPrincipalUIDTransformation))
|
|
t.Run("create", testUserCreate(userStoreSync))
|
|
t.Run("duplicate", testUserDuplicate(userStoreSync))
|
|
t.Run("count", testUserCount(userStoreSync))
|
|
t.Run("find", testUserFind(userStoreSync))
|
|
t.Run("list", testUserList(userStoreSync))
|
|
t.Run("update", testUserUpdate(userStoreSync))
|
|
t.Run("delete", testUserDelete(userStoreSync))
|
|
}
|
|
|
|
// this test creates entries in the database and confirms
|
|
// the primary keys were auto-incremented.
|
|
func testUserCreate(store store.UserStore) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
ctx := context.Background()
|
|
vv := []*types.User{}
|
|
if err := unmarshal("testdata/users.json", &vv); err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
// create row 1
|
|
v := vv[0]
|
|
// generate a deterministic token for each
|
|
// entry based on the hash of the email.
|
|
v.Salt = fmt.Sprintf("%x", v.Email)
|
|
if err := store.Create(ctx, v); err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if v.ID == 0 {
|
|
t.Errorf("Want autoincremented primary key")
|
|
}
|
|
// create row 2
|
|
v = vv[1]
|
|
v.Salt = fmt.Sprintf("%x", v.Email)
|
|
if err := store.Create(ctx, v); err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if v.ID == 0 {
|
|
t.Errorf("Want autoincremented primary key")
|
|
}
|
|
}
|
|
}
|
|
|
|
// this test attempts to create an entry in the database using
|
|
// a duplicate email to verify that unique email constraints are
|
|
// being enforced.
|
|
func testUserDuplicate(store store.UserStore) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
vv := []*types.User{}
|
|
if err := unmarshal("testdata/users.json", &vv); err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if err := store.Create(context.Background(), vv[0]); err == nil {
|
|
t.Errorf("Expect unique index violation")
|
|
}
|
|
}
|
|
}
|
|
|
|
// this test counts the number of users in the database
|
|
// and compares to the expected count.
|
|
func testUserCount(store store.UserStore) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
got, err := store.Count(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if want := int64(2); got != want {
|
|
t.Errorf("Want user count %d, got %d", want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
// this test fetches users from the database by id and key
|
|
// and compares to the expected results (sourced from a json file)
|
|
// to ensure all columns are correctly mapped.
|
|
//
|
|
//nolint:gocognit // test method, keep for now
|
|
func testUserFind(store store.UserStore) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
ctx := context.Background()
|
|
vv := []*types.User{}
|
|
if err := unmarshal("testdata/users.json", &vv); err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
want := vv[0]
|
|
|
|
t.Run("id", func(t *testing.T) {
|
|
got, err := store.Find(ctx, 1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if diff := cmp.Diff(got, want, userIgnore); len(diff) != 0 {
|
|
t.Errorf(diff)
|
|
return
|
|
}
|
|
})
|
|
|
|
t.Run("uid", func(t *testing.T) {
|
|
got, err := store.FindUID(ctx, "jane21")
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if diff := cmp.Diff(got, want, userIgnore); len(diff) != 0 {
|
|
t.Errorf(diff)
|
|
return
|
|
}
|
|
})
|
|
|
|
t.Run("email", func(t *testing.T) {
|
|
got, err := store.FindEmail(ctx, want.Email)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if diff := cmp.Diff(got, want, userIgnore); len(diff) != 0 {
|
|
t.Errorf(diff)
|
|
return
|
|
}
|
|
})
|
|
|
|
t.Run("email/nocase", func(t *testing.T) {
|
|
got, err := store.FindEmail(ctx, strings.ToUpper(want.Email))
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if diff := cmp.Diff(got, want, userIgnore); len(diff) != 0 {
|
|
t.Errorf(diff)
|
|
return
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// this test fetches a list of users from the database
|
|
// and compares to the expected results (sourced from a json file)
|
|
// to ensure all columns are correctly mapped.
|
|
func testUserList(store store.UserStore) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
want := []*types.User{}
|
|
if err := unmarshal("testdata/users.json", &want); err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
got, err := store.List(context.Background(), &types.UserFilter{Page: 0, Size: 100})
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if diff := cmp.Diff(got, want, userIgnore); len(diff) != 0 {
|
|
t.Errorf(diff)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// this test updates an user in the database and then fetches
|
|
// the user and confirms the column was updated as expected.
|
|
func testUserUpdate(store store.UserStore) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
ctx := context.Background()
|
|
before, err := store.Find(ctx, 1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
before.Updated = time.Now().Unix()
|
|
if err = store.Update(ctx, before); err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
after, err := store.Find(ctx, 1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
|
|
if diff := cmp.Diff(before, after, userIgnore); len(diff) != 0 {
|
|
t.Errorf(diff)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// this test deletes an user from the database and then confirms
|
|
// subsequent attempts to fetch the deleted user result in
|
|
// a sql.ErrNoRows error.
|
|
func testUserDelete(s store.UserStore) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
ctx := context.Background()
|
|
_, err := s.Find(ctx, 1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if err = s.Delete(ctx, 1); err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if _, err = s.Find(ctx, 1); errors.Is(err, store.ErrResourceNotFound) {
|
|
t.Errorf("Expected sql.ErrNoRows got %s", err)
|
|
}
|
|
}
|
|
}
|