Browse Source

Add some tests for reference changes.

Gustavo Niemeyer 5 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) {
166 166
 		return
167 167
 	}
168 168
 
169
-	var err error
170
-	var refs []byte
171
-	refs, repo.AllVersions, err = hackedRefs(repo)
169
+	var changed []byte
170
+	original, err := fetchRefs(repo)
171
+	if err == nil {
172
+		changed, repo.AllVersions, err = changeRefs(original, repo.MajorVersion)
173
+	}
174
+
172 175
 	switch err {
173 176
 	case nil:
174 177
 		// all ok
@@ -199,7 +202,7 @@ func handler(resp http.ResponseWriter, req *http.Request) {
199 202
 
200 203
 	if repo.SubPath == "/info/refs" {
201 204
 		resp.Header().Set("Content-Type", "application/x-git-upload-pack-advertisement")
202
-		resp.Write(refs)
205
+		resp.Write(changed)
203 206
 		return
204 207
 	}
205 208
 
@@ -231,10 +234,10 @@ const refsSuffix = ".git/info/refs?service=git-upload-pack"
231 234
 var ErrNoRepo = errors.New("repository not found in GitHub")
232 235
 var ErrNoVersion = errors.New("version reference not found in GitHub")
233 236
 
234
-func hackedRefs(repo *Repo) (refs []byte, versions []Version, err error) {
237
+func fetchRefs(repo *Repo) (data []byte, err error) {
235 238
 	resp, err := httpClient.Get("https://" + repo.GitHubRoot() + refsSuffix)
236 239
 	if err != nil {
237
-		return nil, nil, fmt.Errorf("cannot talk to GitHub: %v", err)
240
+		return nil, fmt.Errorf("cannot talk to GitHub: %v", err)
238 241
 	}
239 242
 	defer resp.Body.Close()
240 243
 
@@ -242,16 +245,19 @@ func hackedRefs(repo *Repo) (refs []byte, versions []Version, err error) {
242 245
 	case 200:
243 246
 		// ok
244 247
 	case 401, 404:
245
-		return nil, nil, ErrNoRepo
248
+		return nil, ErrNoRepo
246 249
 	default:
247
-		return nil, nil, fmt.Errorf("error from GitHub: %v", resp.Status)
250
+		return nil, fmt.Errorf("error from GitHub: %v", resp.Status)
248 251
 	}
249 252
 
250
-	data, err := ioutil.ReadAll(resp.Body)
253
+	data, err = ioutil.ReadAll(resp.Body)
251 254
 	if err != nil {
252
-		return nil, nil, fmt.Errorf("error reading from GitHub: %v", err)
255
+		return nil, fmt.Errorf("error reading from GitHub: %v", err)
253 256
 	}
257
+	return data, err
258
+}
254 259
 
260
+func changeRefs(data []byte, major Version) (changed []byte, versions VersionList, err error) {
255 261
 	var hlinei, hlinej int // HEAD reference line start/end
256 262
 	var mlinei, mlinej int // master reference line start/end
257 263
 	var vrefhash string
@@ -310,7 +316,7 @@ func hackedRefs(repo *Repo) (refs []byte, versions []Version, err error) {
310 316
 				name = name[:len(name)-3]
311 317
 			}
312 318
 			v, ok := parseVersion(name[strings.IndexByte(name, 'v'):])
313
-			if ok && repo.MajorVersion.Contains(v) && (v == vrefv || !vrefv.IsValid() || vrefv.Less(v)) {
319
+			if ok && major.Contains(v) && (v == vrefv || !vrefv.IsValid() || vrefv.Less(v)) {
314 320
 				vrefv = v
315 321
 				vrefhash = sdata[hashi:hashj]
316 322
 				vrefname = name
@@ -322,7 +328,7 @@ func hackedRefs(repo *Repo) (refs []byte, versions []Version, err error) {
322 328
 	}
323 329
 
324 330
 	// If there were absolutely no versions, and v0 was requested, accept the master as-is.
325
-	if len(versions) == 0 && repo.MajorVersion == (Version{0, -1, -1, false}) {
331
+	if len(versions) == 0 && major == (Version{0, -1, -1, false}) {
326 332
 		return data, nil, nil
327 333
 	}
328 334
 
@@ -344,7 +350,20 @@ func hackedRefs(repo *Repo) (refs []byte, versions []Version, err error) {
344 350
 	}
345 351
 
346 352
 	// Insert the HEAD reference line with the right hash and a proper symref capability.
347
-	line := fmt.Sprintf("%s HEAD\x00symref=HEAD:%s %s\n", vrefhash, vrefname, caps)
353
+	var line string
354
+	if strings.HasPrefix(vrefname, "refs/heads/") {
355
+		if caps == "" {
356
+			line = fmt.Sprintf("%s HEAD\x00symref=HEAD:%s\n", vrefhash, vrefname)
357
+		} else {
358
+			line = fmt.Sprintf("%s HEAD\x00symref=HEAD:%s %s\n", vrefhash, vrefname, caps)
359
+		}
360
+	} else {
361
+		if caps == "" {
362
+			line = fmt.Sprintf("%s HEAD\n", vrefhash)
363
+		} else {
364
+			line = fmt.Sprintf("%s HEAD\x00%s\n", vrefhash, caps)
365
+		}
366
+	}
348 367
 	fmt.Fprintf(&buf, "%04x%s", 4+len(line), line)
349 368
 
350 369
 	// Insert the master reference line.

+ 194
- 0
refs_test.go View File

@@ -0,0 +1,194 @@
1
+package main
2
+
3
+import (
4
+	"bytes"
5
+	"fmt"
6
+	. "gopkg.in/check.v1"
7
+	"sort"
8
+)
9
+
10
+var _ = Suite(&RefsSuite{})
11
+
12
+type RefsSuite struct{}
13
+
14
+type refsTest struct {
15
+	summary  string
16
+	original string
17
+	version  string
18
+	changed  string
19
+	versions []string
20
+}
21
+
22
+var refsTests = []refsTest{{
23
+	"Version v0 works even without any references",
24
+	reflines(
25
+		"hash1 HEAD",
26
+	),
27
+	"v0",
28
+	reflines(
29
+		"hash1 HEAD",
30
+	),
31
+	nil,
32
+}, {
33
+	"Preserve original capabilities",
34
+	reflines(
35
+		"hash1 HEAD\x00caps",
36
+	),
37
+	"v0",
38
+	reflines(
39
+		"hash1 HEAD\x00caps",
40
+	),
41
+	nil,
42
+}, {
43
+	"Matching major version branch",
44
+	reflines(
45
+		"00000000000000000000000000000000000hash1 HEAD",
46
+		"00000000000000000000000000000000000hash2 refs/heads/v0",
47
+		"00000000000000000000000000000000000hash3 refs/heads/v1",
48
+		"00000000000000000000000000000000000hash4 refs/heads/v2",
49
+	),
50
+	"v1",
51
+	reflines(
52
+		"00000000000000000000000000000000000hash3 HEAD\x00symref=HEAD:refs/heads/v1",
53
+		"00000000000000000000000000000000000hash3 refs/heads/master",
54
+		"00000000000000000000000000000000000hash2 refs/heads/v0",
55
+		"00000000000000000000000000000000000hash3 refs/heads/v1",
56
+		"00000000000000000000000000000000000hash4 refs/heads/v2",
57
+	),
58
+	[]string{"v0", "v1", "v2"},
59
+}, {
60
+	"Matching minor version branch",
61
+	reflines(
62
+		"00000000000000000000000000000000000hash1 HEAD",
63
+		"00000000000000000000000000000000000hash2 refs/heads/v1.1",
64
+		"00000000000000000000000000000000000hash3 refs/heads/v1.3",
65
+		"00000000000000000000000000000000000hash4 refs/heads/v1.2",
66
+	),
67
+	"v1",
68
+	reflines(
69
+		"00000000000000000000000000000000000hash3 HEAD\x00symref=HEAD:refs/heads/v1.3",
70
+		"00000000000000000000000000000000000hash3 refs/heads/master",
71
+		"00000000000000000000000000000000000hash2 refs/heads/v1.1",
72
+		"00000000000000000000000000000000000hash3 refs/heads/v1.3",
73
+		"00000000000000000000000000000000000hash4 refs/heads/v1.2",
74
+	),
75
+	[]string{"v1.1", "v1.2", "v1.3"},
76
+}, {
77
+	"Disable original symref capability",
78
+	reflines(
79
+		"00000000000000000000000000000000000hash1 HEAD\x00foo symref=bar baz",
80
+		"00000000000000000000000000000000000hash2 refs/heads/v1",
81
+	),
82
+	"v1",
83
+	reflines(
84
+		"00000000000000000000000000000000000hash2 HEAD\x00symref=HEAD:refs/heads/v1 foo oldref=bar baz",
85
+		"00000000000000000000000000000000000hash2 refs/heads/master",
86
+		"00000000000000000000000000000000000hash2 refs/heads/v1",
87
+	),
88
+	[]string{"v1"},
89
+}, {
90
+	"Replace original master branch",
91
+	reflines(
92
+		"00000000000000000000000000000000000hash1 HEAD",
93
+		"00000000000000000000000000000000000hash1 refs/heads/master",
94
+		"00000000000000000000000000000000000hash2 refs/heads/v1",
95
+	),
96
+	"v1",
97
+	reflines(
98
+		"00000000000000000000000000000000000hash2 HEAD\x00symref=HEAD:refs/heads/v1",
99
+		"00000000000000000000000000000000000hash2 refs/heads/master",
100
+		"00000000000000000000000000000000000hash2 refs/heads/v1",
101
+	),
102
+	[]string{"v1"},
103
+}, {
104
+	"Matching tag",
105
+	reflines(
106
+		"00000000000000000000000000000000000hash1 HEAD",
107
+		"00000000000000000000000000000000000hash2 refs/tags/v0",
108
+		"00000000000000000000000000000000000hash3 refs/tags/v1",
109
+		"00000000000000000000000000000000000hash4 refs/tags/v2",
110
+	),
111
+	"v1",
112
+	reflines(
113
+		"00000000000000000000000000000000000hash3 HEAD",
114
+		"00000000000000000000000000000000000hash3 refs/heads/master",
115
+		"00000000000000000000000000000000000hash2 refs/tags/v0",
116
+		"00000000000000000000000000000000000hash3 refs/tags/v1",
117
+		"00000000000000000000000000000000000hash4 refs/tags/v2",
118
+	),
119
+	[]string{"v0", "v1", "v2"},
120
+}, {
121
+	"Tag peeling",
122
+	reflines(
123
+		"00000000000000000000000000000000000hash1 HEAD",
124
+		"00000000000000000000000000000000000hash2 refs/heads/master",
125
+		"00000000000000000000000000000000000hash3 refs/tags/v1",
126
+		"00000000000000000000000000000000000hash4 refs/tags/v1^{}",
127
+		"00000000000000000000000000000000000hash5 refs/tags/v2",
128
+	),
129
+	"v1",
130
+	reflines(
131
+		"00000000000000000000000000000000000hash4 HEAD",
132
+		"00000000000000000000000000000000000hash4 refs/heads/master",
133
+		"00000000000000000000000000000000000hash3 refs/tags/v1",
134
+		"00000000000000000000000000000000000hash4 refs/tags/v1^{}",
135
+		"00000000000000000000000000000000000hash5 refs/tags/v2",
136
+	),
137
+	[]string{"v1", "v1", "v2"},
138
+}, {
139
+	"Matching unstable versions",
140
+	reflines(
141
+		"00000000000000000000000000000000000hash1 HEAD",
142
+		"00000000000000000000000000000000000hash2 refs/heads/master",
143
+		"00000000000000000000000000000000000hash3 refs/heads/v1",
144
+		"00000000000000000000000000000000000hash4 refs/heads/v1.1-unstable",
145
+		"00000000000000000000000000000000000hash5 refs/heads/v1.3-unstable",
146
+		"00000000000000000000000000000000000hash6 refs/heads/v1.2-unstable",
147
+		"00000000000000000000000000000000000hash7 refs/heads/v2",
148
+	),
149
+	"v1-unstable",
150
+	reflines(
151
+		"00000000000000000000000000000000000hash5 HEAD\x00symref=HEAD:refs/heads/v1.3-unstable",
152
+		"00000000000000000000000000000000000hash5 refs/heads/master",
153
+		"00000000000000000000000000000000000hash3 refs/heads/v1",
154
+		"00000000000000000000000000000000000hash4 refs/heads/v1.1-unstable",
155
+		"00000000000000000000000000000000000hash5 refs/heads/v1.3-unstable",
156
+		"00000000000000000000000000000000000hash6 refs/heads/v1.2-unstable",
157
+		"00000000000000000000000000000000000hash7 refs/heads/v2",
158
+	),
159
+	[]string{"v1", "v1.1-unstable", "v1.2-unstable", "v1.3-unstable", "v2"},
160
+}}
161
+
162
+func reflines(lines ...string) string {
163
+	var buf bytes.Buffer
164
+	buf.WriteString("001e# service=git-upload-pack\n0000")
165
+	for _, l := range lines {
166
+		buf.WriteString(fmt.Sprintf("%04x%s\n", len(l)+5, l))
167
+	}
168
+	buf.WriteString("0000")
169
+	return buf.String()
170
+}
171
+
172
+func (s *RefsSuite) TestChangeRefs(c *C) {
173
+	for _, test := range refsTests {
174
+		c.Logf(test.summary)
175
+
176
+		v, ok := parseVersion(test.version)
177
+		if !ok {
178
+			c.Fatalf("Test has an invalid version: %q", test.version)
179
+		}
180
+
181
+		changed, versions, err := changeRefs([]byte(test.original), v)
182
+		c.Assert(err, IsNil)
183
+
184
+		c.Assert(string(changed), Equals, test.changed)
185
+
186
+		sort.Sort(versions)
187
+
188
+		var vs []string
189
+		for _, v := range versions {
190
+			vs = append(vs, v.String())
191
+		}
192
+		c.Assert(vs, DeepEquals, test.versions)
193
+	}
194
+}