You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Koito/engine/engine_test.go

145 lines
3.5 KiB

package engine_test
import (
"context"
"fmt"
"log"
"net"
"net/http"
"os"
"strconv"
"testing"
"time"
"github.com/gabehf/koito/engine"
"github.com/gabehf/koito/internal/cfg"
"github.com/gabehf/koito/internal/db/psql"
"github.com/gabehf/koito/internal/utils"
"github.com/ory/dockertest/v3"
)
var store *psql.Psql
func getTestGetenv(resource *dockertest.Resource) func(string) string {
dir, err := utils.GenerateRandomString(8)
if err != nil {
panic(err)
}
listener, err := net.Listen("tcp", ":0")
if err != nil {
panic(fmt.Errorf("failed to get an open port: %w", err))
}
defer listener.Close()
port := strconv.Itoa(listener.Addr().(*net.TCPAddr).Port)
return func(env string) string {
switch env {
case cfg.ENABLE_STRUCTURED_LOGGING_ENV:
return "true"
case cfg.LOG_LEVEL_ENV:
return "debug"
case cfg.DATABASE_URL_ENV:
return fmt.Sprintf("postgres://postgres:secret@localhost:%s", resource.GetPort("5432/tcp"))
case cfg.DEFAULT_PASSWORD_ENV:
return "testuser123"
case cfg.DEFAULT_USERNAME_ENV:
return "test"
case cfg.CONFIG_DIR_ENV:
return dir
case cfg.LISTEN_PORT_ENV:
return port
case cfg.ALLOWED_HOSTS_ENV:
return "*"
case cfg.DISABLE_DEEZER_ENV, cfg.DISABLE_COVER_ART_ARCHIVE_ENV, cfg.DISABLE_MUSICBRAINZ_ENV, cfg.SKIP_IMPORT_ENV:
return "true"
default:
return ""
}
}
}
func TestMain(m *testing.M) {
// uses a sensible default on windows (tcp/http) and linux/osx (socket)
pool, err := dockertest.NewPool("")
if err != nil {
log.Fatalf("Could not construct pool: %s", err)
}
// uses pool to try to connect to Docker
err = pool.Client.Ping()
if err != nil {
log.Fatalf("Could not connect to Docker: %s", err)
}
// pulls an image, creates a container based on it and runs it
resource, err := pool.Run("postgres", "latest", []string{"POSTGRES_PASSWORD=secret"})
if err != nil {
log.Fatalf("Could not start resource: %s", err)
}
getenv := getTestGetenv(resource)
err = cfg.Load(getenv)
if err != nil {
log.Fatalf("Could not load cfg: %s", err)
}
// exponential backoff-retry, because the application in the container might not be ready to accept connections yet
if err := pool.Retry(func() error {
var err error
store, err = psql.New()
if err != nil {
log.Println("Failed to connect to test database, retrying...")
return err
}
return store.Ping(context.Background())
}); err != nil {
log.Fatalf("Could not connect to database: %s", err)
}
go engine.Run(getenv, os.Stdout, "vTest")
// Wait until the web server is reachable
for i := 0; i < 20; i++ {
url := fmt.Sprintf("http://%s/apis/web/v1/health", cfg.ListenAddr())
client := &http.Client{
Timeout: 2 * time.Second, // Set your desired timeout
}
resp, err := client.Get(url)
if err != nil {
if i >= 19 {
log.Fatalf("Web server is not reachable: %s", err)
}
log.Printf("Failed to connect to web server at %s, retrying... (%d/20)", url, i+1)
time.Sleep(1 * time.Second)
continue
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
err = nil
break
}
log.Printf("Unexpected status code at %s, retrying... (%d/20)", url, i+1)
time.Sleep(1 * time.Second)
}
code := m.Run()
// You can't defer this because os.Exit doesn't care for defer
if err := pool.Purge(resource); err != nil {
log.Fatalf("Could not purge resource: %s", err)
}
err = os.RemoveAll(cfg.ConfigDir())
if err != nil {
log.Fatalf("Could not remove temporary config dir: %v", err)
}
os.Exit(code)
}
func host() string {
return fmt.Sprintf("http://%s", cfg.ListenAddr())
}