mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-06-04 04:22:57 +00:00
202 lines
6.7 KiB
Go
202 lines
6.7 KiB
Go
package api
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/docker/go-connections/nat"
|
|
)
|
|
|
|
func TestNormalizeDatabaseType(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
want string
|
|
}{
|
|
{input: "postgres", want: "postgresql"},
|
|
{input: "postgresql", want: "postgresql"},
|
|
{input: "pg", want: "postgresql"},
|
|
{input: "redis", want: "redis"},
|
|
{input: "dragonflydb", want: "dragonfly"},
|
|
{input: "dragonfly", want: "dragonfly"},
|
|
{input: "mysql", want: "mysql"},
|
|
{input: "mariadb", want: "mariadb"},
|
|
{input: "mongo", want: "mongodb"},
|
|
{input: "mongodb", want: "mongodb"},
|
|
{input: "clickhouse", want: "clickhouse"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := normalizeDatabaseType(tt.input)
|
|
if got != tt.want {
|
|
t.Fatalf("normalizeDatabaseType(%q) = %q, want %q", tt.input, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDatabaseConnectionURLAndDefaultVersion(t *testing.T) {
|
|
handler := &DatabaseHandler{}
|
|
|
|
cases := []struct {
|
|
dbType string
|
|
urlContains string
|
|
version string
|
|
}{
|
|
{dbType: "postgresql", urlContains: "postgresql://", version: "16.2"},
|
|
{dbType: "redis", urlContains: "redis://", version: "7.2"},
|
|
{dbType: "dragonfly", urlContains: "redis://", version: "1.24"},
|
|
{dbType: "mysql", urlContains: "mysql://", version: "8.4"},
|
|
{dbType: "mariadb", urlContains: "mysql://", version: "11.4"},
|
|
{dbType: "mongodb", urlContains: "mongodb://", version: "7.0"},
|
|
{dbType: "clickhouse", urlContains: "http://", version: "24.8"},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
url := handler.generateConnectionURL(DatabaseService{
|
|
Type: tc.dbType,
|
|
Name: "example",
|
|
})
|
|
if url == "" {
|
|
t.Fatalf("generateConnectionURL returned empty for type %q", tc.dbType)
|
|
}
|
|
if len(tc.urlContains) > 0 && !strings.HasPrefix(url, tc.urlContains) {
|
|
t.Fatalf("generateConnectionURL(%q) = %q, expected prefix %q", tc.dbType, url, tc.urlContains)
|
|
}
|
|
|
|
gotVersion := handler.getDefaultVersion(tc.dbType)
|
|
if gotVersion != tc.version {
|
|
t.Fatalf("getDefaultVersion(%q) = %q, want %q", tc.dbType, gotVersion, tc.version)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBuildDatabaseRuntimePlanSupportsAllTypes(t *testing.T) {
|
|
cases := []struct {
|
|
dbType string
|
|
expectedImage string
|
|
expectedPort nat.Port
|
|
urlPrefix string
|
|
}{
|
|
{dbType: "postgresql", expectedImage: "postgres:16-alpine", expectedPort: nat.Port("5432/tcp"), urlPrefix: "postgresql://"},
|
|
{dbType: "redis", expectedImage: "redis:7-alpine", expectedPort: nat.Port("6379/tcp"), urlPrefix: "redis://"},
|
|
{dbType: "dragonfly", expectedImage: "docker.dragonflydb.io/dragonflydb/dragonfly:latest", expectedPort: nat.Port("6379/tcp"), urlPrefix: "redis://"},
|
|
{dbType: "mysql", expectedImage: "mysql:8.4", expectedPort: nat.Port("3306/tcp"), urlPrefix: "mysql://"},
|
|
{dbType: "mariadb", expectedImage: "mariadb:11", expectedPort: nat.Port("3306/tcp"), urlPrefix: "mysql://"},
|
|
{dbType: "mongodb", expectedImage: "mongo:7", expectedPort: nat.Port("27017/tcp"), urlPrefix: "mongodb://"},
|
|
{dbType: "clickhouse", expectedImage: "clickhouse/clickhouse-server:24.8", expectedPort: nat.Port("8123/tcp"), urlPrefix: "http://"},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
plan, err := buildDatabaseRuntimePlan(tc.dbType, "My DB", nil)
|
|
if err != nil {
|
|
t.Fatalf("buildDatabaseRuntimePlan(%q) returned error: %v", tc.dbType, err)
|
|
}
|
|
if plan.Image != tc.expectedImage {
|
|
t.Fatalf("buildDatabaseRuntimePlan(%q) image=%q want=%q", tc.dbType, plan.Image, tc.expectedImage)
|
|
}
|
|
if plan.Port != tc.expectedPort {
|
|
t.Fatalf("buildDatabaseRuntimePlan(%q) port=%q want=%q", tc.dbType, plan.Port, tc.expectedPort)
|
|
}
|
|
conn := plan.ConnectionURL("12345")
|
|
if !strings.HasPrefix(conn, tc.urlPrefix) {
|
|
t.Fatalf("buildDatabaseRuntimePlan(%q) connectionURL=%q expected prefix=%q", tc.dbType, conn, tc.urlPrefix)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBuildDatabaseRuntimePlanHonorsRuntimeVariables(t *testing.T) {
|
|
plan, err := buildDatabaseRuntimePlan("postgresql", "mydb", map[string]string{
|
|
"POSTGRES_USER": "template_user",
|
|
"POSTGRES_PASSWORD": "template_pass",
|
|
"POSTGRES_DB": "template_db",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("buildDatabaseRuntimePlan returned error: %v", err)
|
|
}
|
|
|
|
envJoined := strings.Join(plan.Env, " ")
|
|
if !strings.Contains(envJoined, "POSTGRES_USER=template_user") {
|
|
t.Fatalf("expected POSTGRES_USER override in env, got: %s", envJoined)
|
|
}
|
|
if !strings.Contains(envJoined, "POSTGRES_PASSWORD=template_pass") {
|
|
t.Fatalf("expected POSTGRES_PASSWORD override in env, got: %s", envJoined)
|
|
}
|
|
if !strings.Contains(envJoined, "POSTGRES_DB=template_db") {
|
|
t.Fatalf("expected POSTGRES_DB override in env, got: %s", envJoined)
|
|
}
|
|
|
|
url := plan.ConnectionURL("54321")
|
|
if !strings.Contains(url, "template_user:template_pass") || !strings.Contains(url, "/template_db") {
|
|
t.Fatalf("expected connection URL to reflect runtime overrides, got: %s", url)
|
|
}
|
|
}
|
|
|
|
func TestGenerateDatabaseIDIncludesRandomSuffix(t *testing.T) {
|
|
id1 := generateDatabaseID("Main DB")
|
|
id2 := generateDatabaseID("Main DB")
|
|
if id1 == id2 {
|
|
t.Fatalf("expected generateDatabaseID to produce unique values, got identical id %q", id1)
|
|
}
|
|
if !strings.HasPrefix(id1, "db_") || !strings.Contains(id1, "_main_db_") {
|
|
t.Fatalf("unexpected database id format: %s", id1)
|
|
}
|
|
}
|
|
|
|
func TestManagedDatabaseNamesAreBoundedAndStable(t *testing.T) {
|
|
id := "db_1234567890_this-is-a-very-very-very-very-very-long-name"
|
|
containerName := managedDatabaseContainerName(id)
|
|
volumeName := managedDatabaseVolumeName(id)
|
|
|
|
if containerName == "" || volumeName == "" {
|
|
t.Fatal("expected non-empty managed runtime names")
|
|
}
|
|
if len(containerName) > 63 {
|
|
t.Fatalf("container name too long: %d", len(containerName))
|
|
}
|
|
if len(volumeName) > 63 {
|
|
t.Fatalf("volume name too long: %d", len(volumeName))
|
|
}
|
|
if !strings.HasPrefix(containerName, "containr-db-") {
|
|
t.Fatalf("unexpected container prefix: %s", containerName)
|
|
}
|
|
if !strings.HasPrefix(volumeName, "containr-db-vol-") {
|
|
t.Fatalf("unexpected volume prefix: %s", volumeName)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeBackupArchivePath(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
want string
|
|
}{
|
|
{input: "backup_abc.tar.gz", want: "backup_abc.tar.gz"},
|
|
{input: "/tmp/../../danger", want: "tmp_danger.tar.gz"},
|
|
{input: " weird name ", want: "weird_name.tar.gz"},
|
|
{input: "", want: "backup.tar.gz"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := sanitizeBackupArchivePath(tt.input)
|
|
if got != tt.want {
|
|
t.Fatalf("sanitizeBackupArchivePath(%q) = %q, want %q", tt.input, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestHumanReadableBytes(t *testing.T) {
|
|
tests := []struct {
|
|
size int64
|
|
want string
|
|
}{
|
|
{size: 0, want: "0 B"},
|
|
{size: 1024, want: "1.00 KB"},
|
|
{size: 1048576, want: "1.00 MB"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := humanReadableBytes(tt.size)
|
|
if got != tt.want {
|
|
t.Fatalf("humanReadableBytes(%d) = %q, want %q", tt.size, got, tt.want)
|
|
}
|
|
}
|
|
}
|