|
6 | 6 | "encoding/json"
|
7 | 7 | "net/http"
|
8 | 8 | "net/url"
|
| 9 | + "strings" |
9 | 10 | "testing"
|
10 | 11 | "time"
|
11 | 12 |
|
@@ -2212,63 +2213,239 @@ func Test_resolveGitReference(t *testing.T) {
|
2212 | 2213 | ctx := context.Background()
|
2213 | 2214 | owner := "owner"
|
2214 | 2215 | repo := "repo"
|
2215 |
| - mockedClient := mock.NewMockedHTTPClient( |
2216 |
| - mock.WithRequestMatchHandler( |
2217 |
| - mock.GetReposByOwnerByRepo, |
2218 |
| - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { |
2219 |
| - w.WriteHeader(http.StatusOK) |
2220 |
| - _, _ = w.Write([]byte(`{"name": "repo", "default_branch": "main"}`)) |
2221 |
| - }), |
2222 |
| - ), |
2223 |
| - mock.WithRequestMatchHandler( |
2224 |
| - mock.GetReposGitRefByOwnerByRepoByRef, |
2225 |
| - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { |
2226 |
| - w.WriteHeader(http.StatusOK) |
2227 |
| - _, _ = w.Write([]byte(`{"ref": "refs/heads/main", "object": {"sha": "123sha456"}}`)) |
2228 |
| - }), |
2229 |
| - ), |
2230 |
| - ) |
2231 | 2216 |
|
2232 | 2217 | tests := []struct {
|
2233 | 2218 | name string
|
2234 | 2219 | ref string
|
2235 | 2220 | sha string
|
| 2221 | + mockSetup func() *http.Client |
2236 | 2222 | expectedOutput *raw.ContentOpts
|
| 2223 | + expectError bool |
| 2224 | + errorContains string |
2237 | 2225 | }{
|
2238 | 2226 | {
|
2239 | 2227 | name: "sha takes precedence over ref",
|
2240 | 2228 | ref: "refs/heads/main",
|
2241 | 2229 | sha: "123sha456",
|
| 2230 | + mockSetup: func() *http.Client { |
| 2231 | + // No API calls should be made when SHA is provided |
| 2232 | + return mock.NewMockedHTTPClient() |
| 2233 | + }, |
2242 | 2234 | expectedOutput: &raw.ContentOpts{
|
2243 | 2235 | SHA: "123sha456",
|
2244 | 2236 | },
|
| 2237 | + expectError: false, |
2245 | 2238 | },
|
2246 | 2239 | {
|
2247 | 2240 | name: "use default branch if ref and sha both empty",
|
2248 | 2241 | ref: "",
|
2249 | 2242 | sha: "",
|
| 2243 | + mockSetup: func() *http.Client { |
| 2244 | + return mock.NewMockedHTTPClient( |
| 2245 | + mock.WithRequestMatchHandler( |
| 2246 | + mock.GetReposByOwnerByRepo, |
| 2247 | + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { |
| 2248 | + w.WriteHeader(http.StatusOK) |
| 2249 | + _, _ = w.Write([]byte(`{"name": "repo", "default_branch": "main"}`)) |
| 2250 | + }), |
| 2251 | + ), |
| 2252 | + mock.WithRequestMatchHandler( |
| 2253 | + mock.GetReposGitRefByOwnerByRepoByRef, |
| 2254 | + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 2255 | + assert.Contains(t, r.URL.Path, "/git/ref/heads/main") |
| 2256 | + w.WriteHeader(http.StatusOK) |
| 2257 | + _, _ = w.Write([]byte(`{"ref": "refs/heads/main", "object": {"sha": "main-sha"}}`)) |
| 2258 | + }), |
| 2259 | + ), |
| 2260 | + ) |
| 2261 | + }, |
2250 | 2262 | expectedOutput: &raw.ContentOpts{
|
2251 | 2263 | Ref: "refs/heads/main",
|
2252 |
| - SHA: "123sha456", |
| 2264 | + SHA: "main-sha", |
2253 | 2265 | },
|
| 2266 | + expectError: false, |
2254 | 2267 | },
|
2255 | 2268 | {
|
2256 |
| - name: "get SHA from ref", |
2257 |
| - ref: "refs/heads/main", |
| 2269 | + name: "fully qualified ref passed through unchanged", |
| 2270 | + ref: "refs/heads/feature-branch", |
2258 | 2271 | sha: "",
|
| 2272 | + mockSetup: func() *http.Client { |
| 2273 | + return mock.NewMockedHTTPClient( |
| 2274 | + mock.WithRequestMatchHandler( |
| 2275 | + mock.GetReposGitRefByOwnerByRepoByRef, |
| 2276 | + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 2277 | + assert.Contains(t, r.URL.Path, "/git/ref/heads/feature-branch") |
| 2278 | + w.WriteHeader(http.StatusOK) |
| 2279 | + _, _ = w.Write([]byte(`{"ref": "refs/heads/feature-branch", "object": {"sha": "feature-sha"}}`)) |
| 2280 | + }), |
| 2281 | + ), |
| 2282 | + ) |
| 2283 | + }, |
| 2284 | + expectedOutput: &raw.ContentOpts{ |
| 2285 | + Ref: "refs/heads/feature-branch", |
| 2286 | + SHA: "feature-sha", |
| 2287 | + }, |
| 2288 | + expectError: false, |
| 2289 | + }, |
| 2290 | + { |
| 2291 | + name: "short branch name resolves to refs/heads/", |
| 2292 | + ref: "main", |
| 2293 | + sha: "", |
| 2294 | + mockSetup: func() *http.Client { |
| 2295 | + return mock.NewMockedHTTPClient( |
| 2296 | + mock.WithRequestMatchHandler( |
| 2297 | + mock.GetReposGitRefByOwnerByRepoByRef, |
| 2298 | + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 2299 | + if strings.Contains(r.URL.Path, "/git/ref/heads/main") { |
| 2300 | + w.WriteHeader(http.StatusOK) |
| 2301 | + _, _ = w.Write([]byte(`{"ref": "refs/heads/main", "object": {"sha": "main-sha"}}`)) |
| 2302 | + } else { |
| 2303 | + t.Errorf("Unexpected path: %s", r.URL.Path) |
| 2304 | + w.WriteHeader(http.StatusNotFound) |
| 2305 | + } |
| 2306 | + }), |
| 2307 | + ), |
| 2308 | + ) |
| 2309 | + }, |
2259 | 2310 | expectedOutput: &raw.ContentOpts{
|
2260 | 2311 | Ref: "refs/heads/main",
|
2261 |
| - SHA: "123sha456", |
| 2312 | + SHA: "main-sha", |
| 2313 | + }, |
| 2314 | + expectError: false, |
| 2315 | + }, |
| 2316 | + { |
| 2317 | + name: "short tag name falls back to refs/tags/ when branch not found", |
| 2318 | + ref: "v1.0.0", |
| 2319 | + sha: "", |
| 2320 | + mockSetup: func() *http.Client { |
| 2321 | + return mock.NewMockedHTTPClient( |
| 2322 | + mock.WithRequestMatchHandler( |
| 2323 | + mock.GetReposGitRefByOwnerByRepoByRef, |
| 2324 | + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 2325 | + switch { |
| 2326 | + case strings.Contains(r.URL.Path, "/git/ref/heads/v1.0.0"): |
| 2327 | + w.WriteHeader(http.StatusNotFound) |
| 2328 | + _, _ = w.Write([]byte(`{"message": "Not Found"}`)) |
| 2329 | + case strings.Contains(r.URL.Path, "/git/ref/tags/v1.0.0"): |
| 2330 | + w.WriteHeader(http.StatusOK) |
| 2331 | + _, _ = w.Write([]byte(`{"ref": "refs/tags/v1.0.0", "object": {"sha": "tag-sha"}}`)) |
| 2332 | + default: |
| 2333 | + t.Errorf("Unexpected path: %s", r.URL.Path) |
| 2334 | + w.WriteHeader(http.StatusNotFound) |
| 2335 | + } |
| 2336 | + }), |
| 2337 | + ), |
| 2338 | + ) |
| 2339 | + }, |
| 2340 | + expectedOutput: &raw.ContentOpts{ |
| 2341 | + Ref: "refs/tags/v1.0.0", |
| 2342 | + SHA: "tag-sha", |
| 2343 | + }, |
| 2344 | + expectError: false, |
| 2345 | + }, |
| 2346 | + { |
| 2347 | + name: "heads/ prefix gets refs/ prepended", |
| 2348 | + ref: "heads/feature-branch", |
| 2349 | + sha: "", |
| 2350 | + mockSetup: func() *http.Client { |
| 2351 | + return mock.NewMockedHTTPClient( |
| 2352 | + mock.WithRequestMatchHandler( |
| 2353 | + mock.GetReposGitRefByOwnerByRepoByRef, |
| 2354 | + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 2355 | + assert.Contains(t, r.URL.Path, "/git/ref/heads/feature-branch") |
| 2356 | + w.WriteHeader(http.StatusOK) |
| 2357 | + _, _ = w.Write([]byte(`{"ref": "refs/heads/feature-branch", "object": {"sha": "feature-sha"}}`)) |
| 2358 | + }), |
| 2359 | + ), |
| 2360 | + ) |
| 2361 | + }, |
| 2362 | + expectedOutput: &raw.ContentOpts{ |
| 2363 | + Ref: "refs/heads/feature-branch", |
| 2364 | + SHA: "feature-sha", |
2262 | 2365 | },
|
| 2366 | + expectError: false, |
| 2367 | + }, |
| 2368 | + { |
| 2369 | + name: "tags/ prefix gets refs/ prepended", |
| 2370 | + ref: "tags/v1.0.0", |
| 2371 | + sha: "", |
| 2372 | + mockSetup: func() *http.Client { |
| 2373 | + return mock.NewMockedHTTPClient( |
| 2374 | + mock.WithRequestMatchHandler( |
| 2375 | + mock.GetReposGitRefByOwnerByRepoByRef, |
| 2376 | + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 2377 | + assert.Contains(t, r.URL.Path, "/git/ref/tags/v1.0.0") |
| 2378 | + w.WriteHeader(http.StatusOK) |
| 2379 | + _, _ = w.Write([]byte(`{"ref": "refs/tags/v1.0.0", "object": {"sha": "tag-sha"}}`)) |
| 2380 | + }), |
| 2381 | + ), |
| 2382 | + ) |
| 2383 | + }, |
| 2384 | + expectedOutput: &raw.ContentOpts{ |
| 2385 | + Ref: "refs/tags/v1.0.0", |
| 2386 | + SHA: "tag-sha", |
| 2387 | + }, |
| 2388 | + expectError: false, |
| 2389 | + }, |
| 2390 | + { |
| 2391 | + name: "invalid short name that doesn't exist as branch or tag", |
| 2392 | + ref: "nonexistent", |
| 2393 | + sha: "", |
| 2394 | + mockSetup: func() *http.Client { |
| 2395 | + return mock.NewMockedHTTPClient( |
| 2396 | + mock.WithRequestMatchHandler( |
| 2397 | + mock.GetReposGitRefByOwnerByRepoByRef, |
| 2398 | + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { |
| 2399 | + // Both branch and tag attempts should return 404 |
| 2400 | + w.WriteHeader(http.StatusNotFound) |
| 2401 | + _, _ = w.Write([]byte(`{"message": "Not Found"}`)) |
| 2402 | + }), |
| 2403 | + ), |
| 2404 | + ) |
| 2405 | + }, |
| 2406 | + expectError: true, |
| 2407 | + errorContains: "could not resolve ref \"nonexistent\" as a branch or a tag", |
| 2408 | + }, |
| 2409 | + { |
| 2410 | + name: "fully qualified pull request ref", |
| 2411 | + ref: "refs/pull/123/head", |
| 2412 | + sha: "", |
| 2413 | + mockSetup: func() *http.Client { |
| 2414 | + return mock.NewMockedHTTPClient( |
| 2415 | + mock.WithRequestMatchHandler( |
| 2416 | + mock.GetReposGitRefByOwnerByRepoByRef, |
| 2417 | + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 2418 | + assert.Contains(t, r.URL.Path, "/git/ref/pull/123/head") |
| 2419 | + w.WriteHeader(http.StatusOK) |
| 2420 | + _, _ = w.Write([]byte(`{"ref": "refs/pull/123/head", "object": {"sha": "pr-sha"}}`)) |
| 2421 | + }), |
| 2422 | + ), |
| 2423 | + ) |
| 2424 | + }, |
| 2425 | + expectedOutput: &raw.ContentOpts{ |
| 2426 | + Ref: "refs/pull/123/head", |
| 2427 | + SHA: "pr-sha", |
| 2428 | + }, |
| 2429 | + expectError: false, |
2263 | 2430 | },
|
2264 | 2431 | }
|
2265 | 2432 |
|
2266 | 2433 | for _, tc := range tests {
|
2267 | 2434 | t.Run(tc.name, func(t *testing.T) {
|
2268 | 2435 | // Setup client with mock
|
2269 |
| - client := github.NewClient(mockedClient) |
| 2436 | + client := github.NewClient(tc.mockSetup()) |
2270 | 2437 | opts, err := resolveGitReference(ctx, client, owner, repo, tc.ref, tc.sha)
|
| 2438 | + |
| 2439 | + if tc.expectError { |
| 2440 | + require.Error(t, err) |
| 2441 | + if tc.errorContains != "" { |
| 2442 | + assert.Contains(t, err.Error(), tc.errorContains) |
| 2443 | + } |
| 2444 | + return |
| 2445 | + } |
| 2446 | + |
2271 | 2447 | require.NoError(t, err)
|
| 2448 | + require.NotNil(t, opts) |
2272 | 2449 |
|
2273 | 2450 | if tc.expectedOutput.SHA != "" {
|
2274 | 2451 | assert.Equal(t, tc.expectedOutput.SHA, opts.SHA)
|
|
0 commit comments