|
7 | 7 | "strings" |
8 | 8 | "sync/atomic" |
9 | 9 | "testing" |
| 10 | + "time" |
10 | 11 |
|
11 | 12 | "github.com/git-pkgs/registries/fetch" |
12 | 13 | ) |
@@ -137,3 +138,88 @@ func TestMavenRepositoryRepointedServesTheNewUpstream(t *testing.T) { |
137 | 138 | } |
138 | 139 | } |
139 | 140 | } |
| 141 | + |
| 142 | +// TestMavenDottedGroupDirectoryNotCachedAsGroup checks that a file whose |
| 143 | +// group directories contain dots or colons, which the Maven layout never |
| 144 | +// has, is not served: it would either share the cache entry of the group |
| 145 | +// the dots spell or be proxied past the denylist, scan and cooldown. |
| 146 | +func TestMavenDottedGroupDirectoryNotCachedAsGroup(t *testing.T) { |
| 147 | + const standard = "/org/foo/bar/1.0/bar-1.0.jar" |
| 148 | + odd := []string{ |
| 149 | + "/org.foo/bar/1.0/bar-1.0.jar", "/org.foo/bar/1.0/bar-1.0-linux.exe", |
| 150 | + "/org/foo:x/bar/1.0/bar-1.0.jar", "/org/foo/b:ar/1.0/b:ar-1.0.jar", |
| 151 | + } |
| 152 | + central, requests := mavenRepoUpstream(t, "central", append([]string{standard}, odd...)...) |
| 153 | + portal, _ := mavenRepoUpstream(t, "portal") |
| 154 | + var restricted []string |
| 155 | + for _, p := range odd { |
| 156 | + restricted = append(restricted, "/restricted"+p) |
| 157 | + } |
| 158 | + grails, grailsRequests := mavenRepoUpstream(t, "grails", restricted...) |
| 159 | + h := newMavenRepositoriesHandler(t, central, portal, grails) |
| 160 | + |
| 161 | + if w := getMaven(h, standard); w.Code != http.StatusOK || w.Body.String() != "central "+standard { |
| 162 | + t.Errorf("GET %s = %d %q", standard, w.Code, w.Body.String()) |
| 163 | + } |
| 164 | + before := requests.Load() + grailsRequests.Load() |
| 165 | + for _, p := range odd { |
| 166 | + for _, path := range []string{p, "/grails" + p} { |
| 167 | + if w := getMaven(h, path); w.Code != http.StatusNotFound { |
| 168 | + t.Errorf("GET %s = %d %q, want 404", path, w.Code, w.Body.String()) |
| 169 | + } |
| 170 | + } |
| 171 | + } |
| 172 | + if n := requests.Load() + grailsRequests.Load() - before; n != 0 { |
| 173 | + t.Errorf("%d upstream requests for paths outside the Maven layout", n) |
| 174 | + } |
| 175 | +} |
| 176 | + |
| 177 | +// TestMavenUncachedPathFallsBackToPluginPortal checks that a path proxied |
| 178 | +// without caching, such as a catalog, still tries the Gradle Plugin Portal |
| 179 | +// when the primary upstream lacks it. |
| 180 | +func TestMavenUncachedPathFallsBackToPluginPortal(t *testing.T) { |
| 181 | + const uncached = "/org/foo/archetype-catalog.xml" |
| 182 | + central, _ := mavenRepoUpstream(t, "central") |
| 183 | + portal, _ := mavenRepoUpstream(t, "portal", uncached) |
| 184 | + grails, _ := mavenRepoUpstream(t, "grails") |
| 185 | + h := newMavenRepositoriesHandler(t, central, portal, grails) |
| 186 | + |
| 187 | + if w := getMaven(h, uncached); w.Code != http.StatusOK || w.Body.String() != "portal "+uncached { |
| 188 | + t.Errorf("GET %s = %d %q, want the Plugin Portal's copy", uncached, w.Code, w.Body.String()) |
| 189 | + } |
| 190 | +} |
| 191 | + |
| 192 | +func TestMavenUncachedPathKeepsByteRanges(t *testing.T) { |
| 193 | + const uncached = "/org/foo/archetype-catalog.xml" |
| 194 | + ranged := func() *httptest.Server { |
| 195 | + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 196 | + w.Header().Set("ETag", `"v2"`) |
| 197 | + http.ServeContent(w, r, "archetype-catalog.xml", time.Time{}, strings.NewReader("0123456789")) |
| 198 | + })) |
| 199 | + t.Cleanup(srv.Close) |
| 200 | + return srv |
| 201 | + } |
| 202 | + central, grails := ranged(), ranged() |
| 203 | + portal, _ := mavenRepoUpstream(t, "portal") |
| 204 | + h := newMavenRepositoriesHandler(t, central, portal, grails) |
| 205 | + |
| 206 | + for _, p := range []string{uncached, "/grails" + uncached} { |
| 207 | + req := httptest.NewRequest(http.MethodGet, p, nil) |
| 208 | + req.Header.Set("Range", "bytes=2-4") |
| 209 | + w := httptest.NewRecorder() |
| 210 | + h.ServeHTTP(w, req) |
| 211 | + if w.Code != http.StatusPartialContent || w.Body.String() != "234" { |
| 212 | + t.Errorf("GET %s with Range = %d %q, want 206 %q", p, w.Code, w.Body.String(), "234") |
| 213 | + } |
| 214 | + |
| 215 | + // A Range for an older copy gets the whole current file. |
| 216 | + req = httptest.NewRequest(http.MethodGet, p, nil) |
| 217 | + req.Header.Set("Range", "bytes=2-4") |
| 218 | + req.Header.Set("If-Range", `"v1"`) |
| 219 | + w = httptest.NewRecorder() |
| 220 | + h.ServeHTTP(w, req) |
| 221 | + if w.Code != http.StatusOK || w.Body.String() != "0123456789" { |
| 222 | + t.Errorf("GET %s with stale If-Range = %d %q, want 200 with the whole file", p, w.Code, w.Body.String()) |
| 223 | + } |
| 224 | + } |
| 225 | +} |
0 commit comments