Skip to content

[usage] Fix flakes by deleting records created by each test, not deleting all #10971

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions components/usage/pkg/controller/reconciler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,10 @@ func TestUsageReconciler_ReconcileTimeRange(t *testing.T) {

for _, scenario := range scenarios {
t.Run(scenario.Name, func(t *testing.T) {
conn := db.ConnectForTests(t)
conn := dbtest.ConnectForTests(t)
require.NoError(t, conn.Create(scenario.Memberships).Error)
require.NoError(t, conn.Create(scenario.Workspaces).Error)
require.NoError(t, conn.Create(scenario.Instances).Error)
dbtest.CreateWorkspaces(t, conn, scenario.Workspaces...)
dbtest.CreateWorkspaceInstances(t, conn, scenario.Instances...)

reconciler := &UsageReconciler{
billingController: &NoOpBillingController{},
Expand Down
38 changes: 0 additions & 38 deletions components/usage/pkg/db/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ import (
"github.com/gitpod-io/gitpod/common-go/log"
driver_mysql "github.com/go-sql-driver/mysql"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"testing"
"time"
)

Expand Down Expand Up @@ -58,39 +56,3 @@ func Connect(p ConnectionParams) (*gorm.DB, error) {
}),
})
}

func ConnectForTests(t *testing.T) *gorm.DB {
t.Helper()

// These are static connection details for tests, started by `leeway components/usage:init-testdb`.
// We use the same static credentials for CI & local instance of MySQL Server.
conn, err := Connect(ConnectionParams{
User: "root",
Password: "test",
Host: "localhost:23306",
Database: "gitpod",
})
require.NoError(t, err, "Failed to establish connection to DB. In a workspace, run `leeway build components/usage:init-testdb` once to bootstrap the DB.")

t.Cleanup(func() {
// Delete records for known models from the DB
log.Info("Cleaning up DB between connections.")
for _, model := range []interface{}{
&WorkspaceInstance{},
&Workspace{},
&Project{},
&Team{},
&TeamMembership{},
} {
// See https://gorm.io/docs/delete.html#Block-Global-Delete
tx := conn.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(model)
require.NoError(t, tx.Error)
}

rawConn, err := conn.DB()
require.NoError(t, err)
require.NoError(t, rawConn.Close(), "must close database connection")
})

return conn
}
16 changes: 0 additions & 16 deletions components/usage/pkg/db/conn_test.go

This file was deleted.

42 changes: 42 additions & 0 deletions components/usage/pkg/db/dbtest/conn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License-AGPL.txt in the project root for license information.

package dbtest

import (
"github.com/gitpod-io/gitpod/usage/pkg/db"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
"sync"
"testing"
)

var (
connLock = sync.Mutex{}
conn *gorm.DB
)

func ConnectForTests(t *testing.T) *gorm.DB {
t.Helper()

connLock.Lock()
defer connLock.Unlock()

if conn != nil {
return conn
}

// These are static connection details for tests, started by `leeway components/usage:init-testdb`.
// We use the same static credentials for CI & local instance of MySQL Server.
var err error
conn, err = db.Connect(db.ConnectionParams{
User: "root",
Password: "test",
Host: "localhost:23306",
Database: "gitpod",
})
require.NoError(t, err, "Failed to establish connection to DB. In a workspace, run `leeway build components/usage:init-testdb` once to bootstrap the DB.")

return conn
}
30 changes: 21 additions & 9 deletions components/usage/pkg/db/dbtest/workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
package dbtest

import (
"fmt"
"github.com/gitpod-io/gitpod/common-go/namegen"
"github.com/gitpod-io/gitpod/usage/pkg/db"
"github.com/google/uuid"
"math/rand"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
"testing"
)

Expand Down Expand Up @@ -64,15 +65,26 @@ func NewWorkspace(t *testing.T, workspace db.Workspace) db.Workspace {
}

func GenerateWorkspaceID() string {
return fmt.Sprintf("gitpodio-gitpod-%s", randSeq(11))
id, _ := namegen.GenerateWorkspaceID()
return id
}

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
func CreateWorkspaces(t *testing.T, conn *gorm.DB, workspaces ...db.Workspace) []db.Workspace {
t.Helper()

func randSeq(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
var records []db.Workspace
var ids []string
for _, w := range workspaces {
record := NewWorkspace(t, w)
records = append(records, record)
ids = append(ids, record.ID)
}
return string(b)

require.NoError(t, conn.CreateInBatches(&records, 1000).Error)

t.Cleanup(func() {
require.NoError(t, conn.Where(ids).Delete(&db.Workspace{}).Error)
})

return records
}
22 changes: 22 additions & 0 deletions components/usage/pkg/db/dbtest/workspace_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"database/sql"
"github.com/gitpod-io/gitpod/usage/pkg/db"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
"testing"
"time"
)
Expand Down Expand Up @@ -87,3 +89,23 @@ func NewWorkspaceInstance(t *testing.T, instance db.WorkspaceInstance) db.Worksp
PhasePersisted: "",
}
}

func CreateWorkspaceInstances(t *testing.T, conn *gorm.DB, instances ...db.WorkspaceInstance) []db.WorkspaceInstance {
t.Helper()

var records []db.WorkspaceInstance
var ids []string
for _, instance := range instances {
record := NewWorkspaceInstance(t, instance)
records = append(records, record)
ids = append(ids, record.ID.String())
}

require.NoError(t, conn.CreateInBatches(&records, 1000).Error)

t.Cleanup(func() {
require.NoError(t, conn.Where(ids).Delete(&db.WorkspaceInstance{}).Error)
})

return records
}
6 changes: 4 additions & 2 deletions components/usage/pkg/db/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package db_test
import (
"fmt"
"github.com/gitpod-io/gitpod/usage/pkg/db"
"github.com/gitpod-io/gitpod/usage/pkg/db/dbtest"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
Expand All @@ -15,7 +16,7 @@ import (
)

var projectJSON = map[string]interface{}{
"id": "49b5d309-bb95-4a79-846c-e3cf42c0d591",
"id": uuid.New().String(),
"cloneUrl": "https://github.com/gptest1/gptest1-repo1-private.git",
"teamId": "0e433063-1358-4892-9ed2-68e273d17d07",
"appInstallationId": "20446411",
Expand All @@ -31,7 +32,7 @@ var projectJSON = map[string]interface{}{
}

func TestProject_ReadExistingRecords(t *testing.T) {
conn := db.ConnectForTests(t)
conn := dbtest.ConnectForTests(t)

id := insertRawProject(t, conn, projectJSON)

Expand All @@ -42,6 +43,7 @@ func TestProject_ReadExistingRecords(t *testing.T) {
require.Equal(t, id, project.ID)
require.Equal(t, projectJSON["teamId"], project.TeamID.String)
require.Equal(t, stringToVarchar(t, "2021-11-01T19:36:07.532Z"), project.CreationTime)
require.NoError(t, conn.Where("id = ?", project.ID).Delete(&db.Project{}).Error)
}

func insertRawProject(t *testing.T, conn *gorm.DB, obj map[string]interface{}) uuid.UUID {
Expand Down
5 changes: 3 additions & 2 deletions components/usage/pkg/db/team_membership_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ package db_test
import (
"context"
"github.com/gitpod-io/gitpod/usage/pkg/db"
"github.com/gitpod-io/gitpod/usage/pkg/db/dbtest"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"testing"
)

func TestTeamMembership_WriteRead(t *testing.T) {
conn := db.ConnectForTests(t)
conn := dbtest.ConnectForTests(t)

membership := &db.TeamMembership{
ID: uuid.New(),
Expand All @@ -33,7 +34,7 @@ func TestTeamMembership_WriteRead(t *testing.T) {
}

func TestListTeamMembershipsForUserIDs(t *testing.T) {
conn := db.ConnectForTests(t)
conn := dbtest.ConnectForTests(t)
userWithTwoTeams := uuid.New()
memberships := []db.TeamMembership{
{
Expand Down
56 changes: 0 additions & 56 deletions components/usage/pkg/db/team_test.go

This file was deleted.

41 changes: 0 additions & 41 deletions components/usage/pkg/db/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package db

import (
"github.com/stretchr/testify/require"
"gorm.io/gorm"
"testing"
"time"
)
Expand Down Expand Up @@ -116,43 +115,3 @@ func TestVarcharTime_String_ISO8601(t *testing.T) {
require.Equal(t, scenario.Expected, scenario.Time.String())
}
}

func TestVarcharTime_SerializeAndDeserialize(t *testing.T) {
// Custom table to be able to exercise serialization easily, independent of other models
type VarcharModel struct {
ID int `gorm:"primaryKey"`
Time VarcharTime `gorm:"column:time;type:varchar(255);"`
}

conn := ConnectForTests(t)
require.NoError(t, conn.AutoMigrate(&VarcharModel{}))

conn.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&VarcharModel{})

for _, scenario := range []struct {
Description string
Input VarcharModel
Expected VarcharModel
}{
{
Description: "empty value for VarcharTime",
Input: VarcharModel{
ID: 1,
Time: VarcharTime{},
},
Expected: VarcharModel{
ID: 1,
Time: VarcharTime{},
},
},
} {
tx := conn.Create(scenario.Input)
require.NoError(t, tx.Error)

var read VarcharModel
tx = conn.First(&read, scenario.Input.ID)
require.NoError(t, tx.Error)

require.Equal(t, scenario.Expected, read)
}
}
Loading