package scripts import ( "os" "strings" "testing" ) func TestDockerDeploymentContainsOnlyDobotAIApplication(t *testing.T) { compose, err := os.ReadFile("../deploy/dobotai-dingtalk/compose.yaml") if err != nil { t.Fatal(err) } source := string(compose) for _, required := range []string{"dobotai-dingtalk:", "container_name: dobotai-dingtalk", "network_mode: host", "env_file:", "read_only: true"} { if !strings.Contains(source, required) { t.Errorf("compose missing %q", required) } } for _, forbidden := range []string{"dobotai-postgres", "postgres-data", "name: dobotai-network"} { if strings.Contains(source, forbidden) { t.Errorf("compose must not manage a local database resource %q", forbidden) } } } func TestRootInstallerBuildsImageWithoutOperatorImageArgument(t *testing.T) { data, err := os.ReadFile("../install-docker.sh") if err != nil { t.Fatal(err) } source := string(data) for _, required := range []string{"docker build", "dobotai-dingtalk:local-", "install_docker_if_missing", "DOBOTAI_SOURCE_ROOT", "deploy/dobotai-dingtalk/install-docker.sh"} { if !strings.Contains(source, required) { t.Errorf("root installer missing %q", required) } } if strings.Contains(source, "${DOBOTAI_IMAGE") { t.Fatal("root installer must not require DOBOTAI_IMAGE") } } func TestDockerfilePropagatesConfiguredGoProxyToModuleDownload(t *testing.T) { data, err := os.ReadFile("../Dockerfile") if err != nil { t.Fatal(err) } source := string(data) for _, required := range []string{"ARG GOPROXY=", "ENV GOPROXY=${GOPROXY}", "RUN go mod download"} { if !strings.Contains(source, required) { t.Errorf("Dockerfile missing %q", required) } } if !(strings.Index(source, "ENV GOPROXY=${GOPROXY}") < strings.Index(source, "RUN go mod download")) { t.Fatal("Dockerfile must set GOPROXY before downloading modules") } } func TestRDSInitializerOnlyInitializesEmptySchemaAndRejectsInconsistentSchema(t *testing.T) { data, err := os.ReadFile("../deploy/dobotai-dingtalk/rds-schema-init.sh") if err != nil { t.Fatal(err) } source := string(data) for _, required := range []string{"pg_isready", "to_regclass('public.turns')", "empty", "normal", "inconsistent", "数据库不存在", "*.up.sql", "DATABASE_URL", "postgres:16-alpine"} { if !strings.Contains(source, required) { t.Errorf("RDS initializer missing %q", required) } } for _, forbidden := range []string{"docker compose", "dobotai-postgres", "pg_dump -Fc", "DROP DATABASE", "DROP SCHEMA"} { if strings.Contains(source, forbidden) { t.Errorf("RDS initializer must not manage or destroy databases: %q", forbidden) } } } func TestRDSCredentialConfiguratorPromptsForExternalDatabase(t *testing.T) { data, err := os.ReadFile("../deploy/dobotai-dingtalk/configure_env.py") if err != nil { t.Fatal(err) } source := string(data) for _, required := range []string{"DATABASE_URL", "阿里云RDS", "RDS主机地址", "RDS端口", "数据库名", "数据库账号", "数据库密码", "快速问答Agent ID", "智能推理Agent ID", "getpass.getpass", "os.replace", "0o600", "OSS整组录入", "DOBOTAI_OUTBOUND_IMAGE_OSS_ACCESS_KEY_SECRET"} { if !strings.Contains(source, required) { t.Errorf("RDS configurator missing %q", required) } } if strings.Contains(source, "RDS PostgreSQL连接串") { t.Fatal("operator must not be asked to type a whole DATABASE_URL string") } if strings.Contains(source, "DobotAI租户键") || strings.Contains(source, "Agent Bindings JSON") || strings.Contains(source, "DobotAI Ingress Token") { t.Fatal("operator must only be prompted for real RDS, WeKnora and DingTalk configuration") } installer, err := os.ReadFile("../deploy/dobotai-dingtalk/install-docker.sh") if err != nil { t.Fatal(err) } if !strings.Contains(string(installer), "secrets.token_hex") || !strings.Contains(string(installer), "secrets.token_urlsafe") || !strings.Contains(string(installer), "DOBOTAI_TENANT_KEY=dobotai-") { t.Fatal("installer must generate and persist internal tenant and ingress tokens") } }