Skip to content

Commit 82317d2

Browse files
authored
Merge pull request #31 from djmitche/normalize
Add normalizeRootUrl
2 parents 41eebde + 0d76562 commit 82317d2

File tree

8 files changed

+92
-13
lines changed

8 files changed

+92
-13
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ A simple library to generate URLs for various Taskcluster resources across our v
77
This serves as both a simple shim for projects that use JavaScript but also is the reference implementation for
88
how we define these paths.
99

10-
URLs are defined in the 'Taskcluster URL Format' document.
10+
URLs are defined in the '[Taskcluster URL Format](https://github.com/taskcluster/taskcluster-lib-urls/tree/master/docs/urls-spec.md)' document.
1111

1212
Changelog
1313
---------
@@ -40,6 +40,7 @@ root URL:
4040
* `apiManifest(rootUrl)` -> `String`
4141
* `testRootUrl()` -> `String`
4242
* `withRootUrl(rootUrl)` -> `Class` instance for above methods
43+
* `normalizeRootUrl(rootUrl)` -> `String` (the "normalized" form of the given rootUrl)
4344

4445
When the `rootUrl` is `https://taskcluster.net`, the generated URLs will be to the Heroku cluster. Otherwise they will follow the
4546
[spec defined in this project](https://github.com/taskcluster/taskcluster-lib-urls/tree/master/docs/urls-spec.md).
@@ -113,6 +114,7 @@ func ExchangesReferenceSchema(rootURL string, version string) string
113114
func MetadataMetaschema(rootURL string) string
114115
func UI(rootURL string, path string) string
115116
func APIManifest(rootURL string) string
117+
func NormalizedRootURL(rootURL string) string
116118
```
117119

118120
Install with:
@@ -146,6 +148,7 @@ taskcluster_urls.exchange_reference(root_url, 'auth', 'v1')
146148
taskcluster_urls.ui(root_url, 'foo/bar')
147149
taskcluster_urls.apiManifest(root_url)
148150
taskcluster_urls.docs(root_url, 'foo/bar')
151+
taskcluster_urls.normalized_root_url(root_url)
149152

150153
And for testing,
151154
```python

docs/urls-spec.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ Example:
1313
https://taskcluster.example.com
1414
```
1515

16+
Normally, a rootUrl has no trailing `/` characters.
17+
We suggest that libraries and tools be lenient and accept rootUrls containing a trailing `/`, but produce rootUrls without a trailing `/`.
18+
The `normalizeRootUrl` function supports this practice.
19+
1620
# URLs
1721

1822
Taskcluster uses URLs with the following pattern:

src/index.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,4 +290,11 @@ module.exports = {
290290
testRootUrl() {
291291
return 'https://tc-tests.example.com';
292292
},
293+
294+
/**
295+
* Return the normal form of this rootUrl
296+
*/
297+
normalizeRootUrl(rootUrl) {
298+
return cleanRoot(rootUrl);
299+
},
293300
};

taskcluster_urls/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,7 @@ def test_root_url():
8888
"""Returns a standardized "testing" rootUrl that does not resolve but
8989
is easily recognizable in test failures."""
9090
return 'https://tc-tests.example.com'
91+
92+
def normalize_root_url(root_url):
93+
"""Return the normal form of the given rootUrl"""
94+
return root_url.rstrip('/')

tcurls.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,8 @@ func APIManifest(rootURL string) string {
106106
return fmt.Sprintf("%s/references/manifest.json", r)
107107
}
108108
}
109+
110+
// NormalizeRootURL returns the normal form of the given rootURL.
111+
func NormalizeRootURL(rootURL string) string {
112+
return strings.TrimRight(rootURL, "/")
113+
}

tcurls_test.go

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ type TestsSpecification struct {
1919
Tests []TestCase `yaml:"tests"`
2020
}
2121

22+
func getTests() (*TestsSpecification, error) {
23+
data, err := ioutil.ReadFile("tests.yml")
24+
if err != nil {
25+
return nil, err
26+
}
27+
var spec TestsSpecification
28+
err = yaml.Unmarshal([]byte(data), &spec)
29+
if err != nil {
30+
return nil, err
31+
}
32+
33+
return &spec, nil
34+
}
35+
2236
func testFunc(t *testing.T, function string, expectedURL string, root string, args ...string) {
2337
var actualURL string
2438
switch function {
@@ -56,16 +70,10 @@ func testFunc(t *testing.T, function string, expectedURL string, root string, ar
5670
}
5771

5872
func TestURLs(t *testing.T) {
59-
data, err := ioutil.ReadFile("tests.yml")
73+
spec, err := getTests()
6074
if err != nil {
6175
t.Error(err)
6276
}
63-
var spec TestsSpecification
64-
err = yaml.Unmarshal([]byte(data), &spec)
65-
if err != nil {
66-
t.Error(err)
67-
}
68-
6977
for _, test := range spec.Tests {
7078
for _, argSet := range test.ArgSets {
7179
for cluster, rootURLs := range spec.RootURLs {
@@ -77,6 +85,22 @@ func TestURLs(t *testing.T) {
7785
}
7886
}
7987

88+
func TestNormalize(t *testing.T) {
89+
spec, err := getTests()
90+
if err != nil {
91+
t.Error(err)
92+
}
93+
94+
expected := spec.RootURLs["new"][0]
95+
for _, rootURL := range spec.RootURLs["new"] {
96+
actual := NormalizeRootURL(rootURL)
97+
if expected != actual {
98+
t.Errorf("%v NormalizeRootURL(%v) = `%v` but should be `%v`", redCross(), rootURL, actual, expected)
99+
}
100+
t.Logf("%v NormalizeRootURL(%v) = `%v`", greenTick(), rootURL, actual)
101+
}
102+
}
103+
80104
// quotedList returns a backtick-quoted list of the arguments passed in
81105
func quotedList(url string, args []string) string {
82106
all := append([]string{url}, args...)

test/basic_test.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@ const yaml = require('js-yaml');
55
const libUrls = require('../');
66

77
const SPEC_FILE = path.join(__dirname, '../tests.yml');
8+
const TESTS = yaml.safeLoad(fs.readFileSync(SPEC_FILE, {encoding: 'utf8'}));
89

910
suite('basic test', function() {
10-
11-
var doc = yaml.safeLoad(fs.readFileSync(SPEC_FILE, {encoding: 'utf8'}));
12-
for (let t of doc['tests']) {
11+
for (let t of TESTS['tests']) {
1312
for (let argSet of t['argSets']) {
14-
for (let cluster of Object.keys(doc['rootURLs'])) {
15-
for (let rootURL of doc['rootURLs'][cluster]) {
13+
for (let cluster of Object.keys(TESTS['rootURLs'])) {
14+
for (let rootURL of TESTS['rootURLs'][cluster]) {
1615
test(`${t['function']} - ${argSet}`, function() {
1716
assert.equal(t['expected'][cluster], libUrls.withRootUrl(rootURL)[t['function']](...argSet));
1817
assert.equal(t['expected'][cluster], libUrls[t['function']](rootURL, ...argSet));
@@ -22,3 +21,12 @@ suite('basic test', function() {
2221
}
2322
}
2423
});
24+
25+
suite('normalization', function() {
26+
const correct = TESTS.rootURLs['new'][0];
27+
for (let rootUrl of TESTS.rootURLs['new']) {
28+
test(`normalize ${rootUrl}`, function() {
29+
assert.equal(libUrls.normalizeRootUrl(rootUrl), correct);
30+
});
31+
}
32+
});

test/normalize_test.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import os
2+
import yaml
3+
import taskcluster_urls as tcurls
4+
5+
6+
SPEC_FILE = os.path.join(os.path.dirname(__file__), '..', 'tests.yml')
7+
8+
9+
def pytest_generate_tests(metafunc):
10+
with open(SPEC_FILE) as testsFile:
11+
spec = yaml.load(testsFile)
12+
root_urls = spec['rootURLs']['new']
13+
expected_url = root_urls[0]
14+
metafunc.parametrize(
15+
['expected_url', 'root_url'],
16+
[
17+
(expected_url, root_url)
18+
for root_url in root_urls
19+
]
20+
)
21+
22+
23+
def test_normalize(expected_url, root_url):
24+
assert tcurls.normalize_root_url(root_url) == expected_url

0 commit comments

Comments
 (0)