package registry import ( "bytes" "encoding/json" "os" "path/filepath" "testing" "time" ) func TestMultipleTargetsForSameVersion(t *testing.T) { store, err := New(t.TempDir()) if err != nil { t.Fatal(err) } base := Package{Name: "multi-demo", Version: "1.0.0", Channel: "stable", Status: "published"} linux, err := store.AddArtifact(base, Target{ Platform: "linux", Architecture: "amd64", PackageType: "full", FileName: "linux.pkg", }, bytes.NewBufferString("linux")) if err != nil { t.Fatal(err) } windows, err := store.AddArtifact(base, Target{ Platform: "windows", Architecture: "amd64", PackageType: "full", FileName: "windows.pkg", }, bytes.NewBufferString("windows")) if err != nil { t.Fatal(err) } if linux.SHA256 == windows.SHA256 { t.Fatal("\u4e0d\u540c\u4ea7\u7269\u7684\u6821\u9a8c\u503c\u4e0d\u5e94\u76f8\u540c") } linuxLatest, ok := store.LatestFor("multi-demo", "linux", "amd64", "stable", "") if !ok || linuxLatest.FileName != "linux.pkg" || len(linuxLatest.Targets) != 1 { t.Fatalf("Linux \u76ee\u6807\u9009\u62e9\u9519\u8bef: %+v", linuxLatest) } windowsLatest, ok := store.LatestFor("multi-demo", "windows", "amd64", "stable", "") if !ok || windowsLatest.FileName != "windows.pkg" { t.Fatalf("Windows \u76ee\u6807\u9009\u62e9\u9519\u8bef: %+v", windowsLatest) } } func TestTargetPriorityAndDeltaSource(t *testing.T) { item := Package{ Name: "priority-demo", Version: "2.0.0", Channel: "stable", Status: "published", Targets: []Target{ {ID: "fallback", Platform: "any", Architecture: "universal", PackageType: "full"}, {ID: "linux", Platform: "linux", Architecture: "universal", PackageType: "full"}, {ID: "exact-full", Platform: "linux", Architecture: "amd64", PackageType: "full"}, {ID: "exact-delta", Platform: "linux", Architecture: "amd64", PackageType: "delta", UpgradeFrom: []string{"1.5.0"}}, }, } selected, ok := SelectTarget(item, "linux", "amd64", "1.5.0") if !ok || selected.Targets[0].ID != "exact-delta" { t.Fatalf("\u5dee\u5206\u5305\u4f18\u5148\u7ea7\u9519\u8bef: %+v", selected.Targets) } selected, ok = SelectTarget(item, "linux", "amd64", "1.4.0") if !ok || selected.Targets[0].ID != "exact-full" { t.Fatalf("\u5b8c\u6574\u5305\u56de\u9000\u9009\u62e9\u9519\u8bef: %+v", selected.Targets) } selected, ok = SelectTarget(item, "linux", "arm64", "1.4.0") if !ok || selected.Targets[0].ID != "linux" { t.Fatalf("\u901a\u7528\u67b6\u6784\u9009\u62e9\u9519\u8bef: %+v", selected.Targets) } if _, ok := SelectTarget(item, "windows", "arm64", "1.4.0"); !ok { t.Fatal("any/universal \u76ee\u6807\u5e94\u5f53\u53ef\u7528") } } func TestLegacyReleaseCanBeLoaded(t *testing.T) { root := t.TempDir() versionDir := filepath.Join(root, "legacy-demo", "1.0.0") if err := os.MkdirAll(versionDir, 0o755); err != nil { t.Fatal(err) } legacy := Package{ Name: "legacy-demo", Version: "1.0.0", FileName: "legacy.pkg", Size: 6, SHA256: "legacy-digest", UploadedAt: time.Now().UTC(), } data, err := json.Marshal(legacy) if err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(versionDir, "metadata.json"), data, 0o644); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(versionDir, "package.bin"), []byte("legacy"), 0o644); err != nil { t.Fatal(err) } store, err := New(root) if err != nil { t.Fatal(err) } item, ok := store.LatestFor("legacy-demo", "linux", "amd64", "stable", "") if !ok || item.Platform != "any" || item.Architecture != "universal" { t.Fatalf("\u65e7\u6570\u636e\u517c\u5bb9\u5931\u8d25: %+v", item) } file, _, err := store.OpenPackageFor("legacy-demo", "1.0.0", "linux", "amd64", "", "") if err != nil { t.Fatal(err) } file.Close() } func TestOnlyPublishedReleaseBroadcasts(t *testing.T) { store, err := New(t.TempDir()) if err != nil { t.Fatal(err) } updates, unsubscribe := store.Subscribe() defer unsubscribe() _, err = store.AddArtifact(Package{ Name: "draft-demo", Version: "1.0.0", Status: "draft", }, Target{Platform: "linux", Architecture: "amd64", FileName: "draft.pkg"}, bytes.NewBufferString("draft")) if err != nil { t.Fatal(err) } select { case update := <-updates: t.Fatalf("\u8349\u7a3f\u4e0d\u5e94\u53d1\u9001\u901a\u77e5: %+v", update) case <-time.After(50 * time.Millisecond): } }