Implement Phase 4 test coverage
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
//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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user