diff --git a/database/console/driver/sqlite.go b/database/console/driver/sqlite.go deleted file mode 100644 index 63d704dbc..000000000 --- a/database/console/driver/sqlite.go +++ /dev/null @@ -1,276 +0,0 @@ -package driver - -import ( - "database/sql" - "fmt" - "io" - nurl "net/url" - "strconv" - "strings" - - _ "github.com/glebarez/go-sqlite" - "github.com/golang-migrate/migrate/v4" - "github.com/golang-migrate/migrate/v4/database" - "github.com/hashicorp/go-multierror" - "go.uber.org/atomic" -) - -func init() { - database.Register("sqlite", &Sqlite{}) -} - -var ( - DefaultMigrationsTable = "schema_migrations" - ErrNilConfig = fmt.Errorf("no config") -) - -type Config struct { - MigrationsTable string - DatabaseName string - NoTxWrap bool -} - -type Sqlite struct { - db *sql.DB - isLocked atomic.Bool - - config *Config -} - -func WithInstance(instance *sql.DB, config *Config) (database.Driver, error) { - if config == nil { - return nil, ErrNilConfig - } - - if err := instance.Ping(); err != nil { - return nil, err - } - - if len(config.MigrationsTable) == 0 { - config.MigrationsTable = DefaultMigrationsTable - } - - mx := &Sqlite{ - db: instance, - config: config, - } - if err := mx.ensureVersionTable(); err != nil { - return nil, err - } - return mx, nil -} - -// ensureVersionTable checks if versions table exists and, if not, creates it. -// Note that this function locks the database, which deviates from the usual -// convention of "caller locks" in the Sqlite type. -func (m *Sqlite) ensureVersionTable() (err error) { - if err = m.Lock(); err != nil { - return err - } - - defer func() { - if e := m.Unlock(); e != nil { - if err == nil { - err = e - } else { - err = multierror.Append(err, e) - } - } - }() - - query := fmt.Sprintf(` - CREATE TABLE IF NOT EXISTS %s (version uint64,dirty bool); - CREATE UNIQUE INDEX IF NOT EXISTS version_unique ON %s (version); - `, m.config.MigrationsTable, m.config.MigrationsTable) - - if _, err = m.db.Exec(query); err != nil { - return err - } - return nil -} - -func (m *Sqlite) Open(url string) (database.Driver, error) { - purl, err := nurl.Parse(url) - if err != nil { - return nil, err - } - dbfile := strings.Replace(migrate.FilterCustomQuery(purl).String(), "sqlite://", "", 1) - db, err := sql.Open("sqlite", dbfile) - if err != nil { - return nil, err - } - - qv := purl.Query() - - migrationsTable := qv.Get("x-migrations-table") - if len(migrationsTable) == 0 { - migrationsTable = DefaultMigrationsTable - } - - noTxWrap := false - if v := qv.Get("x-no-tx-wrap"); v != "" { - noTxWrap, err = strconv.ParseBool(v) - if err != nil { - return nil, fmt.Errorf("x-no-tx-wrap: %s", err) - } - } - - mx, err := WithInstance(db, &Config{ - DatabaseName: purl.Path, - MigrationsTable: migrationsTable, - NoTxWrap: noTxWrap, - }) - if err != nil { - return nil, err - } - return mx, nil -} - -func (m *Sqlite) Close() error { - return m.db.Close() -} - -func (m *Sqlite) Drop() (err error) { - query := `SELECT name FROM sqlite_master WHERE type = 'table';` - tables, err := m.db.Query(query) - if err != nil { - return &database.Error{OrigErr: err, Query: []byte(query)} - } - defer func() { - if errClose := tables.Close(); errClose != nil { - err = multierror.Append(err, errClose) - } - }() - - var tableNames []string - for tables.Next() { - var tableName string - if err = tables.Scan(&tableName); err != nil { - return err - } - if len(tableName) > 0 { - tableNames = append(tableNames, tableName) - } - } - if err = tables.Err(); err != nil { - return &database.Error{OrigErr: err, Query: []byte(query)} - } - - if len(tableNames) > 0 { - for _, t := range tableNames { - // SQLite has a sqlite_sequence table and it cannot be dropped - if t == "sqlite_sequence" { - _, err = m.db.Exec("DELETE FROM sqlite_sequence;") - if err != nil { - return &database.Error{OrigErr: err, Query: []byte("DELETE FROM sqlite_sequence;")} - } - - continue - } - - query = "DROP TABLE " + t - err = m.executeQuery(query) - if err != nil { - return &database.Error{OrigErr: err, Query: []byte(query)} - } - } - query = "VACUUM" - _, err = m.db.Exec(query) - if err != nil { - return &database.Error{OrigErr: err, Query: []byte(query)} - } - } - - return nil -} - -func (m *Sqlite) Lock() error { - if !m.isLocked.CompareAndSwap(false, true) { - return database.ErrLocked - } - return nil -} - -func (m *Sqlite) Unlock() error { - if !m.isLocked.CompareAndSwap(true, false) { - return database.ErrNotLocked - } - return nil -} - -func (m *Sqlite) Run(migration io.Reader) error { - migr, err := io.ReadAll(migration) - if err != nil { - return err - } - query := string(migr[:]) - - if m.config.NoTxWrap { - return m.executeQueryNoTx(query) - } - return m.executeQuery(query) -} - -func (m *Sqlite) executeQuery(query string) error { - tx, err := m.db.Begin() - if err != nil { - return &database.Error{OrigErr: err, Err: "transaction start failed"} - } - if _, err = tx.Exec(query); err != nil { - if errRollback := tx.Rollback(); errRollback != nil { - err = multierror.Append(err, errRollback) - } - return &database.Error{OrigErr: err, Query: []byte(query)} - } - if err = tx.Commit(); err != nil { - return &database.Error{OrigErr: err, Err: "transaction commit failed"} - } - return nil -} - -func (m *Sqlite) executeQueryNoTx(query string) error { - if _, err := m.db.Exec(query); err != nil { - return &database.Error{OrigErr: err, Query: []byte(query)} - } - return nil -} - -func (m *Sqlite) SetVersion(version int, dirty bool) error { - tx, err := m.db.Begin() - if err != nil { - return &database.Error{OrigErr: err, Err: "transaction start failed"} - } - - query := "DELETE FROM " + m.config.MigrationsTable - if _, err = tx.Exec(query); err != nil { - return &database.Error{OrigErr: err, Query: []byte(query)} - } - - // Also re-write the schema version for nil dirty versions to prevent - // empty schema version for failed down migration on the first migration - // See: https://github.com/golang-migrate/migrate/issues/330 - if version >= 0 || (version == database.NilVersion && dirty) { - query = fmt.Sprintf(`INSERT INTO %s (version, dirty) VALUES (?, ?)`, m.config.MigrationsTable) - if _, err = tx.Exec(query, version, dirty); err != nil { - if errRollback := tx.Rollback(); errRollback != nil { - err = multierror.Append(err, errRollback) - } - return &database.Error{OrigErr: err, Query: []byte(query)} - } - } - - if err = tx.Commit(); err != nil { - return &database.Error{OrigErr: err, Err: "transaction commit failed"} - } - - return nil -} - -func (m *Sqlite) Version() (version int, dirty bool, err error) { - query := "SELECT version, dirty FROM " + m.config.MigrationsTable + " LIMIT 1" - err = m.db.QueryRow(query).Scan(&version, &dirty) - if err != nil { - return database.NilVersion, false, nil - } - return version, dirty, nil -} diff --git a/database/migration/default_creator.go b/database/migration/creator.go similarity index 71% rename from database/migration/default_creator.go rename to database/migration/creator.go index b00935f06..55ddce65e 100644 --- a/database/migration/default_creator.go +++ b/database/migration/creator.go @@ -10,15 +10,15 @@ import ( "github.com/goravel/framework/support/str" ) -type DefaultCreator struct { +type Creator struct { } -func NewDefaultCreator() *DefaultCreator { - return &DefaultCreator{} +func NewCreator() *Creator { + return &Creator{} } // GetStub Get the migration stub file. -func (r *DefaultCreator) GetStub(table string, create bool) string { +func (r *Creator) GetStub(table string, create bool) string { if table == "" { return Stubs{}.Empty() } @@ -31,7 +31,7 @@ func (r *DefaultCreator) GetStub(table string, create bool) string { } // PopulateStub Populate the place-holders in the migration stub. -func (r *DefaultCreator) PopulateStub(stub, signature, table string) string { +func (r *Creator) PopulateStub(stub, signature, table string) string { stub = strings.ReplaceAll(stub, "DummyMigration", str.Of(signature).Prepend("m_").Studly().String()) stub = strings.ReplaceAll(stub, "DummySignature", signature) stub = strings.ReplaceAll(stub, "DummyTable", table) @@ -40,13 +40,13 @@ func (r *DefaultCreator) PopulateStub(stub, signature, table string) string { } // GetPath Get the full path to the migration. -func (r *DefaultCreator) GetPath(name string) string { +func (r *Creator) GetPath(name string) string { pwd, _ := os.Getwd() return filepath.Join(pwd, "database", "migrations", name+".go") } // GetFileName Get the full path to the migration. -func (r *DefaultCreator) GetFileName(name string) string { +func (r *Creator) GetFileName(name string) string { return fmt.Sprintf("%s_%s", carbon.Now().ToShortDateTimeString(), name) } diff --git a/database/migration/default_creator_test.go b/database/migration/creator_test.go similarity index 97% rename from database/migration/default_creator_test.go rename to database/migration/creator_test.go index ea1e2708c..ce011a66f 100644 --- a/database/migration/default_creator_test.go +++ b/database/migration/creator_test.go @@ -10,7 +10,7 @@ import ( type DefaultCreatorSuite struct { suite.Suite - defaultCreator *DefaultCreator + defaultCreator *Creator } func TestDefaultCreatorSuite(t *testing.T) { @@ -18,7 +18,7 @@ func TestDefaultCreatorSuite(t *testing.T) { } func (s *DefaultCreatorSuite) SetupTest() { - s.defaultCreator = NewDefaultCreator() + s.defaultCreator = NewCreator() } func (s *DefaultCreatorSuite) TestPopulateStub() { diff --git a/database/migration/default_migrator.go b/database/migration/migrator.go similarity index 80% rename from database/migration/default_migrator.go rename to database/migration/migrator.go index 196fac678..8ed7dff65 100644 --- a/database/migration/default_migrator.go +++ b/database/migration/migrator.go @@ -13,23 +13,23 @@ import ( supportfile "github.com/goravel/framework/support/file" ) -type DefaultMigrator struct { +type Migrator struct { artisan console.Artisan - creator *DefaultCreator + creator *Creator repository contractsmigration.Repository schema contractsschema.Schema } -func NewDefaultMigrator(artisan console.Artisan, schema contractsschema.Schema, table string) *DefaultMigrator { - return &DefaultMigrator{ +func NewMigrator(artisan console.Artisan, schema contractsschema.Schema, table string) *Migrator { + return &Migrator{ artisan: artisan, - creator: NewDefaultCreator(), + creator: NewCreator(), repository: NewRepository(schema, table), schema: schema, } } -func (r *DefaultMigrator) Create(name string) error { +func (r *Migrator) Create(name string) error { table, create := TableGuesser{}.Guess(name) stub := r.creator.GetStub(table, create) @@ -45,8 +45,7 @@ func (r *DefaultMigrator) Create(name string) error { return nil } -// TODO Remove this function and move the logic to the migrate:fresh command when the sql migrator is removed. -func (r *DefaultMigrator) Fresh() error { +func (r *Migrator) Fresh() error { if err := r.artisan.Call("db:wipe --force"); err != nil { return err } @@ -57,7 +56,7 @@ func (r *DefaultMigrator) Fresh() error { return nil } -func (r *DefaultMigrator) Reset() error { +func (r *Migrator) Reset() error { ran, err := r.repository.GetRan() if err != nil { return err @@ -66,7 +65,7 @@ func (r *DefaultMigrator) Reset() error { return r.Rollback(len(ran), 0) } -func (r *DefaultMigrator) Rollback(step, batch int) error { +func (r *Migrator) Rollback(step, batch int) error { files, err := r.getFilesForRollback(step, batch) if err != nil { return err @@ -97,7 +96,7 @@ func (r *DefaultMigrator) Rollback(step, batch int) error { return nil } -func (r *DefaultMigrator) Run() error { +func (r *Migrator) Run() error { if err := r.prepareDatabase(); err != nil { return err } @@ -112,7 +111,7 @@ func (r *DefaultMigrator) Run() error { return r.runPending(pendingMigrations) } -func (r *DefaultMigrator) Status() ([]contractsmigration.Status, error) { +func (r *Migrator) Status() ([]contractsmigration.Status, error) { if !r.repository.RepositoryExists() { color.Warningln("Migration table not found") @@ -134,7 +133,7 @@ func (r *DefaultMigrator) Status() ([]contractsmigration.Status, error) { return migrationStatus, nil } -func (r *DefaultMigrator) getFilesForRollback(step, batch int) ([]contractsmigration.File, error) { +func (r *Migrator) getFilesForRollback(step, batch int) ([]contractsmigration.File, error) { if step > 0 { return r.repository.GetMigrationsByStep(step) } @@ -146,7 +145,7 @@ func (r *DefaultMigrator) getFilesForRollback(step, batch int) ([]contractsmigra return r.repository.GetLast() } -func (r *DefaultMigrator) getMigrationViaFile(file contractsmigration.File) contractsschema.Migration { +func (r *Migrator) getMigrationViaFile(file contractsmigration.File) contractsschema.Migration { for _, migration := range r.schema.Migrations() { if migration.Signature() == file.Migration { return migration @@ -156,7 +155,7 @@ func (r *DefaultMigrator) getMigrationViaFile(file contractsmigration.File) cont return nil } -func (r *DefaultMigrator) getStatusForMigrations(batches []contractsmigration.File) []contractsmigration.Status { +func (r *Migrator) getStatusForMigrations(batches []contractsmigration.File) []contractsmigration.Status { var migrationStatus []contractsmigration.Status for _, migration := range r.schema.Migrations() { @@ -185,7 +184,7 @@ func (r *DefaultMigrator) getStatusForMigrations(batches []contractsmigration.Fi return migrationStatus } -func (r *DefaultMigrator) pendingMigrations(ran []string) []contractsschema.Migration { +func (r *Migrator) pendingMigrations(ran []string) []contractsschema.Migration { var pendingMigrations []contractsschema.Migration for _, migration := range r.schema.Migrations() { if !slices.Contains(ran, migration.Signature()) { @@ -196,7 +195,7 @@ func (r *DefaultMigrator) pendingMigrations(ran []string) []contractsschema.Migr return pendingMigrations } -func (r *DefaultMigrator) prepareDatabase() error { +func (r *Migrator) prepareDatabase() error { if r.repository.RepositoryExists() { return nil } @@ -204,7 +203,7 @@ func (r *DefaultMigrator) prepareDatabase() error { return r.repository.CreateRepository() } -func (r *DefaultMigrator) printTitle(maxNameLength int) { +func (r *Migrator) printTitle(maxNameLength int) { color.Default().Print(fmt.Sprintf("%-*s", maxNameLength, "Migration name")) color.Default().Println(" | Batch / Status") for i := 0; i < maxNameLength+17; i++ { @@ -213,7 +212,7 @@ func (r *DefaultMigrator) printTitle(maxNameLength int) { color.Default().Println() } -func (r *DefaultMigrator) runPending(migrations []contractsschema.Migration) error { +func (r *Migrator) runPending(migrations []contractsschema.Migration) error { if len(migrations) == 0 { color.Infoln("Nothing to migrate") @@ -238,7 +237,7 @@ func (r *DefaultMigrator) runPending(migrations []contractsschema.Migration) err return nil } -func (r *DefaultMigrator) runDown(migration contractsschema.Migration) error { +func (r *Migrator) runDown(migration contractsschema.Migration) error { defaultConnection := r.schema.GetConnection() defaultQuery := r.schema.Orm().Query() if connectionMigration, ok := migration.(contractsschema.Connection); ok { @@ -267,7 +266,7 @@ func (r *DefaultMigrator) runDown(migration contractsschema.Migration) error { return r.repository.Delete(migration.Signature()) } -func (r *DefaultMigrator) runUp(migration contractsschema.Migration, batch int) error { +func (r *Migrator) runUp(migration contractsschema.Migration, batch int) error { defaultConnection := r.schema.GetConnection() defaultQuery := r.schema.Orm().Query() if connectionMigration, ok := migration.(contractsschema.Connection); ok { diff --git a/database/migration/default_migrator_test.go b/database/migration/migrator_test.go similarity index 98% rename from database/migration/default_migrator_test.go rename to database/migration/migrator_test.go index 3036d92f6..bdd18e75b 100644 --- a/database/migration/default_migrator_test.go +++ b/database/migration/migrator_test.go @@ -84,7 +84,7 @@ func (s *DefaultMigratorWithDBSuite) TestRun() { testMigration, }) - migrator := NewDefaultMigrator(nil, schema, "migrations") + migrator := NewMigrator(nil, schema, "migrations") s.NoError(migrator.Run()) s.True(schema.HasTable("users")) @@ -104,7 +104,7 @@ func (s *DefaultMigratorWithDBSuite) TestReset() { testMigration, }) - migrator := NewDefaultMigrator(nil, schema, "migrations") + migrator := NewMigrator(nil, schema, "migrations") s.NoError(migrator.Run()) s.True(schema.HasTable("users")) @@ -123,7 +123,7 @@ func (s *DefaultMigratorWithDBSuite) TestRollback() { testMigration, }) - migrator := NewDefaultMigrator(nil, schema, "migrations") + migrator := NewMigrator(nil, schema, "migrations") s.NoError(migrator.Run()) s.True(schema.HasTable("users")) @@ -138,7 +138,7 @@ func (s *DefaultMigratorWithDBSuite) TestStatus() { s.Run(driver.String(), func() { schema := databaseschema.GetTestSchema(testQuery, s.driverToTestQuery) testMigration := NewTestMigration(schema) - migrator := NewDefaultMigrator(nil, schema, "migrations") + migrator := NewMigrator(nil, schema, "migrations") status, err := migrator.Status() s.NoError(err) s.Len(status, 0) @@ -178,7 +178,7 @@ func TestDefaultMigratorWithPostgresSchema(t *testing.T) { schema.Register([]contractsschema.Migration{ testMigration, }) - migrator := NewDefaultMigrator(nil, schema, "migrations") + migrator := NewMigrator(nil, schema, "migrations") assert.NoError(t, migrator.Run()) assert.True(t, schema.HasTable("users")) @@ -202,7 +202,7 @@ func TestDefaultMigratorWithSqlserverSchema(t *testing.T) { schema.Register([]contractsschema.Migration{ testMigration, }) - migrator := NewDefaultMigrator(nil, schema, "migrations") + migrator := NewMigrator(nil, schema, "migrations") assert.NoError(t, migrator.Run()) assert.True(t, schema.HasTable("goravel.users")) @@ -215,7 +215,7 @@ type DefaultMigratorSuite struct { mockArtisan *mocksconsole.Artisan mockRepository *mocksmigration.Repository mockSchema *mocksschema.Schema - migrator *DefaultMigrator + migrator *Migrator } func TestDefaultMigratorSuite(t *testing.T) { @@ -227,9 +227,9 @@ func (s *DefaultMigratorSuite) SetupTest() { s.mockRepository = mocksmigration.NewRepository(s.T()) s.mockSchema = mocksschema.NewSchema(s.T()) - s.migrator = &DefaultMigrator{ + s.migrator = &Migrator{ artisan: s.mockArtisan, - creator: NewDefaultCreator(), + creator: NewCreator(), repository: s.mockRepository, schema: s.mockSchema, } diff --git a/database/migration/sql_creator.go b/database/migration/sql_creator.go deleted file mode 100644 index 2934c584a..000000000 --- a/database/migration/sql_creator.go +++ /dev/null @@ -1,75 +0,0 @@ -package migration - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/goravel/framework/contracts/database" - "github.com/goravel/framework/support/carbon" -) - -type SqlCreator struct { - driver database.Driver - charset string -} - -func NewSqlCreator(driver database.Driver, charset string) *SqlCreator { - return &SqlCreator{ - driver: driver, - charset: charset, - } -} - -// GetPath Get the full path to the migration. -func (r *SqlCreator) GetPath(name string, category string) string { - pwd, _ := os.Getwd() - - return filepath.Join(pwd, "database", "migrations", fmt.Sprintf("%s_%s.%s.sql", carbon.Now().ToShortDateTimeString(), name, category)) -} - -// GetStub Get the migration stub file. -func (r *SqlCreator) GetStub(table string, create bool) (string, string) { - if table == "" { - return "", "" - } - - switch r.driver { - case database.DriverPostgres: - if create { - return PostgresStubs{}.CreateUp(), PostgresStubs{}.CreateDown() - } - - return PostgresStubs{}.UpdateUp(), PostgresStubs{}.UpdateDown() - case database.DriverSqlite: - if create { - return SqliteStubs{}.CreateUp(), SqliteStubs{}.CreateDown() - } - - return SqliteStubs{}.UpdateUp(), SqliteStubs{}.UpdateDown() - case database.DriverSqlserver: - if create { - return SqlserverStubs{}.CreateUp(), SqlserverStubs{}.CreateDown() - } - - return SqlserverStubs{}.UpdateUp(), SqlserverStubs{}.UpdateDown() - default: - if create { - return MysqlStubs{}.CreateUp(), MysqlStubs{}.CreateDown() - } - - return MysqlStubs{}.UpdateUp(), MysqlStubs{}.UpdateDown() - } -} - -// PopulateStub Populate the place-holders in the migration stub. -func (r *SqlCreator) PopulateStub(stub string, table string) string { - stub = strings.ReplaceAll(stub, "DummyDatabaseCharset", r.charset) - - if table != "" { - stub = strings.ReplaceAll(stub, "DummyTable", table) - } - - return stub -} diff --git a/database/migration/sql_creator_test.go b/database/migration/sql_creator_test.go deleted file mode 100644 index d81095e89..000000000 --- a/database/migration/sql_creator_test.go +++ /dev/null @@ -1,150 +0,0 @@ -package migration - -import ( - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/suite" - - "github.com/goravel/framework/contracts/database" - "github.com/goravel/framework/support/carbon" - "github.com/goravel/framework/support/str" -) - -type SqlCreatorSuite struct { - suite.Suite - sqlCreator *SqlCreator -} - -func TestSqlCreatorSuite(t *testing.T) { - suite.Run(t, &SqlCreatorSuite{}) -} - -func (s *SqlCreatorSuite) SetupTest() { - s.sqlCreator = NewSqlCreator("postgres", "utf8mb4") -} - -func (s *SqlCreatorSuite) TestGetPath() { - now := carbon.FromDateTime(2024, 8, 17, 21, 45, 1) - carbon.SetTestNow(now) - - pwd, _ := os.Getwd() - path := filepath.Join(pwd, "database", "migrations") - - s.Equal(filepath.Join(path, "20240817214501_create_users_table.up.sql"), s.sqlCreator.GetPath("create_users_table", "up")) - s.Equal(filepath.Join(path, "20240817214501_create_users_table.down.sql"), s.sqlCreator.GetPath("create_users_table", "down")) - - carbon.UnsetTestNow() -} - -func (s *SqlCreatorSuite) TestPopulateStub() { - tests := []struct { - name string - driver database.Driver - table string - create bool - expectUp string - expectDown string - }{ - { - name: "table is empty", - }, - { - name: "mysql - create template", - driver: "mysql", - table: "users", - create: true, - expectUp: `CREATE TABLE users ( - id bigint(20) unsigned NOT NULL AUTO_INCREMENT, - created_at datetime(3) NOT NULL, - updated_at datetime(3) NOT NULL, - PRIMARY KEY (id), - KEY idx_users_created_at (created_at), - KEY idx_users_updated_at (updated_at) -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;`, - expectDown: `DROP TABLE IF EXISTS users;`, - }, - { - name: "mysql - update template", - driver: "mysql", - table: "users", - create: false, - expectUp: `ALTER TABLE users ADD column varchar(255) COMMENT '';`, - expectDown: `ALTER TABLE users DROP COLUMN column;`, - }, - { - name: "postgres - create template", - driver: "postgres", - table: "users", - create: true, - expectUp: `CREATE TABLE users ( - id SERIAL PRIMARY KEY NOT NULL, - created_at timestamp NOT NULL, - updated_at timestamp NOT NULL -);`, - expectDown: `DROP TABLE IF EXISTS users;`, - }, - { - name: "postgres - update template", - driver: "postgres", - table: "users", - create: false, - expectUp: `ALTER TABLE users ADD column varchar(255) NOT NULL;`, - expectDown: `ALTER TABLE users DROP COLUMN column;`, - }, - { - name: "sqlite - create template", - driver: "sqlite", - table: "users", - create: true, - expectUp: `CREATE TABLE users ( - id integer PRIMARY KEY AUTOINCREMENT NOT NULL, - created_at datetime NOT NULL, - updated_at datetime NOT NULL -);`, - expectDown: `DROP TABLE IF EXISTS users;`, - }, - { - name: "sqlite - update template", - driver: "sqlite", - table: "users", - create: false, - expectUp: `ALTER TABLE users ADD column text;`, - expectDown: `ALTER TABLE users DROP COLUMN column;`, - }, - { - name: "sqlserver - create template", - driver: "sqlserver", - table: "users", - create: true, - expectUp: `CREATE TABLE users ( - id bigint NOT NULL IDENTITY(1,1), - created_at datetime NOT NULL, - updated_at datetime NOT NULL, - PRIMARY KEY (id) -);`, - expectDown: `DROP TABLE IF EXISTS users;`, - }, - { - name: "sqlserver - update template", - driver: "sqlserver", - table: "users", - create: false, - expectUp: `ALTER TABLE users ADD column varchar(255);`, - expectDown: `ALTER TABLE users DROP COLUMN column;`, - }, - } - - for _, test := range tests { - s.Run(test.name, func() { - sqlCreator := NewSqlCreator(test.driver, "utf8mb4") - upStub, downStub := sqlCreator.GetStub(test.table, test.create) - up := sqlCreator.PopulateStub(upStub, test.table) - down := sqlCreator.PopulateStub(downStub, test.table) - - s.Equal(test.expectUp, str.Of(up).RTrim("\n").String()) - s.Equal(test.expectDown, str.Of(down).RTrim("\n").String()) - }) - } -} diff --git a/database/migration/sql_migrator.go b/database/migration/sql_migrator.go deleted file mode 100644 index 6a8ceaabc..000000000 --- a/database/migration/sql_migrator.go +++ /dev/null @@ -1,211 +0,0 @@ -package migration - -import ( - "database/sql" - "fmt" - - "github.com/golang-migrate/migrate/v4" - migratedatabase "github.com/golang-migrate/migrate/v4/database" - "github.com/golang-migrate/migrate/v4/database/mysql" - "github.com/golang-migrate/migrate/v4/database/postgres" - "github.com/golang-migrate/migrate/v4/database/sqlserver" - _ "github.com/golang-migrate/migrate/v4/source/file" - - "github.com/goravel/framework/contracts/config" - "github.com/goravel/framework/contracts/database" - "github.com/goravel/framework/contracts/database/migration" - "github.com/goravel/framework/database/console/driver" - databasedb "github.com/goravel/framework/database/db" - "github.com/goravel/framework/errors" - "github.com/goravel/framework/support" - "github.com/goravel/framework/support/color" - "github.com/goravel/framework/support/file" -) - -// TODO Remove in v1.16 -type SqlMigrator struct { - configBuilder *databasedb.ConfigBuilder - creator *SqlCreator - migrator *migrate.Migrate - table string -} - -func NewSqlMigrator(config config.Config) (*SqlMigrator, error) { - connection := config.GetString("database.default") - charset := config.GetString(fmt.Sprintf("database.connections.%s.charset", connection)) - dbDriver := database.Driver(config.GetString(fmt.Sprintf("database.connections.%s.driver", connection))) - table := config.GetString("database.migrations.table") - configBuilder := databasedb.NewConfigBuilder(config, connection) - migrator, err := getMigrator(configBuilder, table) - if err != nil { - return nil, err - } - - return &SqlMigrator{ - configBuilder: configBuilder, - creator: NewSqlCreator(dbDriver, charset), - migrator: migrator, - table: table, - }, nil -} - -func (r *SqlMigrator) Create(name string) error { - table, create := TableGuesser{}.Guess(name) - - upStub, downStub := r.creator.GetStub(table, create) - - // Create the up.sql file. - if err := file.Create(r.creator.GetPath(name, "up"), r.creator.PopulateStub(upStub, table)); err != nil { - return err - } - - // Create the down.sql file. - if err := file.Create(r.creator.GetPath(name, "down"), r.creator.PopulateStub(downStub, table)); err != nil { - return err - } - - return nil -} - -func (r *SqlMigrator) Fresh() error { - if err := r.migrator.Drop(); err != nil && !errors.Is(err, migrate.ErrNoChange) { - return err - } - - // Recreate the migrations table. - migrator, err := getMigrator(r.configBuilder, r.table) - if err != nil { - return err - } - - r.migrator = migrator - - return r.Run() -} - -func (r *SqlMigrator) Reset() error { - if err := r.migrator.Down(); err != nil && !errors.Is(err, migrate.ErrNoChange) { - return errors.MigrationResetFailed.Args(err) - } - - color.Successln("Migration reset success") - - return nil -} - -func (r *SqlMigrator) Rollback(step, batch int) error { - if err := r.migrator.Steps(-step); err != nil { - var errShortLimit migrate.ErrShortLimit - if errors.Is(err, migrate.ErrNoChange) || errors.Is(err, migrate.ErrNilVersion) || errors.As(err, &errShortLimit) { - return nil - } - - return errors.MigrationRollbackFailed.Args(err) - } - - return nil -} - -func (r *SqlMigrator) Run() error { - if err := r.migrator.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) { - return err - } - - return nil -} - -func (r *SqlMigrator) Status() ([]migration.Status, error) { - version, dirty, err := r.migrator.Version() - if err != nil { - if errors.Is(err, migrate.ErrNilVersion) { - color.Warningln("No migrations found") - - return nil, nil - } else { - return nil, errors.MigrationGetStatusFailed.Args(err) - } - } - if dirty { - color.Warningln("Migration status: dirty") - } - - color.Successln(fmt.Sprintf("Migration version: %d", version)) - - return nil, nil -} - -func getMigrator(configBuilder *databasedb.ConfigBuilder, table string) (*migrate.Migrate, error) { - path := "file://./database/migrations" - if support.RelativePath != "" { - path = fmt.Sprintf("file://%s/database/migrations", support.RelativePath) - } - - writeConfigs := configBuilder.Writes() - if len(writeConfigs) == 0 { - return nil, errors.OrmDatabaseConfigNotFound - } - - writeConfig := writeConfigs[0] - dsn := databasedb.Dsn(writeConfigs[0]) - if dsn == "" { - return nil, errors.OrmFailedToGenerateDNS - } - - var ( - databaseName string - db *sql.DB - dbDriver migratedatabase.Driver - err error - ) - - switch writeConfig.Driver { - case database.DriverMysql: - databaseName = "mysql" - db, err = sql.Open(databaseName, dsn) - if err != nil { - return nil, err - } - - dbDriver, err = mysql.WithInstance(db, &mysql.Config{ - MigrationsTable: table, - }) - case database.DriverPostgres: - databaseName = "postgres" - db, err = sql.Open(databaseName, dsn) - if err != nil { - return nil, err - } - - dbDriver, err = postgres.WithInstance(db, &postgres.Config{ - MigrationsTable: table, - }) - case database.DriverSqlite: - databaseName = "sqlite3" - db, err = sql.Open("sqlite", dsn) - if err != nil { - return nil, err - } - - dbDriver, err = driver.WithInstance(db, &driver.Config{ - MigrationsTable: table, - }) - case database.DriverSqlserver: - databaseName = "sqlserver" - db, err = sql.Open(databaseName, dsn) - if err != nil { - return nil, err - } - - dbDriver, err = sqlserver.WithInstance(db, &sqlserver.Config{ - MigrationsTable: table, - }) - default: - err = errors.OrmDriverNotSupported.Args(writeConfig.Connection) - } - - if err != nil { - return nil, err - } - - return migrate.NewWithDatabaseInstance(path, databaseName, dbDriver) -} diff --git a/database/migration/sql_migrator_test.go b/database/migration/sql_migrator_test.go deleted file mode 100644 index 0a4d859c5..000000000 --- a/database/migration/sql_migrator_test.go +++ /dev/null @@ -1,169 +0,0 @@ -package migration - -import ( - "io" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - - contractsdatabase "github.com/goravel/framework/contracts/database" - "github.com/goravel/framework/contracts/database/orm" - databasedb "github.com/goravel/framework/database/db" - "github.com/goravel/framework/database/gorm" - "github.com/goravel/framework/support/carbon" - "github.com/goravel/framework/support/color" - "github.com/goravel/framework/support/env" - "github.com/goravel/framework/support/file" -) - -type SqlMigratorSuite struct { - suite.Suite - driverToTestQuery map[contractsdatabase.Driver]*gorm.TestQuery -} - -func TestSqlMigratorSuite(t *testing.T) { - if env.IsWindows() { - t.Skip("Skip test that using Docker") - } - - suite.Run(t, &SqlMigratorSuite{}) -} - -func (s *SqlMigratorSuite) SetupTest() { - s.driverToTestQuery = gorm.NewTestQueries().Queries() -} - -func (s *SqlMigratorSuite) TearDownTest() { - s.NoError(file.Remove("database")) - if s.driverToTestQuery[contractsdatabase.DriverSqlite] != nil { - s.NoError(s.driverToTestQuery[contractsdatabase.DriverSqlite].Docker().Shutdown()) - } -} - -func (s *SqlMigratorSuite) TestCreate() { - now := carbon.FromDateTime(2024, 8, 17, 21, 45, 1) - carbon.SetTestNow(now) - defer carbon.UnsetTestNow() - - pwd, err := os.Getwd() - s.NoError(err) - - path := filepath.Join(pwd, "database", "migrations") - name := "create_users_table" - - for driver, testQuery := range s.driverToTestQuery { - migrator, _ := getTestSqlMigrator(s.T(), driver, testQuery) - - s.NoError(migrator.Create(name)) - - upFile := filepath.Join(path, "20240817214501_"+name+".up.sql") - downFile := filepath.Join(path, "20240817214501_"+name+".down.sql") - - s.True(file.Exists(upFile)) - s.True(file.Exists(downFile)) - } -} - -func (s *SqlMigratorSuite) TestFresh() { - for driver, testQuery := range s.driverToTestQuery { - s.Run(driver.String(), func() { - migrator, query := getTestSqlMigrator(s.T(), driver, testQuery) - - err := migrator.Run() - s.NoError(err) - - err = migrator.Fresh() - s.NoError(err) - - var agent Agent - err = query.Where("name", "goravel").First(&agent) - s.NoError(err) - s.True(agent.ID > 0) - }) - } -} - -func (s *SqlMigratorSuite) TestRollback() { - for driver, testQuery := range s.driverToTestQuery { - s.Run(driver.String(), func() { - migrator, query := getTestSqlMigrator(s.T(), driver, testQuery) - - err := migrator.Run() - s.NoError(err) - - var agent Agent - err = query.Where("name", "goravel").First(&agent) - s.NoError(err) - s.True(agent.ID > 0) - - err = migrator.Rollback(1, 0) - s.NoError(err) - - var agent1 Agent - err = query.Where("name", "goravel").First(&agent1) - s.NotNil(err) - }) - } -} - -func (s *SqlMigratorSuite) TestRun() { - for driver, testQuery := range s.driverToTestQuery { - s.Run(driver.String(), func() { - migrator, query := getTestSqlMigrator(s.T(), driver, testQuery) - - err := migrator.Run() - s.NoError(err) - - var agent Agent - s.NoError(query.Where("name", "goravel").First(&agent)) - s.True(agent.ID > 0) - - err = migrator.Run() - s.NoError(err) - }) - } -} - -func (s *SqlMigratorSuite) TestStatus() { - for driver, testQuery := range s.driverToTestQuery { - s.Run(driver.String(), func() { - migrator, _ := getTestSqlMigrator(s.T(), driver, testQuery) - - s.Equal("\x1b[30;43m\x1b[30;43m WARNING \x1b[0m\x1b[0m \x1b[33m\x1b[33mNo migrations found\x1b[0m\x1b[0m\n", color.CaptureOutput(func(w io.Writer) { - status, err := migrator.Status() - s.NoError(err) - s.Nil(status) - })) - - err := migrator.Run() - s.NoError(err) - - s.Equal("\x1b[30;42m\x1b[30;42m SUCCESS \x1b[0m\x1b[0m \x1b[32m\x1b[32mMigration version: 20230311160527\x1b[0m\x1b[0m\n", color.CaptureOutput(func(w io.Writer) { - status, err := migrator.Status() - s.NoError(err) - s.Nil(status) - })) - }) - } -} - -func getTestSqlMigrator(t *testing.T, driver contractsdatabase.Driver, testQuery *gorm.TestQuery) (*SqlMigrator, orm.Query) { - query := testQuery.Query() - mockConfig := testQuery.MockConfig() - CreateTestMigrations(driver) - - table := "migrations" - configBuilder := databasedb.NewConfigBuilder(mockConfig, driver.String()) - migrator, err := getMigrator(configBuilder, table) - require.NoError(t, err) - - return &SqlMigrator{ - configBuilder: databasedb.NewConfigBuilder(mockConfig, driver.String()), - creator: NewSqlCreator(driver, "utf8mb4"), - migrator: migrator, - table: table, - }, query -} diff --git a/database/service_provider.go b/database/service_provider.go index 99b43d148..af12df4af 100644 --- a/database/service_provider.go +++ b/database/service_provider.go @@ -4,7 +4,6 @@ import ( "context" contractsconsole "github.com/goravel/framework/contracts/console" - contractsmigration "github.com/goravel/framework/contracts/database/migration" "github.com/goravel/framework/contracts/foundation" "github.com/goravel/framework/database/console" consolemigration "github.com/goravel/framework/database/console/migration" @@ -82,23 +81,7 @@ func (r *ServiceProvider) registerCommands(app foundation.Application) { seeder := app.MakeSeeder() if artisan != nil && config != nil && log != nil && schema != nil && seeder != nil { - var migrator contractsmigration.Migrator - - driver := config.GetString("database.migrations.driver") - if driver == contractsmigration.MigratorDefault { - migrator = migration.NewDefaultMigrator(artisan, schema, config.GetString("database.migrations.table")) - } else if driver == contractsmigration.MigratorSql { - var err error - migrator, err = migration.NewSqlMigrator(config) - if err != nil { - log.Error(errors.MigrationSqlMigratorInit.Args(err).SetModule(errors.ModuleMigration)) - return - } - } else { - log.Error(errors.MigrationUnsupportedDriver.Args(driver).SetModule(errors.ModuleMigration)) - return - } - + migrator := migration.NewMigrator(artisan, schema, config.GetString("database.migrations.table")) artisan.Register([]contractsconsole.Command{ consolemigration.NewMigrateMakeCommand(migrator), consolemigration.NewMigrateCommand(migrator), diff --git a/errors/list.go b/errors/list.go index 8ff6b5271..14ce72c2e 100644 --- a/errors/list.go +++ b/errors/list.go @@ -74,16 +74,14 @@ var ( LogDriverNotSupported = New("invalid driver: %s, only support stack, single, daily, custom").SetModule(ModuleLog) LogEmptyLogFilePath = New("empty log file path").SetModule(ModuleLog) - MigrationCreateFailed = New("Create migration failed: %v") - MigrationFreshFailed = New("migration fresh failed: %v") - MigrationGetStatusFailed = New("get migration status failed: %v") - MigrationMigrateFailed = New("migrate failed: %v") - MigrationNameIsRequired = New("migration name cannot be empty") - MigrationRefreshFailed = New("migration refresh failed: %v") - MigrationResetFailed = New("migration reset failed: %v") - MigrationRollbackFailed = New("migration rollback failed: %v") - MigrationSqlMigratorInit = New("failed to init sql migration driver: %s") - MigrationUnsupportedDriver = New("unsupported migration driver: %s") + MigrationCreateFailed = New("Create migration failed: %v") + MigrationFreshFailed = New("migration fresh failed: %v") + MigrationGetStatusFailed = New("get migration status failed: %v") + MigrationMigrateFailed = New("migrate failed: %v") + MigrationNameIsRequired = New("migration name cannot be empty") + MigrationRefreshFailed = New("migration refresh failed: %v") + MigrationResetFailed = New("migration reset failed: %v") + MigrationRollbackFailed = New("migration rollback failed: %v") OrmDatabaseConfigNotFound = New("not found database configuration") OrmDriverNotSupported = New("invalid driver: %s, only support mysql, postgres, sqlite and sqlserver") diff --git a/go.mod b/go.mod index e8ac7baaa..868745a2a 100644 --- a/go.mod +++ b/go.mod @@ -8,21 +8,18 @@ require ( github.com/RichardKnop/machinery/v2 v2.0.13 github.com/brianvoe/gofakeit/v7 v7.1.2 github.com/charmbracelet/huh v0.6.0 - github.com/charmbracelet/huh/spinner v0.0.0-20241216182847-438e4f741435 + github.com/charmbracelet/huh/spinner v0.0.0-20250109160224-6c6b31916f8e github.com/charmbracelet/lipgloss v1.0.0 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/dromara/carbon/v2 v2.5.2 github.com/gabriel-vasile/mimetype v1.4.8 - github.com/glebarez/go-sqlite v1.22.0 github.com/glebarez/sqlite v1.11.0 github.com/go-viper/mapstructure/v2 v2.2.1 github.com/golang-jwt/jwt/v5 v5.2.1 - github.com/golang-migrate/migrate/v4 v4.18.1 github.com/golang/protobuf v1.5.4 github.com/google/uuid v1.6.0 github.com/gookit/validate v1.5.4 github.com/goravel/file-rotatelogs/v2 v2.4.2 - github.com/hashicorp/go-multierror v1.1.1 github.com/pterm/pterm v0.12.80 github.com/redis/go-redis/v9 v9.7.0 github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 @@ -34,9 +31,8 @@ require ( github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.10.0 github.com/urfave/cli/v2 v2.27.5 - go.uber.org/atomic v1.11.0 - golang.org/x/crypto v0.31.0 - golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 + golang.org/x/crypto v0.32.0 + golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 google.golang.org/grpc v1.69.2 gorm.io/driver/mysql v1.5.7 gorm.io/driver/sqlserver v1.5.4 @@ -54,11 +50,6 @@ require ( cloud.google.com/go/iam v1.1.6 // indirect cloud.google.com/go/pubsub v1.36.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect - github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest/adal v0.9.16 // indirect - github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect - github.com/Azure/go-autorest/logger v0.2.1 // indirect - github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae // indirect github.com/atotto/clipboard v0.1.4 // indirect github.com/aws/aws-sdk-go v1.49.6 // indirect @@ -77,13 +68,13 @@ require ( github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/glebarez/go-sqlite v1.22.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-redsync/redsync/v4 v4.8.1 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-stack/stack v1.8.0 // indirect - github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -96,6 +87,7 @@ require ( github.com/gookit/filter v1.2.2 // indirect github.com/gookit/goutil v0.6.18 github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect @@ -103,7 +95,6 @@ require ( github.com/kelseyhightower/envconfig v1.4.0 // indirect github.com/klauspost/compress v1.17.2 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect - github.com/lib/pq v1.10.9 // indirect github.com/lithammer/fuzzysearch v1.1.8 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/magiconair/properties v1.8.7 // indirect @@ -123,6 +114,7 @@ require ( github.com/rabbitmq/amqp091-go v1.9.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -144,12 +136,13 @@ require ( go.opentelemetry.io/otel v1.31.0 // indirect go.opentelemetry.io/otel/metric v1.31.0 // indirect go.opentelemetry.io/otel/trace v1.31.0 // indirect + go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/net v0.33.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/term v0.27.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 golang.org/x/time v0.5.0 // indirect google.golang.org/api v0.171.0 // indirect diff --git a/go.sum b/go.sum index 2f4abb228..3f0c33b2c 100644 --- a/go.sum +++ b/go.sum @@ -69,20 +69,6 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= -github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest/adal v0.9.16 h1:P8An8Z9rH1ldbOLdFpxYorgOt2sywL9V24dAwWHPuGc= -github.com/Azure/go-autorest/autorest/adal v0.9.16/go.mod h1:tGMin8I49Yij6AQ+rvV+Xa/zwxYQB5hmsd6DkfAx2+A= -github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= -github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= -github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= -github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= -github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= @@ -99,8 +85,6 @@ github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/ github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4= github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY= -github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= -github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae h1:DcFpTQBYQ9Ct2d6sC7ol0/ynxc2pO1cpGUM+f4t5adg= github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae/go.mod h1:rJJ84PyA/Wlmw1hO+xTzV2wsSUon6J5ktg0g8BF2PuU= github.com/RichardKnop/machinery/v2 v2.0.13 h1:uo9htg+qNBi7UeUK3jcTBl3vTO/vvLKGaOdCOKePl50= @@ -138,8 +122,8 @@ github.com/charmbracelet/bubbletea v1.2.5-0.20241205214244-9306010a31ee h1:xNijb github.com/charmbracelet/bubbletea v1.2.5-0.20241205214244-9306010a31ee/go.mod h1:Hbk5+oE4a7cDyjfdPi4sHZ42aGTMYcmHnVDhsRswn7A= github.com/charmbracelet/huh v0.6.0 h1:mZM8VvZGuE0hoDXq6XLxRtgfWyTI3b2jZNKh0xWmax8= github.com/charmbracelet/huh v0.6.0/go.mod h1:GGNKeWCeNzKpEOh/OJD8WBwTQjV3prFAtQPpLv+AVwU= -github.com/charmbracelet/huh/spinner v0.0.0-20241216182847-438e4f741435 h1:GnQvPBetPFyWaq4xVP4iia8UZAaLMVUk4UZ1O3Gdx44= -github.com/charmbracelet/huh/spinner v0.0.0-20241216182847-438e4f741435/go.mod h1:YqGqPo+vKnyTc0xppm1sv3Ir8FwG9bSW2H33LT++Xdg= +github.com/charmbracelet/huh/spinner v0.0.0-20250109160224-6c6b31916f8e h1:1evzoX6fqBfx5U7dMfEz63eXc7afCJ+1LWYrOECxU8k= +github.com/charmbracelet/huh/spinner v0.0.0-20250109160224-6c6b31916f8e/go.mod h1:YqGqPo+vKnyTc0xppm1sv3Ir8FwG9bSW2H33LT++Xdg= github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= github.com/charmbracelet/x/ansi v0.4.5 h1:LqK4vwBNaXw2AyGIICa5/29Sbdq58GbGdFngSexTdRM= @@ -167,18 +151,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/dhui/dktest v0.4.3 h1:wquqUxAFdcUgabAVLvSCOKOlag5cIZuaOjYIBOWdsR0= -github.com/dhui/dktest v0.4.3/go.mod h1:zNK8IwktWzQRm6I/l2Wjp7MakiyaFWv4G1hjmodmMTs= -github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= -github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docker/docker v27.2.0+incompatible h1:Rk9nIVdfH3+Vz4cyI/uhbINhEZ/oLmc+CBXmH6fbNk4= -github.com/docker/docker v27.2.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= -github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dromara/carbon/v2 v2.5.2 h1:GquNyA9Imda+LwS9FIzHhKg+foU2QPstH+S3idBRjKg= github.com/dromara/carbon/v2 v2.5.2/go.mod h1:zyPlND2o27sKKkRmdgLbk/qYxkmmH6Z4eE8OoM0w3DM= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -255,17 +229,10 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= -github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang-migrate/migrate/v4 v4.18.1 h1:JML/k+t4tpHCpQTCAD62Nu43NUFzHY4CV3uAuvHGC+Y= -github.com/golang-migrate/migrate/v4 v4.18.1/go.mod h1:HAX6m3sQgcdO81tdjn5exv20+3Kb13cmGli1hrD6hks= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= @@ -428,8 +395,6 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= @@ -451,15 +416,9 @@ github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4 github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= -github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= @@ -476,10 +435,6 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= @@ -648,7 +603,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= @@ -657,8 +611,8 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -669,8 +623,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 h1:9kj3STMvgqy3YA4VQXBrN7925ICMxD5wzMRcgA30588= -golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= +golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -832,8 +786,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -846,8 +800,8 @@ golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/testing/assertable_json.go b/testing/http/assertable_json.go similarity index 88% rename from testing/assertable_json.go rename to testing/http/assertable_json.go index fd2c8cb3a..d2c68cef6 100644 --- a/testing/assertable_json.go +++ b/testing/http/assertable_json.go @@ -1,4 +1,4 @@ -package testing +package http import ( "fmt" @@ -6,17 +6,19 @@ import ( "github.com/stretchr/testify/assert" + "github.com/goravel/framework/contracts/foundation" contractstesting "github.com/goravel/framework/contracts/testing" "github.com/goravel/framework/support/maps" ) type AssertableJson struct { t *testing.T - json string + json foundation.Json + jsonStr string decoded map[string]any } -func NewAssertableJSON(t *testing.T, jsonStr string) (contractstesting.AssertableJSON, error) { +func NewAssertableJSON(t *testing.T, json foundation.Json, jsonStr string) (contractstesting.AssertableJSON, error) { var decoded map[string]any err := json.Unmarshal([]byte(jsonStr), &decoded) if err != nil { @@ -25,7 +27,8 @@ func NewAssertableJSON(t *testing.T, jsonStr string) (contractstesting.Assertabl return &AssertableJson{ t: t, - json: jsonStr, + json: json, + jsonStr: jsonStr, decoded: decoded, }, nil } @@ -111,9 +114,9 @@ func (r *AssertableJson) First(key string, callback func(contractstesting.Assert } firstItem := array[0] - itemJson, err := json.Marshal(firstItem) + itemJson, err := r.json.Marshal(firstItem) if assert.NoError(r.t, err, "Failed to marshal the first item") { - newJson, err := NewAssertableJSON(r.t, string(itemJson)) + newJson, err := NewAssertableJSON(r.t, r.json, string(itemJson)) if assert.NoError(r.t, err, "Failed to create AssertableJSON for first item") { callback(newJson) } @@ -138,12 +141,12 @@ func (r *AssertableJson) HasWithScope(key string, length int, callback func(cont } if len(array) > 0 { - itemJson, err := json.Marshal(array[0]) + itemJson, err := r.json.Marshal(array[0]) if !assert.NoError(r.t, err, "Failed to marshal the first item of array") { return r } - newJson, err := NewAssertableJSON(r.t, string(itemJson)) + newJson, err := NewAssertableJSON(r.t, r.json, string(itemJson)) if !assert.NoError(r.t, err, "Failed to create AssertableJSON for first item in scoped array") { return r } @@ -166,12 +169,12 @@ func (r *AssertableJson) Each(key string, callback func(contractstesting.Asserta } for _, item := range array { - itemJson, err := json.Marshal(item) + itemJson, err := r.json.Marshal(item) if !assert.NoError(r.t, err) { continue } - newJson, err := NewAssertableJSON(r.t, string(itemJson)) + newJson, err := NewAssertableJSON(r.t, r.json, string(itemJson)) if !assert.NoError(r.t, err) { continue } diff --git a/testing/assertable_json_test.go b/testing/http/assertable_json_test.go similarity index 83% rename from testing/assertable_json_test.go rename to testing/http/assertable_json_test.go index 3b6f1fbb6..8c8983e30 100644 --- a/testing/assertable_json_test.go +++ b/testing/http/assertable_json_test.go @@ -1,4 +1,4 @@ -package testing +package http import ( "testing" @@ -13,35 +13,28 @@ type AssertableJsonTestSuite struct { } func TestAssertableJsonTestSuite(t *testing.T) { - json = &testJson{} - suite.Run(t, new(AssertableJsonTestSuite)) } func (s *AssertableJsonTestSuite) SetupTest() { - -} - -func (s *AssertableJsonTestSuite) TearDownSuite() { - json = nil } func (s *AssertableJsonTestSuite) TestNewAssertableJSON() { validJSON := `{"key1": "value1", "key2": [1, 2, 3]}` invalidJSON := `{"key1": "value1", "key2": [1, 2, 3]` - assertable, err := NewAssertableJSON(s.T(), validJSON) + assertable, err := NewAssertableJSON(s.T(), &testJson{}, validJSON) s.NoError(err) s.NotNil(assertable) - assertable, err = NewAssertableJSON(s.T(), invalidJSON) + assertable, err = NewAssertableJSON(s.T(), &testJson{}, invalidJSON) s.Error(err) s.Nil(assertable) } func (s *AssertableJsonTestSuite) TestCount() { jsonStr := `{"items": [1, 2, 3], "otherKey": "value"}` - assertable, err := NewAssertableJSON(s.T(), jsonStr) + assertable, err := NewAssertableJSON(s.T(), &testJson{}, jsonStr) s.NoError(err) assertable.Count("items", 3) @@ -56,7 +49,7 @@ func (s *AssertableJsonTestSuite) TestHas() { "nested": {"deep": "value"}, "nullKey": null }` - assertable, err := NewAssertableJSON(s.T(), jsonStr) + assertable, err := NewAssertableJSON(s.T(), &testJson{}, jsonStr) s.NoError(err) assertable.Has("key1") @@ -67,7 +60,7 @@ func (s *AssertableJsonTestSuite) TestHas() { func (s *AssertableJsonTestSuite) TestHasAll() { jsonStr := `{"key1": "value1", "key2": [1, 2, 3]}` - assertable, err := NewAssertableJSON(s.T(), jsonStr) + assertable, err := NewAssertableJSON(s.T(), &testJson{}, jsonStr) s.NoError(err) // Test all keys exist @@ -79,7 +72,7 @@ func (s *AssertableJsonTestSuite) TestHasAll() { func (s *AssertableJsonTestSuite) TestHasAny() { jsonStr := `{"key1": "value1", "key2": [1, 2, 3]}` - assertable, err := NewAssertableJSON(s.T(), jsonStr) + assertable, err := NewAssertableJSON(s.T(), &testJson{}, jsonStr) s.NoError(err) // Test at least one key exists @@ -91,7 +84,7 @@ func (s *AssertableJsonTestSuite) TestHasAny() { func (s *AssertableJsonTestSuite) TestMissing() { jsonStr := `{"key1": "value1"}` - assertable, err := NewAssertableJSON(s.T(), jsonStr) + assertable, err := NewAssertableJSON(s.T(), &testJson{}, jsonStr) s.NoError(err) // Test key is missing @@ -103,7 +96,7 @@ func (s *AssertableJsonTestSuite) TestMissing() { func (s *AssertableJsonTestSuite) TestMissingAll() { jsonStr := `{"key1": "value1"}` - assertable, err := NewAssertableJSON(s.T(), jsonStr) + assertable, err := NewAssertableJSON(s.T(), &testJson{}, jsonStr) s.NoError(err) // Test all keys are missing @@ -122,7 +115,7 @@ func (s *AssertableJsonTestSuite) TestWhere() { "objKey": {"nested": "value"}, "arrayKey": [1, 2, 3] }` - assertable, err := NewAssertableJSON(s.T(), jsonStr) + assertable, err := NewAssertableJSON(s.T(), &testJson{}, jsonStr) s.NoError(err) // Test correct value @@ -143,7 +136,7 @@ func (s *AssertableJsonTestSuite) TestWhere() { func (s *AssertableJsonTestSuite) TestWhereNot() { jsonStr := `{"key1": "value1", "key2": [1, 2, 3]}` - assertable, err := NewAssertableJSON(s.T(), jsonStr) + assertable, err := NewAssertableJSON(s.T(), &testJson{}, jsonStr) s.NoError(err) // Test value is not as expected @@ -156,7 +149,7 @@ func (s *AssertableJsonTestSuite) TestWhereNot() { func (s *AssertableJsonTestSuite) TestFirst() { jsonStr := `{"items": [{"id": 1}, {"id": 2}]}` - assertable, err := NewAssertableJSON(s.T(), jsonStr) + assertable, err := NewAssertableJSON(s.T(), &testJson{}, jsonStr) s.NoError(err) // Test fetching the first item @@ -176,7 +169,7 @@ func (s *AssertableJsonTestSuite) TestFirst() { func (s *AssertableJsonTestSuite) TestHasWithScope() { jsonStr := `{"items": [{"id": 1}, {"id": 2}]}` - assertable, err := NewAssertableJSON(s.T(), jsonStr) + assertable, err := NewAssertableJSON(s.T(), &testJson{}, jsonStr) s.NoError(err) // Test has with correct length @@ -198,7 +191,7 @@ func (s *AssertableJsonTestSuite) TestEach() { "nonArray": "value" }` - assertable, err := NewAssertableJSON(s.T(), jsonStr) + assertable, err := NewAssertableJSON(s.T(), &testJson{}, jsonStr) s.NoError(err) // Test iterating over each item @@ -214,7 +207,7 @@ func (s *AssertableJsonTestSuite) TestEach() { // Test with an empty array emptyJsonStr := `{"items": []}` - emptyAssertable, err := NewAssertableJSON(s.T(), emptyJsonStr) + emptyAssertable, err := NewAssertableJSON(s.T(), &testJson{}, emptyJsonStr) s.NoError(err) emptyCallCount := 0 diff --git a/testing/test_request.go b/testing/http/test_request.go similarity index 86% rename from testing/test_request.go rename to testing/http/test_request.go index 59c3232b5..1318fe7eb 100644 --- a/testing/test_request.go +++ b/testing/http/test_request.go @@ -1,4 +1,4 @@ -package testing +package http import ( "context" @@ -9,6 +9,9 @@ import ( "net/http/httptest" "testing" + "github.com/goravel/framework/contracts/foundation" + "github.com/goravel/framework/contracts/route" + "github.com/goravel/framework/contracts/session" contractstesting "github.com/goravel/framework/contracts/testing" "github.com/goravel/framework/errors" "github.com/goravel/framework/support/collect" @@ -22,15 +25,21 @@ type TestRequest struct { bind any defaultHeaders map[string]string defaultCookies map[string]string + json foundation.Json + route route.Route + session session.Manager sessionAttributes map[string]any } -func NewTestRequest(t *testing.T) contractstesting.TestRequest { +func NewTestRequest(t *testing.T, json foundation.Json, route route.Route, session session.Manager) contractstesting.TestRequest { return &TestRequest{ t: t, ctx: context.Background(), defaultHeaders: make(map[string]string), defaultCookies: make(map[string]string), + json: json, + route: route, + session: session, sessionAttributes: make(map[string]any), } } @@ -153,23 +162,23 @@ func (r *TestRequest) call(method string, uri string, body io.Reader) (contracts req.AddCookie(&cookie) } - if routeFacade == nil { + if r.route == nil { r.t.Fatal(errors.RouteFacadeNotSet.SetModule(errors.ModuleTesting)) } - response, err := routeFacade.Test(req) + response, err := r.route.Test(req) if err != nil { return nil, err } - testResponse := NewTestResponse(r.t, response) + testResponse := NewTestResponse(r.t, response, r.json, r.session) if r.bind != nil { body, err := testResponse.Content() if err != nil { return nil, err } - if err := json.Unmarshal([]byte(body), r.bind); err != nil { + if err := r.json.Unmarshal([]byte(body), r.bind); err != nil { return nil, err } } @@ -182,18 +191,18 @@ func (r *TestRequest) setSession() error { return nil } - if sessionFacade == nil { + if r.session == nil { return errors.SessionFacadeNotSet } // Retrieve session driver - driver, err := sessionFacade.Driver() + driver, err := r.session.Driver() if err != nil { return err } // Build session - session, err := sessionFacade.BuildSession(driver) + session, err := r.session.BuildSession(driver) if err != nil { return err } @@ -209,6 +218,6 @@ func (r *TestRequest) setSession() error { } // Release session - sessionFacade.ReleaseSession(session) + r.session.ReleaseSession(session) return nil } diff --git a/testing/test_request_test.go b/testing/http/test_request_test.go similarity index 95% rename from testing/test_request_test.go rename to testing/http/test_request_test.go index d652a6b9d..999eae2c2 100644 --- a/testing/test_request_test.go +++ b/testing/http/test_request_test.go @@ -1,4 +1,4 @@ -package testing +package http import ( "bytes" @@ -31,24 +31,19 @@ func TestTestRequestSuite(t *testing.T) { func (s *TestRequestSuite) SetupTest() { s.mockRoute = mocksroute.NewRoute(s.T()) s.mockSessionManager = mockssession.NewManager(s.T()) - json = &testJson{} - routeFacade = s.mockRoute - sessionFacade = s.mockSessionManager + s.testRequest = &TestRequest{ t: s.T(), ctx: context.Background(), defaultHeaders: make(map[string]string), defaultCookies: make(map[string]string), sessionAttributes: make(map[string]any), + json: &testJson{}, + route: s.mockRoute, + session: s.mockSessionManager, } } -func (s *TestRequestSuite) TearDownTest() { - json = nil - routeFacade = nil - sessionFacade = nil -} - func (s *TestRequestSuite) TestBindAndCall() { s.mockRoute.EXPECT().Test(httptest.NewRequest("GET", "/", nil).WithContext(context.Background())).Return(&http.Response{ Body: io.NopCloser(bytes.NewBufferString(`{"name": "John", "age": 30}`)), diff --git a/testing/test_response.go b/testing/http/test_response.go similarity index 93% rename from testing/test_response.go rename to testing/http/test_response.go index c9b1daeae..cc519a649 100644 --- a/testing/test_response.go +++ b/testing/http/test_response.go @@ -1,4 +1,4 @@ -package testing +package http import ( "fmt" @@ -12,6 +12,8 @@ import ( "github.com/stretchr/testify/assert" + "github.com/goravel/framework/contracts/foundation" + contractssession "github.com/goravel/framework/contracts/session" contractstesting "github.com/goravel/framework/contracts/testing" "github.com/goravel/framework/errors" "github.com/goravel/framework/support/carbon" @@ -22,11 +24,18 @@ type TestResponseImpl struct { mu sync.Mutex response *http.Response content string + json foundation.Json + session contractssession.Manager sessionAttributes map[string]any } -func NewTestResponse(t *testing.T, response *http.Response) contractstesting.TestResponse { - return &TestResponseImpl{t: t, response: response} +func NewTestResponse(t *testing.T, response *http.Response, json foundation.Json, session contractssession.Manager) contractstesting.TestResponse { + return &TestResponseImpl{ + t: t, + response: response, + json: json, + session: session, + } } func (r *TestResponseImpl) Json() (map[string]any, error) { @@ -35,7 +44,7 @@ func (r *TestResponseImpl) Json() (map[string]any, error) { return nil, err } - testAble, err := NewAssertableJSON(r.t, content) + testAble, err := NewAssertableJSON(r.t, r.json, content) if err != nil { return nil, err } @@ -60,24 +69,24 @@ func (r *TestResponseImpl) Session() (map[string]any, error) { return r.sessionAttributes, nil } - if sessionFacade == nil { + if r.session == nil { return nil, errors.SessionFacadeNotSet } // Retrieve session driver - driver, err := sessionFacade.Driver() + driver, err := r.session.Driver() if err != nil { return nil, err } // Build session - session, err := sessionFacade.BuildSession(driver) + session, err := r.session.BuildSession(driver) if err != nil { return nil, err } r.sessionAttributes = session.All() - sessionFacade.ReleaseSession(session) + r.session.ReleaseSession(session) return r.sessionAttributes, nil } @@ -352,7 +361,7 @@ func (r *TestResponseImpl) AssertJson(data map[string]any) contractstesting.Test content, err := r.getContent() assert.Nil(r.t, err) - assertableJson, err := NewAssertableJSON(r.t, content) + assertableJson, err := NewAssertableJSON(r.t, r.json, content) assert.Nil(r.t, err) for key, value := range data { @@ -386,7 +395,7 @@ func (r *TestResponseImpl) AssertFluentJson(callback func(json contractstesting. content, err := r.getContent() assert.Nil(r.t, err) - assertableJson, err := NewAssertableJSON(r.t, content) + assertableJson, err := NewAssertableJSON(r.t, r.json, content) assert.Nil(r.t, err) callback(assertableJson) diff --git a/testing/test_response_test.go b/testing/http/test_response_test.go similarity index 80% rename from testing/test_response_test.go rename to testing/http/test_response_test.go index ef74ce977..167d87cac 100644 --- a/testing/test_response_test.go +++ b/testing/http/test_response_test.go @@ -1,4 +1,4 @@ -package testing +package http import ( "html" @@ -17,19 +17,19 @@ import ( func TestAssertOk(t *testing.T) { res := createTestResponse(http.StatusOK) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertOk() } func TestAssertCreated(t *testing.T) { res := createTestResponse(http.StatusCreated) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertCreated() } func TestAssertAccepted(t *testing.T) { res := createTestResponse(http.StatusAccepted) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertAccepted() } @@ -37,127 +37,127 @@ func TestAssertNoContent(t *testing.T) { res := createTestResponse(http.StatusNoContent) res.Body = http.NoBody - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertNoContent() } func TestAssertMovedPermanently(t *testing.T) { res := createTestResponse(http.StatusMovedPermanently) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertMovedPermanently() } func TestAssertFound(t *testing.T) { res := createTestResponse(http.StatusFound) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertFound() } func TestAssertNotModified(t *testing.T) { res := createTestResponse(http.StatusNotModified) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertNotModified() } func TestAssertPartialContent(t *testing.T) { res := createTestResponse(http.StatusPartialContent) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertPartialContent() } func TestAssertTemporaryRedirect(t *testing.T) { res := createTestResponse(http.StatusTemporaryRedirect) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertTemporaryRedirect() } func TestAssertBadRequest(t *testing.T) { res := createTestResponse(http.StatusBadRequest) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertBadRequest() } func TestAssertUnauthorized(t *testing.T) { res := createTestResponse(http.StatusUnauthorized) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertUnauthorized() } func TestAssertPaymentRequired(t *testing.T) { res := createTestResponse(http.StatusPaymentRequired) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertPaymentRequired() } func TestAssertForbidden(t *testing.T) { res := createTestResponse(http.StatusForbidden) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertForbidden() } func TestAssertNotFound(t *testing.T) { res := createTestResponse(http.StatusNotFound) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertNotFound() } func TestAssertMethodNotAllowed(t *testing.T) { res := createTestResponse(http.StatusMethodNotAllowed) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertMethodNotAllowed() } func TestAssertNotAcceptable(t *testing.T) { res := createTestResponse(http.StatusNotAcceptable) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertNotAcceptable() } func TestAssertConflict(t *testing.T) { res := createTestResponse(http.StatusConflict) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertConflict() } func TestAssertRequestTimeout(t *testing.T) { res := createTestResponse(http.StatusRequestTimeout) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertRequestTimeout() } func TestAssertGone(t *testing.T) { res := createTestResponse(http.StatusGone) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertGone() } func TestAssertUnsupportedMediaType(t *testing.T) { res := createTestResponse(http.StatusUnsupportedMediaType) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertUnsupportedMediaType() } func TestAssertUnprocessableEntity(t *testing.T) { res := createTestResponse(http.StatusUnprocessableEntity) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertUnprocessableEntity() } func TestAssertTooManyRequests(t *testing.T) { res := createTestResponse(http.StatusTooManyRequests) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertTooManyRequests() } func TestAssertInternalServerError(t *testing.T) { res := createTestResponse(http.StatusInternalServerError) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertInternalServerError() } func TestAssertServiceUnavailable(t *testing.T) { res := createTestResponse(http.StatusServiceUnavailable) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertServiceUnavailable() } @@ -166,7 +166,7 @@ func TestAssertHeader(t *testing.T) { res := createTestResponse(http.StatusCreated) res.Header.Set(headerName, headerValue) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertHeader(headerName, headerValue).AssertCreated() } @@ -174,20 +174,20 @@ func TestAssertHeader(t *testing.T) { func TestAssertHeaderMissing(t *testing.T) { res := createTestResponse(http.StatusCreated) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertHeaderMissing("X-Custom-Header").AssertCreated() } func TestAssertSuccessful(t *testing.T) { res := createTestResponse(http.StatusPartialContent) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertSuccessful() } func TestServerError(t *testing.T) { res := createTestResponse(http.StatusInternalServerError) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertServerError() } @@ -200,7 +200,7 @@ func TestAssertCookie(t *testing.T) { HttpOnly: true, }).String()) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertCookie("session_id", "12345"). AssertCookieNotExpired("session_id"). @@ -215,7 +215,7 @@ func TestAssertCookieExpired(t *testing.T) { Expires: time.Now().Add(-24 * time.Hour), }).String()) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertCookie("session_id", "expired"). AssertCookieExpired("session_id") @@ -224,7 +224,7 @@ func TestAssertCookieExpired(t *testing.T) { func TestAssertCookieMissing(t *testing.T) { res := createTestResponse(http.StatusOK) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertCookieMissing("session_id") } @@ -233,7 +233,7 @@ func TestAssertSee(t *testing.T) { res := createTestResponse(http.StatusOK) res.Body = io.NopCloser(strings.NewReader("Hello, World! This is a test response.")) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertSee([]string{"Hello", "test"}) } @@ -242,7 +242,7 @@ func TestAssertSeeEscaped(t *testing.T) { escapedContent := html.EscapeString("
Hello, World!
") res.Body = io.NopCloser(strings.NewReader(escapedContent)) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertSee([]string{"
Hello, World!
"}, true) } @@ -250,7 +250,7 @@ func TestAssertDontSee(t *testing.T) { res := createTestResponse(http.StatusOK) res.Body = io.NopCloser(strings.NewReader("This is a safe response.")) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertDontSee([]string{"error", "failure"}) } @@ -258,7 +258,7 @@ func TestAssertDontSeeEscaped(t *testing.T) { res := createTestResponse(http.StatusOK) res.Body = io.NopCloser(strings.NewReader("
Unauthorized access
")) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertDontSee([]string{"
Unauthorized access
"}, true) } @@ -266,60 +266,40 @@ func TestAssertSeeInOrder(t *testing.T) { res := createTestResponse(http.StatusOK) res.Body = io.NopCloser(strings.NewReader("Hello, this is a test for seeing values in order.")) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertSeeInOrder([]string{"Hello", "test", "values"}) } func TestAssertJson(t *testing.T) { - json = &testJson{} - defer func() { - json = nil - }() - res := createTestResponse(http.StatusOK) res.Body = io.NopCloser(strings.NewReader(`{"key1": "value1", "key2": 42}`)) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertJson(map[string]any{"key1": "value1"}) } func TestAssertExactJson(t *testing.T) { - json = &testJson{} - defer func() { - json = nil - }() - res := createTestResponse(http.StatusOK) res.Body = io.NopCloser(strings.NewReader(`{"key1": "value1", "key2": 42}`)) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertExactJson(map[string]any{"key1": "value1", "key2": float64(42)}) } func TestAssertJsonMissing(t *testing.T) { - json = &testJson{} - defer func() { - json = nil - }() - res := createTestResponse(http.StatusOK) res.Body = io.NopCloser(strings.NewReader(`{"key1": "value1", "key2": 42}`)) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertJsonMissing(map[string]any{"key3": "value3"}) } func TestAssertFluentJson(t *testing.T) { - json = &testJson{} - defer func() { - json = nil - }() - sampleJson := `{"name": "krishan", "age": 22, "email": "krishan@example.com"}` res := createTestResponse(http.StatusOK) res.Body = io.NopCloser(strings.NewReader(sampleJson)) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertFluentJson(func(json contractstesting.AssertableJSON) { json.Has("name").Where("name", "krishan") @@ -335,7 +315,7 @@ func TestAssertSeeInOrderWithEscape(t *testing.T) { escapedContent := html.EscapeString("Hello,
ordered
values") res.Body = io.NopCloser(strings.NewReader(escapedContent)) - r := NewTestResponse(t, res) + r := NewTestResponse(t, res, &testJson{}, nil) r.AssertSeeInOrder([]string{"Hello,", "
ordered
"}, true) } @@ -343,7 +323,6 @@ func TestSession_Success(t *testing.T) { mockSessionManager := mockssession.NewManager(t) mockDriver := mockssession.NewDriver(t) mockSession := mockssession.NewSession(t) - sessionFacade = mockSessionManager sessionData := map[string]any{ "user_id": 123, @@ -362,7 +341,9 @@ func TestSession_Success(t *testing.T) { response := createTestResponse(http.StatusOK) response.Header.Add("Set-Cookie", cookie.String()) - testResponse := &TestResponseImpl{} + testResponse := &TestResponseImpl{ + session: mockSessionManager, + } session, err := testResponse.Session() require.NoError(t, err) @@ -371,11 +352,12 @@ func TestSession_Success(t *testing.T) { func TestSession_DriverError(t *testing.T) { mockSessionManager := mockssession.NewManager(t) - sessionFacade = mockSessionManager mockSessionManager.On("Driver").Return(nil, errors.New("driver error")).Once() - testResponse := &TestResponseImpl{} + testResponse := &TestResponseImpl{ + session: mockSessionManager, + } _, err := testResponse.Session() require.EqualError(t, err, "driver error") @@ -384,21 +366,22 @@ func TestSession_DriverError(t *testing.T) { func TestSession_BuildSessionError(t *testing.T) { mockSessionManager := mockssession.NewManager(t) mockDriver := mockssession.NewDriver(t) - sessionFacade = mockSessionManager mockSessionManager.On("Driver").Return(mockDriver, nil).Once() mockSessionManager.On("BuildSession", mockDriver).Return(nil, errors.New("build session error")).Once() - testResponse := &TestResponseImpl{} + testResponse := &TestResponseImpl{ + session: mockSessionManager, + } _, err := testResponse.Session() require.EqualError(t, err, "build session error") } func TestSession_SessionFacadeNotSet(t *testing.T) { - sessionFacade = nil - - testResponse := &TestResponseImpl{} + testResponse := &TestResponseImpl{ + session: nil, + } _, err := testResponse.Session() require.ErrorIs(t, err, errors.SessionFacadeNotSet) diff --git a/testing/test_case.go b/testing/test_case.go index 1213f070f..4736f4ff4 100644 --- a/testing/test_case.go +++ b/testing/test_case.go @@ -7,13 +7,14 @@ import ( contractsseeder "github.com/goravel/framework/contracts/database/seeder" contractstesting "github.com/goravel/framework/contracts/testing" "github.com/goravel/framework/errors" + "github.com/goravel/framework/testing/http" ) type TestCase struct { } func (r *TestCase) Http(t *testing.T) contractstesting.TestRequest { - return NewTestRequest(t) + return http.NewTestRequest(t, json, routeFacade, sessionFacade) } func (r *TestCase) Seed(seeders ...contractsseeder.Seeder) {