Files
GitOcean-Old/internal/app/migration_integration_test.go
2026-06-08 15:03:41 -05:00

99 lines
2.7 KiB
Go

//go:build integration
package app
import (
"database/sql"
"os"
"strings"
"testing"
"time"
"github.com/go-sql-driver/mysql"
)
func TestIntegrationMigrationsAreIdempotent(t *testing.T) {
dsn := os.Getenv("GITOOCEAN_TEST_MYSQL_DSN")
if dsn == "" {
t.Skip("set GITOOCEAN_TEST_MYSQL_DSN to run integration migration tests")
}
cfg, err := mysql.ParseDSN(dsn)
if err != nil {
t.Fatal(err)
}
if cfg.DBName == "" || !strings.Contains(cfg.DBName, "test") {
t.Fatalf("refusing to run integration test against non-test database %q", cfg.DBName)
}
db, err := openMySQLAndCreateDatabaseIfMissing(dsn)
if err != nil {
t.Fatal(err)
}
defer db.Close()
if err := resetIntegrationDB(db); err != nil {
t.Fatal(err)
}
if err := migrate(db); err != nil {
t.Fatal(err)
}
if err := migrate(db); err != nil {
t.Fatalf("second migrate should be idempotent: %v", err)
}
for _, table := range []string{"users", "auth_tokens", "repositories", "repository_collaborators", "pull_requests", "pull_request_comments"} {
var name string
if err := db.QueryRow("SHOW TABLES LIKE ?", table).Scan(&name); err != nil {
t.Fatalf("expected table %s: %v", table, err)
}
}
}
func resetIntegrationDB(db *sql.DB) error {
_, _ = db.Exec("SET FOREIGN_KEY_CHECKS=0")
for _, table := range []string{"pull_request_comments", "pull_requests", "repository_collaborators", "auth_tokens", "repositories", "users"} {
_, _ = db.Exec("DROP TABLE IF EXISTS " + quoteMySQLIdentifier(table))
}
_, err := db.Exec("SET FOREIGN_KEY_CHECKS=1")
return err
}
func TestIntegrationAuthTokenLifecycle(t *testing.T) {
dsn := os.Getenv("GITOOCEAN_TEST_MYSQL_DSN")
if dsn == "" {
t.Skip("set GITOOCEAN_TEST_MYSQL_DSN to run integration auth tests")
}
db, err := openMySQLAndCreateDatabaseIfMissing(dsn)
if err != nil {
t.Fatal(err)
}
defer db.Close()
if err := resetIntegrationDB(db); err != nil {
t.Fatal(err)
}
if err := migrate(db); err != nil {
t.Fatal(err)
}
if err := createUserDirect(db, "alice@example.com", "alice", "password123", true); err != nil {
t.Fatal(err)
}
s := &Server{db: db, storage: t.TempDir(), publicURL: "http://example.test"}
token, expires, err := s.createToken(1)
if err != nil {
t.Fatal(err)
}
if time.Until(expires) < tokenTTL-time.Minute {
t.Fatalf("unexpected expiry: %s", expires)
}
user, err := s.userFromToken(token, "alice")
if err != nil {
t.Fatal(err)
}
if user.Username != "alice" || !user.IsAdmin {
t.Fatalf("unexpected user from token: %#v", user)
}
if _, err := db.Exec("UPDATE auth_tokens SET revoked_at = UTC_TIMESTAMP() WHERE token_hash = ?", hashToken(token)); err != nil {
t.Fatal(err)
}
if _, err := s.userFromToken(token, "alice"); err == nil {
t.Fatal("expected revoked token to be rejected")
}
}