package apps import ( "os" "path/filepath" "strings" "testing" ) func TestKeyForURL(t *testing.T) { cases := []struct { raw, want string }{ // Default ports are PRESERVED — no port-stripping (the previous // behavior conflated "operator wrote :443" with "operator wrote // bare host"; with the full origin in the key, every URL maps // to exactly one path). {"https://zddc.varasys.io/releases/archive_stable.html", "https/zddc.varasys.io/releases/archive_stable.html"}, {"https://ZDDC.Varasys.IO/releases/archive_stable.html", "https/zddc.varasys.io/releases/archive_stable.html"}, {"http://example.com/foo.html", "http/example.com/foo.html"}, {"http://example.com:80/foo.html", "http/example.com:80/foo.html"}, {"https://example.com/foo.html", "https/example.com/foo.html"}, {"https://example.com:443/foo.html", "https/example.com:443/foo.html"}, {"https://example.com:8443/foo.html", "https/example.com:8443/foo.html"}, // Scheme segregation: same host+path under http and https map // to different cache entries (defensive against reverse-proxy // stacks that legitimately serve different bytes per scheme). {"http://example.com/x.html", "http/example.com/x.html"}, {"https://example.com/x.html", "https/example.com/x.html"}, // Path normalization preserved. {"https://example.com/", "https/example.com/index.html"}, {"https://example.com", "https/example.com/index.html"}, {"https://example.com//foo//bar.html", "https/example.com/foo/bar.html"}, } for _, tc := range cases { t.Run(tc.raw, func(t *testing.T) { got, err := keyForURL(tc.raw) if err != nil { t.Fatalf("keyForURL error: %v", err) } if got != tc.want { t.Errorf("got %q, want %q", got, tc.want) } }) } } // TestKeyForURL_NoCollisions: explicit assertion that the dimensions // previously collapsed (default-port ↔ bare-host, http ↔ https) are // now distinct. Any future change that re-introduces collapsing will // fail this test. func TestKeyForURL_NoCollisions(t *testing.T) { pairs := [][2]string{ // Different scheme, same host+path {"http://example.com/x.html", "https://example.com/x.html"}, // https default port preserved (not collapsed onto bare host) {"https://example.com/x.html", "https://example.com:443/x.html"}, // http default port preserved {"http://example.com/x.html", "http://example.com:80/x.html"}, // Different non-default ports {"https://example.com:8443/x.html", "https://example.com:9443/x.html"}, } for _, p := range pairs { t.Run(p[0]+" vs "+p[1], func(t *testing.T) { a, err := keyForURL(p[0]) if err != nil { t.Fatalf("keyForURL(%q): %v", p[0], err) } b, err := keyForURL(p[1]) if err != nil { t.Fatalf("keyForURL(%q): %v", p[1], err) } if a == b { t.Errorf("collision: %q and %q both → %q", p[0], p[1], a) } }) } } func TestKeyForURL_Errors(t *testing.T) { cases := []string{ "", "not-a-url", "ftp://example.com/x.html", "https:///x.html", "https://example.com/x.html?v=1", } for _, tc := range cases { t.Run(tc, func(t *testing.T) { if _, err := keyForURL(tc); err == nil { t.Errorf("keyForURL(%q) = nil, want error", tc) } }) } } func TestCacheRoundtrip(t *testing.T) { c, err := NewCache(filepath.Join(t.TempDir(), "_app")) if err != nil { t.Fatalf("NewCache: %v", err) } urlStr := "https://zddc.varasys.io/releases/archive_stable.html" body := []byte("archive content") if c.Has(urlStr) { t.Fatalf("Has(empty cache) = true, want false") } if err := c.Write(urlStr, body); err != nil { t.Fatalf("Write: %v", err) } if !c.Has(urlStr) { t.Fatalf("Has(after write) = false, want true") } got, err := c.Read(urlStr) if err != nil { t.Fatalf("Read: %v", err) } if string(got) != string(body) { t.Errorf("body mismatch") } } func TestCacheAtomicWrite_LeavesNoTempOnSuccess(t *testing.T) { root := filepath.Join(t.TempDir(), "_app") c, _ := NewCache(root) urlStr := "https://zddc.varasys.io/releases/archive_stable.html" if err := c.Write(urlStr, []byte("hello")); err != nil { t.Fatalf("Write: %v", err) } count := 0 _ = filepath.Walk(root, func(p string, info os.FileInfo, err error) error { if err != nil { return err } if !info.IsDir() && strings.Contains(info.Name(), ".tmp.") { count++ } return nil }) if count != 0 { t.Errorf("found %d .tmp.* leftovers, want 0", count) } } func TestCacheSweepsTempsOnNew(t *testing.T) { root := filepath.Join(t.TempDir(), "_app") stale := filepath.Join(root, "example.com", "releases", "archive_stable.html.tmp.123") if err := os.MkdirAll(filepath.Dir(stale), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(stale, []byte("partial"), 0o644); err != nil { t.Fatal(err) } if _, err := NewCache(root); err != nil { t.Fatalf("NewCache: %v", err) } if _, err := os.Stat(stale); !os.IsNotExist(err) { t.Errorf("stale tmp file not swept: %v", err) } }