From d10aa731bc9f622fa9325e7adee1a7143cfda0bc Mon Sep 17 00:00:00 2001 From: SoXX Date: Wed, 14 Aug 2024 14:53:08 +0200 Subject: [PATCH] feat(test): added scopes fixed issues fully tested scopes. Also found bugs with the tests. Those are now fixed. --- pkg/database/client_test.go | 174 +++++++++++++++++++++++++++++ pkg/database/scopes.go | 2 +- pkg/database/scopes_test.go | 216 ++++++++++++++++++++++++++++++++++++ test/helper.go | 45 ++++++++ 4 files changed, 436 insertions(+), 1 deletion(-) create mode 100644 pkg/database/client_test.go create mode 100644 pkg/database/scopes_test.go diff --git a/pkg/database/client_test.go b/pkg/database/client_test.go new file mode 100644 index 0000000..f81c91f --- /dev/null +++ b/pkg/database/client_test.go @@ -0,0 +1,174 @@ +package database + +import ( + "context" + "testing" + + "git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models" + "git.anthrove.art/Anthrove/otter-space-sdk/v2/test" + "go.opentelemetry.io/contrib/bridges/otellogrus" + "go.opentelemetry.io/otel" + "gorm.io/gorm" +) + +func TestConnect(t *testing.T) { + // Setup trow away container + ctx := context.Background() + container, _, err := test.StartPostgresContainer(ctx) + if err != nil { + t.Fatalf("Could not start PostgreSQL container: %v", err) + } + + defer container.Terminate(ctx) + + // -- -- Setup Tests + + // -- Create Database config to test with + validDatabaseConfig, err := test.DatabaseModesFromConnectionString(ctx, container) + if err != nil { + t.Fatalf("Could not get valid database config: %v", err) + } + // -- + + // -- -- Tests + type args struct { + ctx context.Context + config models.DatabaseConfig + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "Test 01: Valid DatabaseConfig", + args: args{ + ctx: ctx, + config: validDatabaseConfig, + }, + wantErr: false, + }, + { + name: "Test 02: invalid DatabaseConfig", + args: args{ + ctx: ctx, + config: models.DatabaseConfig{}, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := Connect(tt.args.ctx, tt.args.config); (err != nil) != tt.wantErr { + t.Errorf("Connect() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestGetGorm(t *testing.T) { + // Setup trow away container + ctx := context.Background() + container, _, err := test.StartPostgresContainer(ctx) + if err != nil { + t.Fatalf("Could not start PostgreSQL container: %v", err) + } + + defer container.Terminate(ctx) + + // -- -- Setup Tests + + // -- Create Database config to test with + validDatabaseConfig, err := test.DatabaseModesFromConnectionString(ctx, container) + if err != nil { + t.Fatalf("Could not get valid database config: %v", err) + } + + err = Connect(ctx, validDatabaseConfig) + if err != nil { + t.Fatalf("Could not connect to valid database: %v", err) + } + // -- + + // -- -- Tests + type args struct { + ctx context.Context + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "Test 01: GetGorm", + args: args{ + ctx: ctx, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := GetGorm(tt.args.ctx) + if (err == nil) != !tt.wantErr { + t.Errorf("GetGorm() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func Test_migrateDatabase(t *testing.T) { + // Setup trow away container + ctx := context.Background() + container, gormDB, err := test.StartPostgresContainer(ctx) + if err != nil { + t.Fatalf("Could not start PostgreSQL container: %v", err) + } + + // Setup open telemetry + tracer = otel.Tracer(tracingName) + + hook := otellogrus.NewHook(tracingName) + logger.AddHook(hook) + + defer container.Terminate(ctx) + + // -- -- Setup Tests + + // -- Create Database config to test with + validDatabaseConfig, err := test.DatabaseModesFromConnectionString(ctx, container) + if err != nil { + t.Fatalf("Could not get valid database config: %v", err) + } + validDatabaseConfig.Debug = true + // -- + + // -- -- Tests + type args struct { + ctx context.Context + dbPool *gorm.DB + config models.DatabaseConfig + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "Test 01: MigrateDatabase", + args: args{ + ctx: ctx, + dbPool: gormDB, + config: validDatabaseConfig, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := migrateDatabase(tt.args.ctx, tt.args.dbPool, tt.args.config); (err != nil) != tt.wantErr { + t.Errorf("migrateDatabase() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/pkg/database/scopes.go b/pkg/database/scopes.go index 0161872..70c59a0 100644 --- a/pkg/database/scopes.go +++ b/pkg/database/scopes.go @@ -60,7 +60,7 @@ func AdvancedPagination(value any, pagination *Pagination, db *gorm.DB) func(db } if pagination.Sort == "" { - pagination.Sort = "Id desc" + pagination.Sort = "id desc" } switch { diff --git a/pkg/database/scopes_test.go b/pkg/database/scopes_test.go new file mode 100644 index 0000000..7ab5ed9 --- /dev/null +++ b/pkg/database/scopes_test.go @@ -0,0 +1,216 @@ +package database + +import ( + "context" + "reflect" + "testing" + + "git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models" + "git.anthrove.art/Anthrove/otter-space-sdk/v2/test" + "github.com/davecgh/go-spew/spew" + "go.opentelemetry.io/contrib/bridges/otellogrus" + "go.opentelemetry.io/otel" + "gorm.io/gorm" +) + +func TestPaginate(t *testing.T) { + // Setup trow away container + ctx := context.Background() + container, gormDB, err := test.StartPostgresContainer(ctx) + if err != nil { + logger.Fatalf("Could not start PostgreSQL container: %v", err) + } + + client = gormDB + + // Setup open telemetry + tracer = otel.Tracer(tracingName) + + hook := otellogrus.NewHook(tracingName) + logger.AddHook(hook) + + defer container.Terminate(ctx) + + // -- -- Setup Tests + + // -- Create Tags to test with + validTags := test.GenerateRandomTags(500) + err = CreateTagInBatch(ctx, validTags, len(validTags)) + if err != nil { + logger.Fatalf("Could not create tags: %v", err) + } + // -- + + // -- -- Tests + type args struct { + page int + pageSize int + } + tests := []struct { + name string + args args + want []models.Tag + }{ + { + name: "Test 01: Valid Page & PageSize", + args: args{ + page: 1, + pageSize: 5, + }, + want: validTags[:5], + }, + { + name: "Test 02: Second page with Valid Page & PageSize", + args: args{ + page: 2, + pageSize: 5, + }, + want: validTags[5:10], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var tags []models.Tag + result := client.WithContext(ctx).Scopes(Paginate(tt.args.page, tt.args.pageSize)).Find(&tags) + + if result.Error != nil { + t.Errorf("Paginate() = %v", result.Error) + } + + if !reflect.DeepEqual(tt.want, tags) { + t.Errorf("Length of tags: %d", len(tags)) + t.Errorf("Length of want: %d", len(tt.want)) + t.Errorf("Paginate() = %v, want %v", tags, tt.want) + } + + }) + } +} + +func TestAdvancedPagination(t *testing.T) { + // Setup trow away container + ctx := context.Background() + container, gormDB, err := test.StartPostgresContainer(ctx) + if err != nil { + logger.Fatalf("Could not start PostgreSQL container: %v", err) + } + + client = gormDB + + // Setup open telemetry + tracer = otel.Tracer(tracingName) + + hook := otellogrus.NewHook(tracingName) + logger.AddHook(hook) + + defer container.Terminate(ctx) + + // -- -- Setup Tests + + // -- Create Tags to test with + validTags := []models.Tag{ + { + Name: "a", + Type: models.General, + }, + { + Name: "b", + Type: models.General, + }, + { + Name: "c", + Type: models.Lore, + }, + { + Name: "d", + Type: models.Artist, + }, + { + Name: "e", + Type: models.Artist, + }, + { + Name: "f", + Type: models.Copyright, + }, + { + Name: "g", + Type: models.Meta, + }, + { + Name: "h", + Type: models.Species, + }, + { + Name: "i", + Type: models.Invalid, + }, + { + Name: "j", + Type: models.General, + }, + } + err = CreateTagInBatch(ctx, validTags, len(validTags)) + if err != nil { + logger.Fatalf("Could not create tags: %v", err) + } + // -- + + // -- -- Tests + type args struct { + value any + pagination *Pagination + db *gorm.DB + } + tests := []struct { + name string + args args + want []models.Tag + }{ + { + name: "Test 01: Valid Data", + args: args{ + value: validTags, + pagination: &Pagination{ + Limit: 5, + Page: 1, + Sort: "name asc", + }, + db: client, + }, + want: validTags[:5], + }, + { + name: "Test 02: Second page with Valid Data", + args: args{ + value: validTags, + pagination: &Pagination{ + Limit: 5, + Page: 2, + Sort: "name asc", + }, + db: client, + }, + want: validTags[5:10], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var tags []models.Tag + result := client.WithContext(ctx).Scopes(AdvancedPagination(tt.args.value, tt.args.pagination, tt.args.db)).Find(&tags) + + spew.Dump(tt.args.pagination) + + if result.Error != nil { + t.Errorf("Paginate() = %v", result.Error) + } + + if !reflect.DeepEqual(tt.want, tags) { + t.Errorf("Length of tags: %d", len(tags)) + t.Errorf("Length of want: %d", len(tt.want)) + t.Errorf("Paginate() = %v, want %v", tags, tt.want) + } + + }) + } +} diff --git a/test/helper.go b/test/helper.go index da9d4f3..2ef87e3 100644 --- a/test/helper.go +++ b/test/helper.go @@ -3,8 +3,12 @@ package test import ( "context" "database/sql" + "net/url" + "strconv" + "strings" "time" + "git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models" migrate "github.com/rubenv/sql-migrate" postgrescontainer "github.com/testcontainers/testcontainers-go/modules/postgres" "gorm.io/driver/postgres" @@ -80,3 +84,44 @@ func getGormDB(connectionString string) (*gorm.DB, error) { TranslateError: true, }) } + +func DatabaseModesFromConnectionString(ctx context.Context, pgContainer *postgrescontainer.PostgresContainer) (models.DatabaseConfig, error) { + var err error + var databaseConfig models.DatabaseConfig + + connectionString, err := pgContainer.ConnectionString(ctx) + if err != nil { + return databaseConfig, err + } + + connectionStringUrl, err := url.Parse(connectionString) + if err != nil { + return databaseConfig, err + } + + split := strings.Split(connectionStringUrl.Host, ":") + host := split[0] + + port, err := strconv.Atoi(split[1]) + if err != nil { + return databaseConfig, err + } + + database := strings.TrimPrefix(connectionStringUrl.Path, "/") + + username := connectionStringUrl.User.Username() + password, _ := connectionStringUrl.User.Password() + + databaseConfig = models.DatabaseConfig{ + Endpoint: host, + Username: username, + Password: password, + Database: database, + Port: port, + SSL: false, + Timezone: "Europe/Berlin", + Debug: true, + } + + return databaseConfig, nil +}