Skip to content

Commit

Permalink
Merge pull request #31 from djmitche/normalize
Browse files Browse the repository at this point in the history
Add normalizeRootUrl
  • Loading branch information
djmitche authored Nov 19, 2019
2 parents 41eebde + 0d76562 commit 82317d2
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 13 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ A simple library to generate URLs for various Taskcluster resources across our v
This serves as both a simple shim for projects that use JavaScript but also is the reference implementation for
how we define these paths.

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

Changelog
---------
Expand Down Expand Up @@ -40,6 +40,7 @@ root URL:
* `apiManifest(rootUrl)` -> `String`
* `testRootUrl()` -> `String`
* `withRootUrl(rootUrl)` -> `Class` instance for above methods
* `normalizeRootUrl(rootUrl)` -> `String` (the "normalized" form of the given rootUrl)

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

Install with:
Expand Down Expand Up @@ -146,6 +148,7 @@ taskcluster_urls.exchange_reference(root_url, 'auth', 'v1')
taskcluster_urls.ui(root_url, 'foo/bar')
taskcluster_urls.apiManifest(root_url)
taskcluster_urls.docs(root_url, 'foo/bar')
taskcluster_urls.normalized_root_url(root_url)

And for testing,
```python
Expand Down
4 changes: 4 additions & 0 deletions docs/urls-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ Example:
https://taskcluster.example.com
```

Normally, a rootUrl has no trailing `/` characters.
We suggest that libraries and tools be lenient and accept rootUrls containing a trailing `/`, but produce rootUrls without a trailing `/`.
The `normalizeRootUrl` function supports this practice.

# URLs

Taskcluster uses URLs with the following pattern:
Expand Down
7 changes: 7 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,11 @@ module.exports = {
testRootUrl() {
return 'https://tc-tests.example.com';
},

/**
* Return the normal form of this rootUrl
*/
normalizeRootUrl(rootUrl) {
return cleanRoot(rootUrl);
},
};
4 changes: 4 additions & 0 deletions taskcluster_urls/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,7 @@ def test_root_url():
"""Returns a standardized "testing" rootUrl that does not resolve but
is easily recognizable in test failures."""
return 'https://tc-tests.example.com'

def normalize_root_url(root_url):
"""Return the normal form of the given rootUrl"""
return root_url.rstrip('/')
5 changes: 5 additions & 0 deletions tcurls.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,8 @@ func APIManifest(rootURL string) string {
return fmt.Sprintf("%s/references/manifest.json", r)
}
}

// NormalizeRootURL returns the normal form of the given rootURL.
func NormalizeRootURL(rootURL string) string {
return strings.TrimRight(rootURL, "/")
}
38 changes: 31 additions & 7 deletions tcurls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ type TestsSpecification struct {
Tests []TestCase `yaml:"tests"`
}

func getTests() (*TestsSpecification, error) {
data, err := ioutil.ReadFile("tests.yml")
if err != nil {
return nil, err
}
var spec TestsSpecification
err = yaml.Unmarshal([]byte(data), &spec)
if err != nil {
return nil, err
}

return &spec, nil
}

func testFunc(t *testing.T, function string, expectedURL string, root string, args ...string) {
var actualURL string
switch function {
Expand Down Expand Up @@ -56,16 +70,10 @@ func testFunc(t *testing.T, function string, expectedURL string, root string, ar
}

func TestURLs(t *testing.T) {
data, err := ioutil.ReadFile("tests.yml")
spec, err := getTests()
if err != nil {
t.Error(err)
}
var spec TestsSpecification
err = yaml.Unmarshal([]byte(data), &spec)
if err != nil {
t.Error(err)
}

for _, test := range spec.Tests {
for _, argSet := range test.ArgSets {
for cluster, rootURLs := range spec.RootURLs {
Expand All @@ -77,6 +85,22 @@ func TestURLs(t *testing.T) {
}
}

func TestNormalize(t *testing.T) {
spec, err := getTests()
if err != nil {
t.Error(err)
}

expected := spec.RootURLs["new"][0]
for _, rootURL := range spec.RootURLs["new"] {
actual := NormalizeRootURL(rootURL)
if expected != actual {
t.Errorf("%v NormalizeRootURL(%v) = `%v` but should be `%v`", redCross(), rootURL, actual, expected)
}
t.Logf("%v NormalizeRootURL(%v) = `%v`", greenTick(), rootURL, actual)
}
}

// quotedList returns a backtick-quoted list of the arguments passed in
func quotedList(url string, args []string) string {
all := append([]string{url}, args...)
Expand Down
18 changes: 13 additions & 5 deletions test/basic_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ const yaml = require('js-yaml');
const libUrls = require('../');

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

suite('basic test', function() {

var doc = yaml.safeLoad(fs.readFileSync(SPEC_FILE, {encoding: 'utf8'}));
for (let t of doc['tests']) {
for (let t of TESTS['tests']) {
for (let argSet of t['argSets']) {
for (let cluster of Object.keys(doc['rootURLs'])) {
for (let rootURL of doc['rootURLs'][cluster]) {
for (let cluster of Object.keys(TESTS['rootURLs'])) {
for (let rootURL of TESTS['rootURLs'][cluster]) {
test(`${t['function']} - ${argSet}`, function() {
assert.equal(t['expected'][cluster], libUrls.withRootUrl(rootURL)[t['function']](...argSet));
assert.equal(t['expected'][cluster], libUrls[t['function']](rootURL, ...argSet));
Expand All @@ -22,3 +21,12 @@ suite('basic test', function() {
}
}
});

suite('normalization', function() {
const correct = TESTS.rootURLs['new'][0];
for (let rootUrl of TESTS.rootURLs['new']) {
test(`normalize ${rootUrl}`, function() {
assert.equal(libUrls.normalizeRootUrl(rootUrl), correct);
});
}
});
24 changes: 24 additions & 0 deletions test/normalize_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import os
import yaml
import taskcluster_urls as tcurls


SPEC_FILE = os.path.join(os.path.dirname(__file__), '..', 'tests.yml')


def pytest_generate_tests(metafunc):
with open(SPEC_FILE) as testsFile:
spec = yaml.load(testsFile)
root_urls = spec['rootURLs']['new']
expected_url = root_urls[0]
metafunc.parametrize(
['expected_url', 'root_url'],
[
(expected_url, root_url)
for root_url in root_urls
]
)


def test_normalize(expected_url, root_url):
assert tcurls.normalize_root_url(root_url) == expected_url

0 comments on commit 82317d2

Please sign in to comment.