package services import ( "strings" "testing" ) // 托管方式选择是「卸载时删容器还是删 unit」的唯一依据,四条分支都要钉死。 func TestChooseHostRunMode(t *testing.T) { cases := []struct { name string caps *HostCapabilities want string wantErr string }{ { name: "docker 可用 → 容器(即使同时有 systemd 也优先容器)", caps: &HostCapabilities{HasDocker: true, DockerUsable: true, HasSystemd: true}, want: HostRunModeDocker, }, { name: "装了 docker 但 daemon 没起来 → 回退 systemd", caps: &HostCapabilities{HasDocker: true, DockerUsable: false, HasSystemd: true}, want: HostRunModeSystemd, }, { name: "没有 docker 也没有 systemd → 明确报错,不裸跑", caps: &HostCapabilities{HasDocker: false, DockerUsable: false, HasSystemd: false}, wantErr: "既没有可用的 Docker", }, { name: "探测结果缺失 → 报错而不是猜一个", caps: nil, wantErr: "缺少目标机能力探测结果", }, } for _, c := range cases { got, err := chooseHostRunMode(c.caps) if c.wantErr != "" { if err == nil || !strings.Contains(err.Error(), c.wantErr) { t.Fatalf("%s: 期望报错含 %q,实际 got=%q err=%v", c.name, c.wantErr, got, err) } continue } if err != nil { t.Fatalf("%s: 不应报错,实际 %v", c.name, err) } if got != c.want { t.Fatalf("%s: 期望 %q,实际 %q", c.name, c.want, got) } } } func TestNormalizeArch(t *testing.T) { for in, want := range map[string]string{ "x86_64": "amd64", "amd64": "amd64", "aarch64": "arm64", "arm64": "arm64", } { got, err := normalizeArch(in) if err != nil || got != want { t.Fatalf("%s → %q (err=%v),期望 %q", in, got, err, want) } } if _, err := normalizeArch("mips64"); err == nil { t.Fatal("未知架构应报错") } } // 容器名必须带上采集器 ID:同一台机器可能装多个主机采集器, // 用固定名字会互相覆盖(第二个部署把第一个容器删掉)。 func TestPromtailContainerNameIsPerCollector(t *testing.T) { a, b := promtailContainerName(2), promtailContainerName(3) if a == b { t.Fatalf("不同采集器不能共用容器名: %s", a) } if !strings.HasPrefix(a, "lokistack-promtail-") { t.Fatalf("容器名不符合约定: %s", a) } } // 探测摘要要能一眼区分「没装 docker」和「装了但起不来」——这两种处置完全不同。 func TestDockerSummaryDistinguishesStates(t *testing.T) { missing := (&HostCapabilities{}).DockerSummary() broken := (&HostCapabilities{HasDocker: true}).DockerSummary() ok := (&HostCapabilities{HasDocker: true, DockerUsable: true, DockerVersion: "27.5.1", DockerEnabled: "enabled"}).DockerSummary() if !strings.Contains(missing, "未安装") { t.Fatalf("未安装 docker 的摘要不对: %s", missing) } if !strings.Contains(broken, "不可用") || strings.Contains(broken, "未安装") { t.Fatalf("装了但不可用的摘要不对: %s", broken) } if !strings.Contains(ok, "27.5.1") || !strings.Contains(ok, "enabled") { t.Fatalf("可用状态的摘要不对: %s", ok) } }