99 lines
2.7 KiB
Go
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")
|
|
}
|
|
}
|