mirror of
https://github.com/git-pkgs/proxy.git
synced 2026-11-09 15:49:16 -05:00
A pkg:git version can now be a tag as well as a full commit ID. With a version, the submodules the commit records are mirrored at the commits it pins, from the upstream.git hosts serving them; one no host serves is skipped with a warning.
154 lines
6.3 KiB
Go
154 lines
6.3 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/git-pkgs/proxy/internal/config"
|
|
)
|
|
|
|
func TestGitMirrorLocation(t *testing.T) {
|
|
h := NewGitHandler(nil, nil, config.UpstreamConfig{Git: map[string]config.GitUpstream{
|
|
"github": {URL: "https://github.com"},
|
|
"wikimedia": {URL: "https://gitlab.wikimedia.org", Repos: []string{"mediawiki/**"}},
|
|
"sub": {URL: "https://git.example/r/"},
|
|
"nested": {URL: "https://git.example/r/deep"},
|
|
}})
|
|
tests := []struct {
|
|
location string
|
|
ok bool
|
|
key, repoURL string
|
|
}{
|
|
{"github.com/acme/widgets", true, h.upstreams["github"].dir + "/acme/widgets.git", "https://github.com/acme/widgets"},
|
|
{"github.com/acme/widgets.git", true, h.upstreams["github"].dir + "/acme/widgets.git", "https://github.com/acme/widgets.git"},
|
|
{"gitlab.wikimedia.org/mediawiki/skins/Vector", true, h.upstreams["wikimedia"].dir + "/mediawiki/skins/Vector.git", "https://gitlab.wikimedia.org/mediawiki/skins/Vector"},
|
|
{"gitlab.wikimedia.org/other/repo", false, "", ""},
|
|
{"git.example/r/a", true, h.upstreams["sub"].dir + "/a.git", "https://git.example/r/a"},
|
|
// The longest matching upstream URL wins.
|
|
{"git.example/r/deep/a", true, h.upstreams["nested"].dir + "/a.git", "https://git.example/r/deep/a"},
|
|
{"git.example/other", false, "", ""},
|
|
{"git.example/r", false, "", ""},
|
|
{"github.com.evil/acme/widgets", false, "", ""},
|
|
{"github.com/acme/../widgets", false, "", ""},
|
|
{"codeberg.org/forgejo/forgejo", false, "", ""},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.location, func(t *testing.T) {
|
|
repo, err := h.mirrorRepository(tt.location)
|
|
if (err == nil) != tt.ok {
|
|
t.Fatalf("error %v, want ok %v", err, tt.ok)
|
|
}
|
|
if tt.ok && (repo.key != tt.key || repo.url != tt.repoURL) {
|
|
t.Errorf("key %q, URL %q; want %q, %q", repo.key, repo.url, tt.key, tt.repoURL)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGitMirrorCachesCommitForClones(t *testing.T) {
|
|
g := newGitTestSetup(t, 0, 0)
|
|
sha := runGitCommand(t, g.work, "rev-parse", "HEAD")
|
|
location := strings.TrimPrefix(g.upstreamURL, "http://") + "/repo"
|
|
|
|
got, err := g.handler.Mirror(context.Background(), location, sha)
|
|
if err != nil {
|
|
t.Fatalf("Mirror: %v", err)
|
|
}
|
|
if got.Cached {
|
|
t.Errorf("first mirror = %+v, want fetched", got)
|
|
}
|
|
got, err = g.handler.Mirror(context.Background(), location, sha)
|
|
if err != nil || !got.Cached {
|
|
t.Errorf("second mirror = %+v, %v, want cached", got, err)
|
|
}
|
|
|
|
// With the upstream gone, a clone through the proxy gets the mirrored copy.
|
|
g.upstream.Close()
|
|
clone := t.TempDir()
|
|
runGitCommand(t, "", "clone", "--quiet", g.url(), clone)
|
|
if head := runGitCommand(t, clone, "rev-parse", "HEAD"); head != sha {
|
|
t.Errorf("cloned HEAD %s, want %s", head, sha)
|
|
}
|
|
}
|
|
|
|
func TestGitSubmoduleLocation(t *testing.T) {
|
|
tests := []struct {
|
|
repoURL, submoduleURL, want string
|
|
}{
|
|
{"https://github.com/acme/widgets", "../lib.git", "github.com/acme/lib.git"},
|
|
{"https://github.com/acme/widgets.git", "../../other/lib", "github.com/other/lib"},
|
|
{"https://github.com/acme/widgets", "./vendored", "github.com/acme/widgets/vendored"},
|
|
{"http://127.0.0.1:8080/team/repo", "../lib.git", "127.0.0.1:8080/team/lib.git"},
|
|
{"https://github.com/acme/widgets", "https://GitLab.com/group/lib.git/", "gitlab.com/group/lib.git"},
|
|
{"https://github.com/acme/widgets", "ssh://git@github.com:22/acme/lib.git", "github.com/acme/lib.git"},
|
|
{"https://github.com/acme/widgets", "git://git.example/lib", "git.example/lib"},
|
|
{"https://github.com/acme/widgets", "git@github.com:acme/lib.git", "github.com/acme/lib.git"},
|
|
{"https://github.com/acme/widgets", "/srv/git/lib.git", ""},
|
|
{"https://github.com/acme/widgets", "file:///srv/git/lib.git", ""},
|
|
{"https://github.com/acme/widgets", "", ""},
|
|
}
|
|
for _, tt := range tests {
|
|
got, err := gitSubmoduleLocation(tt.repoURL, tt.submoduleURL)
|
|
if tt.want == "" {
|
|
if err == nil {
|
|
t.Errorf("location of %q = %q, want an error", tt.submoduleURL, got)
|
|
}
|
|
continue
|
|
}
|
|
if err != nil || got != tt.want {
|
|
t.Errorf("location of %q from %s = %q, %v; want %q", tt.submoduleURL, tt.repoURL, got, err, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestGitMirrorCachesSubmodules mirrors a commit with a submodule served by
|
|
// the same upstream and one on a host no upstream.git serves, which is
|
|
// skipped.
|
|
func TestGitMirrorCachesSubmodules(t *testing.T) {
|
|
g := newGitTestSetup(t, 0, 0)
|
|
libBare := filepath.Join(g.root, "lib.git")
|
|
runGitCommand(t, "", "init", "--quiet", "--bare", "--initial-branch=main", libBare)
|
|
libWork := t.TempDir()
|
|
runGitCommand(t, "", "clone", "--quiet", libBare, libWork)
|
|
runGitCommand(t, libWork, "commit", "--quiet", "--allow-empty", "-m", "lib")
|
|
runGitCommand(t, libWork, "push", "--quiet", "origin", "HEAD:main")
|
|
libCommit := runGitCommand(t, libWork, "rev-parse", "HEAD")
|
|
|
|
gitmodules := "[submodule \"lib\"]\n\tpath = lib\n\turl = ../lib.git\n" +
|
|
"[submodule \"elsewhere\"]\n\tpath = elsewhere\n\turl = https://elsewhere.example/x.git\n"
|
|
if err := os.WriteFile(filepath.Join(g.work, ".gitmodules"), []byte(gitmodules), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
runGitCommand(t, g.work, "add", ".gitmodules")
|
|
runGitCommand(t, g.work, "update-index", "--add", "--cacheinfo", "160000,"+libCommit+",lib")
|
|
runGitCommand(t, g.work, "update-index", "--add", "--cacheinfo", "160000,"+strings.Repeat("ab", 20)+",elsewhere")
|
|
runGitCommand(t, g.work, "commit", "--quiet", "-m", "submodules")
|
|
runGitCommand(t, g.work, "push", "--quiet", "origin", "HEAD:main")
|
|
sha := runGitCommand(t, g.work, "rev-parse", "HEAD")
|
|
location := strings.TrimPrefix(g.upstreamURL, "http://") + "/repo"
|
|
|
|
got, err := g.handler.Mirror(context.Background(), location, sha)
|
|
if err != nil {
|
|
t.Fatalf("Mirror: %v", err)
|
|
}
|
|
if got.Cached {
|
|
t.Errorf("first mirror = %+v, want fetched", got)
|
|
}
|
|
if got, err = g.handler.Mirror(context.Background(), location, sha); err != nil || !got.Cached {
|
|
t.Errorf("second mirror = %+v, %v, want cached", got, err)
|
|
}
|
|
if !strings.Contains(g.logs.String(), "elsewhere.example") {
|
|
t.Errorf("log doesn't name the skipped submodule:\n%s", g.logs.String())
|
|
}
|
|
|
|
// With the upstream gone, the submodule's commit is served from the cache.
|
|
g.upstream.Close()
|
|
clone := t.TempDir()
|
|
runGitCommand(t, "", "clone", "--quiet", g.server.URL+"/git/up/lib", clone)
|
|
if head := runGitCommand(t, clone, "rev-parse", "HEAD"); head != libCommit {
|
|
t.Errorf("cloned lib HEAD %s, want %s", head, libCommit)
|
|
}
|
|
}
|