Browse Source

Add some tests for reference changes.

master
Gustavo Niemeyer 6 years ago
parent
commit
224efbc020
2 changed files with 226 additions and 13 deletions
  1. +32
    -13
      main.go
  2. +194
    -0
      refs_test.go

+ 32
- 13
main.go View File

@@ -166,9 +166,12 @@ func handler(resp http.ResponseWriter, req *http.Request) {
return
}

var err error
var refs []byte
refs, repo.AllVersions, err = hackedRefs(repo)
var changed []byte
original, err := fetchRefs(repo)
if err == nil {
changed, repo.AllVersions, err = changeRefs(original, repo.MajorVersion)
}

switch err {
case nil:
// all ok
@@ -199,7 +202,7 @@ func handler(resp http.ResponseWriter, req *http.Request) {

if repo.SubPath == "/info/refs" {
resp.Header().Set("Content-Type", "application/x-git-upload-pack-advertisement")
resp.Write(refs)
resp.Write(changed)
return
}

@@ -231,10 +234,10 @@ const refsSuffix = ".git/info/refs?service=git-upload-pack"
var ErrNoRepo = errors.New("repository not found in GitHub")
var ErrNoVersion = errors.New("version reference not found in GitHub")

func hackedRefs(repo *Repo) (refs []byte, versions []Version, err error) {
func fetchRefs(repo *Repo) (data []byte, err error) {
resp, err := httpClient.Get("https://" + repo.GitHubRoot() + refsSuffix)
if err != nil {
return nil, nil, fmt.Errorf("cannot talk to GitHub: %v", err)
return nil, fmt.Errorf("cannot talk to GitHub: %v", err)
}
defer resp.Body.Close()

@@ -242,16 +245,19 @@ func hackedRefs(repo *Repo) (refs []byte, versions []Version, err error) {
case 200:
// ok
case 401, 404:
return nil, nil, ErrNoRepo
return nil, ErrNoRepo
default:
return nil, nil, fmt.Errorf("error from GitHub: %v", resp.Status)
return nil, fmt.Errorf("error from GitHub: %v", resp.Status)
}

data, err := ioutil.ReadAll(resp.Body)
data, err = ioutil.ReadAll(resp.Body)
if err != nil {
return nil, nil, fmt.Errorf("error reading from GitHub: %v", err)
return nil, fmt.Errorf("error reading from GitHub: %v", err)
}
return data, err
}

func changeRefs(data []byte, major Version) (changed []byte, versions VersionList, err error) {
var hlinei, hlinej int // HEAD reference line start/end
var mlinei, mlinej int // master reference line start/end
var vrefhash string
@@ -310,7 +316,7 @@ func hackedRefs(repo *Repo) (refs []byte, versions []Version, err error) {
name = name[:len(name)-3]
}
v, ok := parseVersion(name[strings.IndexByte(name, 'v'):])
if ok && repo.MajorVersion.Contains(v) && (v == vrefv || !vrefv.IsValid() || vrefv.Less(v)) {
if ok && major.Contains(v) && (v == vrefv || !vrefv.IsValid() || vrefv.Less(v)) {
vrefv = v
vrefhash = sdata[hashi:hashj]
vrefname = name
@@ -322,7 +328,7 @@ func hackedRefs(repo *Repo) (refs []byte, versions []Version, err error) {
}

// If there were absolutely no versions, and v0 was requested, accept the master as-is.
if len(versions) == 0 && repo.MajorVersion == (Version{0, -1, -1, false}) {
if len(versions) == 0 && major == (Version{0, -1, -1, false}) {
return data, nil, nil
}

@@ -344,7 +350,20 @@ func hackedRefs(repo *Repo) (refs []byte, versions []Version, err error) {
}

// Insert the HEAD reference line with the right hash and a proper symref capability.
line := fmt.Sprintf("%s HEAD\x00symref=HEAD:%s %s\n", vrefhash, vrefname, caps)
var line string
if strings.HasPrefix(vrefname, "refs/heads/") {
if caps == "" {
line = fmt.Sprintf("%s HEAD\x00symref=HEAD:%s\n", vrefhash, vrefname)
} else {
line = fmt.Sprintf("%s HEAD\x00symref=HEAD:%s %s\n", vrefhash, vrefname, caps)
}
} else {
if caps == "" {
line = fmt.Sprintf("%s HEAD\n", vrefhash)
} else {
line = fmt.Sprintf("%s HEAD\x00%s\n", vrefhash, caps)
}
}
fmt.Fprintf(&buf, "%04x%s", 4+len(line), line)

// Insert the master reference line.


+ 194
- 0
refs_test.go View File

@@ -0,0 +1,194 @@
package main

import (
"bytes"
"fmt"
. "gopkg.in/check.v1"
"sort"
)

var _ = Suite(&RefsSuite{})

type RefsSuite struct{}

type refsTest struct {
summary string
original string
version string
changed string
versions []string
}

var refsTests = []refsTest{{
"Version v0 works even without any references",
reflines(
"hash1 HEAD",
),
"v0",
reflines(
"hash1 HEAD",
),
nil,
}, {
"Preserve original capabilities",
reflines(
"hash1 HEAD\x00caps",
),
"v0",
reflines(
"hash1 HEAD\x00caps",
),
nil,
}, {
"Matching major version branch",
reflines(
"00000000000000000000000000000000000hash1 HEAD",
"00000000000000000000000000000000000hash2 refs/heads/v0",
"00000000000000000000000000000000000hash3 refs/heads/v1",
"00000000000000000000000000000000000hash4 refs/heads/v2",
),
"v1",
reflines(
"00000000000000000000000000000000000hash3 HEAD\x00symref=HEAD:refs/heads/v1",
"00000000000000000000000000000000000hash3 refs/heads/master",
"00000000000000000000000000000000000hash2 refs/heads/v0",
"00000000000000000000000000000000000hash3 refs/heads/v1",
"00000000000000000000000000000000000hash4 refs/heads/v2",
),
[]string{"v0", "v1", "v2"},
}, {
"Matching minor version branch",
reflines(
"00000000000000000000000000000000000hash1 HEAD",
"00000000000000000000000000000000000hash2 refs/heads/v1.1",
"00000000000000000000000000000000000hash3 refs/heads/v1.3",
"00000000000000000000000000000000000hash4 refs/heads/v1.2",
),
"v1",
reflines(
"00000000000000000000000000000000000hash3 HEAD\x00symref=HEAD:refs/heads/v1.3",
"00000000000000000000000000000000000hash3 refs/heads/master",
"00000000000000000000000000000000000hash2 refs/heads/v1.1",
"00000000000000000000000000000000000hash3 refs/heads/v1.3",
"00000000000000000000000000000000000hash4 refs/heads/v1.2",
),
[]string{"v1.1", "v1.2", "v1.3"},
}, {
"Disable original symref capability",
reflines(
"00000000000000000000000000000000000hash1 HEAD\x00foo symref=bar baz",
"00000000000000000000000000000000000hash2 refs/heads/v1",
),
"v1",
reflines(
"00000000000000000000000000000000000hash2 HEAD\x00symref=HEAD:refs/heads/v1 foo oldref=bar baz",
"00000000000000000000000000000000000hash2 refs/heads/master",
"00000000000000000000000000000000000hash2 refs/heads/v1",
),
[]string{"v1"},
}, {
"Replace original master branch",
reflines(
"00000000000000000000000000000000000hash1 HEAD",
"00000000000000000000000000000000000hash1 refs/heads/master",
"00000000000000000000000000000000000hash2 refs/heads/v1",
),
"v1",
reflines(
"00000000000000000000000000000000000hash2 HEAD\x00symref=HEAD:refs/heads/v1",
"00000000000000000000000000000000000hash2 refs/heads/master",
"00000000000000000000000000000000000hash2 refs/heads/v1",
),
[]string{"v1"},
}, {
"Matching tag",
reflines(
"00000000000000000000000000000000000hash1 HEAD",
"00000000000000000000000000000000000hash2 refs/tags/v0",
"00000000000000000000000000000000000hash3 refs/tags/v1",
"00000000000000000000000000000000000hash4 refs/tags/v2",
),
"v1",
reflines(
"00000000000000000000000000000000000hash3 HEAD",
"00000000000000000000000000000000000hash3 refs/heads/master",
"00000000000000000000000000000000000hash2 refs/tags/v0",
"00000000000000000000000000000000000hash3 refs/tags/v1",
"00000000000000000000000000000000000hash4 refs/tags/v2",
),
[]string{"v0", "v1", "v2"},
}, {
"Tag peeling",
reflines(
"00000000000000000000000000000000000hash1 HEAD",
"00000000000000000000000000000000000hash2 refs/heads/master",
"00000000000000000000000000000000000hash3 refs/tags/v1",
"00000000000000000000000000000000000hash4 refs/tags/v1^{}",
"00000000000000000000000000000000000hash5 refs/tags/v2",
),
"v1",
reflines(
"00000000000000000000000000000000000hash4 HEAD",
"00000000000000000000000000000000000hash4 refs/heads/master",
"00000000000000000000000000000000000hash3 refs/tags/v1",
"00000000000000000000000000000000000hash4 refs/tags/v1^{}",
"00000000000000000000000000000000000hash5 refs/tags/v2",
),
[]string{"v1", "v1", "v2"},
}, {
"Matching unstable versions",
reflines(
"00000000000000000000000000000000000hash1 HEAD",
"00000000000000000000000000000000000hash2 refs/heads/master",
"00000000000000000000000000000000000hash3 refs/heads/v1",
"00000000000000000000000000000000000hash4 refs/heads/v1.1-unstable",
"00000000000000000000000000000000000hash5 refs/heads/v1.3-unstable",
"00000000000000000000000000000000000hash6 refs/heads/v1.2-unstable",
"00000000000000000000000000000000000hash7 refs/heads/v2",
),
"v1-unstable",
reflines(
"00000000000000000000000000000000000hash5 HEAD\x00symref=HEAD:refs/heads/v1.3-unstable",
"00000000000000000000000000000000000hash5 refs/heads/master",
"00000000000000000000000000000000000hash3 refs/heads/v1",
"00000000000000000000000000000000000hash4 refs/heads/v1.1-unstable",
"00000000000000000000000000000000000hash5 refs/heads/v1.3-unstable",
"00000000000000000000000000000000000hash6 refs/heads/v1.2-unstable",
"00000000000000000000000000000000000hash7 refs/heads/v2",
),
[]string{"v1", "v1.1-unstable", "v1.2-unstable", "v1.3-unstable", "v2"},
}}

func reflines(lines ...string) string {
var buf bytes.Buffer
buf.WriteString("001e# service=git-upload-pack\n0000")
for _, l := range lines {
buf.WriteString(fmt.Sprintf("%04x%s\n", len(l)+5, l))
}
buf.WriteString("0000")
return buf.String()
}

func (s *RefsSuite) TestChangeRefs(c *C) {
for _, test := range refsTests {
c.Logf(test.summary)

v, ok := parseVersion(test.version)
if !ok {
c.Fatalf("Test has an invalid version: %q", test.version)
}

changed, versions, err := changeRefs([]byte(test.original), v)
c.Assert(err, IsNil)

c.Assert(string(changed), Equals, test.changed)

sort.Sort(versions)

var vs []string
for _, v := range versions {
vs = append(vs, v.String())
}
c.Assert(vs, DeepEquals, test.versions)
}
}

Loading…
Cancel
Save