Files
langgraph/libs/cli/internal/docker/docker_test.go
2026-04-08 04:46:31 -07:00

291 lines
7.7 KiB
Go

package docker
import (
"fmt"
"strings"
"testing"
)
func cleanEmptyLines(s string) string {
lines := strings.Split(s, "\n")
var result []string
for _, line := range lines {
if strings.TrimSpace(line) != "" {
result = append(result, line)
}
}
return strings.Join(result, "\n")
}
var defaultCaps = &DockerCapabilities{
VersionDocker: Version{Major: 26, Minor: 1, Patch: 1},
VersionCompose: Version{Major: 2, Minor: 27, Patch: 0},
HealthcheckStartInterval: false,
}
func TestComposeCustomDBNoDebugger(t *testing.T) {
port := 8123
actual := Compose(defaultCaps, ComposeOpts{
Port: port,
PostgresURI: "custom_postgres_uri",
})
expected := fmt.Sprintf(`services:
langgraph-redis:
image: redis:6
healthcheck:
test: redis-cli ping
interval: 5s
timeout: 1s
retries: 5
langgraph-api:
ports:
- "%d:8000"
depends_on:
langgraph-redis:
condition: service_healthy
environment:
REDIS_URI: redis://langgraph-redis:6379
POSTGRES_URI: custom_postgres_uri`, port)
if cleanEmptyLines(actual) != expected {
t.Errorf("mismatch.\nExpected:\n%s\n\nGot:\n%s", expected, cleanEmptyLines(actual))
}
}
func TestComposeCustomDBWithHealthcheck(t *testing.T) {
port := 8123
capsHC := &DockerCapabilities{
VersionDocker: Version{Major: 26, Minor: 1, Patch: 1},
VersionCompose: Version{Major: 2, Minor: 27, Patch: 0},
HealthcheckStartInterval: true,
}
actual := Compose(capsHC, ComposeOpts{
Port: port,
PostgresURI: "custom_postgres_uri",
})
expected := fmt.Sprintf(`services:
langgraph-redis:
image: redis:6
healthcheck:
test: redis-cli ping
interval: 5s
timeout: 1s
retries: 5
langgraph-api:
ports:
- "%d:8000"
depends_on:
langgraph-redis:
condition: service_healthy
environment:
REDIS_URI: redis://langgraph-redis:6379
POSTGRES_URI: custom_postgres_uri
healthcheck:
test: python /api/healthcheck.py
interval: 60s
start_interval: 1s
start_period: 10s`, port)
if cleanEmptyLines(actual) != expected {
t.Errorf("mismatch.\nExpected:\n%s\n\nGot:\n%s", expected, cleanEmptyLines(actual))
}
}
func TestComposeDefaultDB(t *testing.T) {
port := 8123
actual := Compose(defaultCaps, ComposeOpts{Port: port})
expected := fmt.Sprintf(`volumes:
langgraph-data:
driver: local
services:
langgraph-redis:
image: redis:6
healthcheck:
test: redis-cli ping
interval: 5s
timeout: 1s
retries: 5
langgraph-postgres:
image: pgvector/pgvector:pg16
ports:
- "5433:5432"
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
command:
- postgres
- -c
- shared_preload_libraries=vector
volumes:
- langgraph-data:/var/lib/postgresql/data
healthcheck:
test: pg_isready -U postgres
start_period: 10s
timeout: 1s
retries: 5
interval: 5s
langgraph-api:
ports:
- "%d:8000"
depends_on:
langgraph-redis:
condition: service_healthy
langgraph-postgres:
condition: service_healthy
environment:
REDIS_URI: redis://langgraph-redis:6379
POSTGRES_URI: %s`, port, DefaultPostgresURI)
if cleanEmptyLines(actual) != expected {
t.Errorf("mismatch.\nExpected:\n%s\n\nGot:\n%s", expected, cleanEmptyLines(actual))
}
}
func TestComposeDistributedMode(t *testing.T) {
port := 8123
actual := Compose(defaultCaps, ComposeOpts{
Port: port,
PostgresURI: "custom_postgres_uri",
EngineRuntimeMode: "distributed",
})
expected := fmt.Sprintf(`services:
langgraph-redis:
image: redis:6
healthcheck:
test: redis-cli ping
interval: 5s
timeout: 1s
retries: 5
langgraph-api:
ports:
- "%d:8000"
depends_on:
langgraph-redis:
condition: service_healthy
environment:
REDIS_URI: redis://langgraph-redis:6379
POSTGRES_URI: custom_postgres_uri
N_JOBS_PER_WORKER: "0"`, port)
if cleanEmptyLines(actual) != expected {
t.Errorf("mismatch.\nExpected:\n%s\n\nGot:\n%s", expected, cleanEmptyLines(actual))
}
}
func TestComposeCombinedModeNoNJobs(t *testing.T) {
actual := Compose(defaultCaps, ComposeOpts{
Port: 8123,
EngineRuntimeMode: "combined_queue_worker",
})
if strings.Contains(actual, "N_JOBS_PER_WORKER") {
t.Error("combined mode should not contain N_JOBS_PER_WORKER")
}
}
func TestComposeDebuggerDefaultDB(t *testing.T) {
port := 8123
debuggerPort := 8001
actual := Compose(defaultCaps, ComposeOpts{
Port: port,
DebuggerPort: debuggerPort,
})
expected := fmt.Sprintf(`volumes:
langgraph-data:
driver: local
services:
langgraph-redis:
image: redis:6
healthcheck:
test: redis-cli ping
interval: 5s
timeout: 1s
retries: 5
langgraph-postgres:
image: pgvector/pgvector:pg16
ports:
- "5433:5432"
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
command:
- postgres
- -c
- shared_preload_libraries=vector
volumes:
- langgraph-data:/var/lib/postgresql/data
healthcheck:
test: pg_isready -U postgres
start_period: 10s
timeout: 1s
retries: 5
interval: 5s
langgraph-debugger:
image: langchain/langgraph-debugger
restart: on-failure
depends_on:
langgraph-postgres:
condition: service_healthy
ports:
- "%d:3968"
langgraph-api:
ports:
- "%d:8000"
depends_on:
langgraph-redis:
condition: service_healthy
langgraph-postgres:
condition: service_healthy
environment:
REDIS_URI: redis://langgraph-redis:6379
POSTGRES_URI: %s`, debuggerPort, port, DefaultPostgresURI)
if cleanEmptyLines(actual) != expected {
t.Errorf("mismatch.\nExpected:\n%s\n\nGot:\n%s", expected, cleanEmptyLines(actual))
}
}
func TestParseVersion(t *testing.T) {
tests := []struct {
input string
expected Version
}{
{"1.2.3", Version{1, 2, 3}},
{"v1.2.3", Version{1, 2, 3}},
{"1.2.3-alpha", Version{1, 2, 3}},
{"1.2.3+1", Version{1, 2, 3}},
{"1.2.3-alpha+build", Version{1, 2, 3}},
{"1.2", Version{1, 2, 0}},
{"1", Version{1, 0, 0}},
{"v28.1.1+1", Version{28, 1, 1}},
{"2.0.0-beta.1+exp.sha.5114f85", Version{2, 0, 0}},
{"v3.4.5-rc1+build.123", Version{3, 4, 5}},
}
for _, tc := range tests {
result := ParseVersion(tc.input)
if result != tc.expected {
t.Errorf("ParseVersion(%q) = %v, want %v", tc.input, result, tc.expected)
}
}
}
func TestVersionGreaterOrEqual(t *testing.T) {
tests := []struct {
v, other Version
want bool
}{
{Version{25, 0, 0}, Version{25, 0, 0}, true},
{Version{26, 1, 1}, Version{25, 0, 0}, true},
{Version{24, 9, 9}, Version{25, 0, 0}, false},
}
for _, tc := range tests {
got := tc.v.GreaterOrEqual(tc.other)
if got != tc.want {
t.Errorf("%v.GreaterOrEqual(%v) = %v, want %v", tc.v, tc.other, got, tc.want)
}
}
}