HTTP REST API v2

The HTTP REST API allows you to control your Stb-tester HDMI and Stb-tester CAMERA devices programmatically using HTTP requests and JSON.

This API is intended for integrating stb-tester with external systems, such as a Continuous Integration system.

If you are using the Stb-tester ONE (our previous-generation product) see REST API v1 instead.

Authentication

To allow your scripts to access this API without providing your password, you need to generate an access token: Log into the portal using your browser, click on the user menu in the top right corner, and select “Generate new access token”. You can revoke access tokens from the same menu.

images/generate-new-access-token.png

You must specify the token in the Authorization HTTP header of every request. If the token is missing or invalid you will get a “403 Forbidden” response.

Example using curl:

curl -H "Authorization: token BP7BxqZvuZPGeQRBuG6fxh7S_B1iWmS9" \
     https://company.stb-tester.com/api/...

Example using Python requests:

import requests
requests.post("https://company.stb-tester.com/api/...",
              headers={"Authorization": "token BP7BxqZvuZPGeQRBuG6fxh7S_B1iWmS9"})

If you need to make multiple HTTP requests from a single script you can use requests.Session to set default values for every request:

import requests
session = requests.Session()
session.headers.update({"Authorization": "token BP7BxqZvuZPGeQRBuG6fxh7S_B1iWmS9"})
session.get("https://company.stb-tester.com/api/...")
session.post("https://company.stb-tester.com/api/...")

Rate limits

Automated scripts that make many requests are subject to rate-limiting. If you are making requests in serial, you probably won’t even notice the rate-limiting, but if you send many requests at once in parallel, the requests may fail with the HTTP status code 429 Too Many Requests. If you receive a 429 response, your script should wait a few seconds before retrying.

The endpoints for downloading test-results artifacts have a generous “burst” rate, to allow batch scripts that download artifacts from a job with many test-runs.

Grab screenshot

GET /api/v2/nodes/(node_id)/screenshot.png

Grab a screenshot from the device under test.

Example using curl:

Save a screenshot to screenshot.png:

curl -H "Authorization: token BP7BxqZvuZPGeQRBuG6fxh7S_B1iWmS9" \
    https://company.stb-tester.com/api/v2/nodes/stb-tester-abcdef123456/screenshot.png \
    > screenshot.png
Response Headers:
 
Status Codes:

Grab screenshot thumbnail

GET /api/v2/nodes/(node_id)/thumbnail.jpg

Grab a small thumbnail of the screenshot from the device under test.

Example using curl:

Save a screenshot to thumbnail.jpg:

curl -O -H "Authorization: token BP7BxqZvuZPGeQRBuG6fxh7S_B1iWmS9" \
    https://company.stb-tester.com/api/v2/nodes/stb-tester-abcdef123456/thumbnail.jpg
Response Headers:
 
Status Codes:

List testcases

GET /api/v2/test_pack/<test_pack_sha>/test_case_names

List testcases found at a particular revision (test_pack_commit_sha) of your test-pack. These names can be passed to /api/v2/run_tests.

Example using Python requests:

List the testcases in your local git checkout HEAD:

import requests, subprocess

my_sha = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip()
tests = requests.get(
    "https://company.stb-tester.com/api/v2/test_pack/%s/test_case_names" % my_sha,
    headers={"Authorization": "token BP7BxqZvuZPGeQRBuG6fxh7S_B1iWmS9"}
    ).json()
for test_name in tests:
    print test_name
tests/menu.py::test_that_menu_appears_when_menu_key_is_pressed
tests/menu.py::test_that_close_button_closes_menu
tests/live_tv.py::test_that_pause_button_pauses_live_tv
Response Headers:
 
Status Codes:

Run tests

POST /api/v2/run_tests

Run the specified testcases from the given git commit. The parameters are encoded in the request body as a JSON object. Returns a job_uid that can be used to poll for job completion and test results.

Example using Python requests:

Start a test job with a single test:

response = requests.post(
    "https://company.stb-tester.com/api/v2/run_tests",
    headers={"Authorization": "token BP7BxqZvuZPGeQRBuG6fxh7S_B1iWmS9"},
    data=json.dumps({
        "node_id": "stb-tester-abcdef123456",
        "test_pack_revision": "master",
        "test_cases": ["tests/menu.py::test_that_menu_appears_when_menu_key_is_pressed"],
        "remote_control": "roku",
        }))
print response.json()
{'job_uid': '/stb-tester-abcdef123456/0a23/972',
 'job_url': 'https://company.stb-tester.com/api/v2/jobs/stb-tester-abcdef123456/0a23/972',
 'status': 'running',
 'start_time': '2015-05-28T14:46:35.354791Z',
 'end_time': None,
 'result_counts': {'pass': 0, 'fail': 0, 'error': 0, 'total': 1},
}

To make it easier for you to integrate Stb-tester with a Continuous Integration system such as Jenkins, we provide a helper script called stbt_rig.py. See Continuous Integration for details.

Request JSON Object:
 
  • node_id (string) – (mandatory) Which Stb-tester device to run the tests on. This is the name of the device as shown in the portal and on the physical case of the device, for example stb-tester-abcdef123456.
  • test_pack_revision (string) – (mandatory) Git commit SHA in test-pack repository identifying the version of the tests to run. Can also be the name of a git tag or branch.
  • test_cases (array) –

    (mandatory) List of tests to run.

    Testcase names have the form (filename)::(function_name) where filename is given relative to the root of the test-pack repository and function_name identifies a function within that file; for example tests/my_test.py::test_that_blah_dee_blah.

    The list of all possible testcase names for a given revision can be retrieved using /api/v2/test_pack/(test_pack_commit_sha)/test_case_names.

  • remote_control (string) –

    (usually mandatory) The remote control infrared configuration to use when running the tests.

    This should match the name of a remote control configuration file in your test-pack git repository. For example if your test-pack has config/remote-control/Sony_RM-ED022.lircd.conf, then you should specify "Sony_RM-ED022".

    If not specified in the HTTP request, you must specify test_pack.default_remote_control in your test-pack’s configuration files.

  • category (string) –

    (optional) Category to save the results in. Defaults to "default".

    When you are viewing test results you can filter by this string so that you don’t see results that you aren’t interested in. For example you might set this to “soak test of release x”.

    This must be a valid UTF-8 string and must not contain the characters /, newline (\n), colon (:), NUL (\0), $, or any control characters. It must not start with . or - and must not be empty. UTF-8 encoded Unicode characters are accepted.

  • soak (string) –

    (optional) Soak-testing mode. The allowed values are:

    • "run once" – this is the default mode; it runs each of the specified testcases once.
    • "run forever" – runs each of the testcases once, then repeats, forever. Use /api/v2/jobs/(job_uid)/stop to stop it.
  • shuffle (bool) –

    (optional) Randomise the order in which the tests are run. The allowed values are:

    • true – Randomise the order in which the testcases are run, weighting towards running the faster testcases more often. See Run forever in random order for more information.
    • false – Run the testcases in the order in which they appear in test_cases. This is the default if shuffle is omitted.
  • tags (object) – (optional) Map of name:value pairs, for example {"model": "T-1000"}. Tags are passed to the test script as an automatic configuration key and are recorded in the test-results. Tags set here can be retrived in Python during the test-run with stbt.get_config("result.tags", "tagname"). See also Tags.
Response JSON Object:
 
Request Headers:
 
Response Headers:
 
Status Codes:

Inspect a test job

GET /api/v2/jobs/(job_uid)

Find out the current status of the job started with /api/v2/run_tests.

Parameters:
  • job_uid – The desired job’s universal identifier, as returned from /api/v2/run_tests.
Response JSON Object:
 
  • job_uid (string) – Identifier that refers to this test job. This is unique across all Stb-tester devices in your test farm.
  • job_url (string) – The URL of this endpoint. This is included here for consistency with /api/v2/run_tests.
  • status (string) – Current status of the job. This can be either "running" or "exited".
  • start_time (string) – The time at which the job started as an ISO8601 formatted datetime (for example "2015-05-28T14:46:35.354791Z").
  • end_time (string) – The time at which the job finished as an ISO8601 formatted datetime, or null if the job is still running.
  • result_counts (object) –

    A summary of the test results. This is a dictionary with the following keys:

    • pass – number of tests that completed and passed.
    • fail – number of tests that completed but failed.
    • error – number of tests that couldn’t complete due to an error (see Exceptions in the Python API reference).
    • total – can be greater than pass+fail+error if the job is still running or was stopped prematurely.
Response Headers:
 
Status Codes:

Inspect a node’s current test job

GET /api/v2/nodes/(node_id)/job

Similar to /api/v2/jobs/(job_uid) but instead of specifying a job_uid, it retrieves the current job on the specified Stb-tester device (or the last job that ran on that device if there is no job currently in progress).

Status Codes:

Stop a job in progress

POST /api/v2/jobs/(job_uid)/stop

Stop a job started with /api/v2/run_tests.

By the time this endpoint returns a response, the job will be stopped. This makes it safe to use /api/v2/run_tests immediately after you receive the HTTP response from this endpoint.

This endpoint will respond with HTTP status 200 even if the job has already exited. This makes it safe to stop a job any number of times.

Parameters:
  • job_uid – The desired job’s universal identifier, as returned from /api/v2/run_tests.
Status Codes:

Stop a node’s current job

POST /api/v2/nodes/(node_id)/job/stop

Similar to /api/v2/jobs/(job_uid)/stop but instead of specifying a job_uid, it stops the job that is currently running on the specified Stb-tester device.

Status Codes:

Get list of test results

GET /api/v2/results

Retrieve test results for each test run, optionally filtered by a search expression.

Notes:

  • The response will not include a test-run that is currently in progress.
  • The response only includes the first 2,000 matching test-runs. Use the filter and sort parameters to retrieve older results (for example, sort by date, then make a second request using a filter to exclude results newer than the last result in the first response).

Example using Python requests:

response = requests.get(
    "https://company.stb-tester.com/api/v2/results",
    headers={"Authorization": "token BP7BxqZvuZPGeQRBuG6fxh7S_B1iWmS9"},
    params={"filter": "job:/stb-tester-abcdef123456/0a23/972"})
print response.json()
[{'result_id': '/stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.34'
  'job_uid': '/stb-tester-abcdef123456/0a23/972',
  'result_url': 'https://company.stb-tester.com/api/v2/results/stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.34',
  'triage_url': 'https://company.stb-tester.com/app/#/result//stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.34',
  'start_time': '2015-05-28T14:46:35.354791Z',
  'end_time': '2015-05-28T14:46:42.325432Z',
  'test_pack_sha': 'c2c82cad08114f973e2c36f0bbfbfb0a78dad911',
  'test_case': 'tests/epg.py::test_that_epg_is_populated',
  'result': 'fail',
  'failure_reason': 'EPG is empty'
 },
 {'result_id': '/stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.44'
  'job_uid': '/stb-tester-abcdef123456/0a23/972',
  'result_url': 'https://company.stb-tester.com/api/v2/results/stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.44',
  'triage_url': 'https://company.stb-tester.com/app/#/result//stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.44',
  'start_time': '2015-05-28T14:46:45.431553Z',
  'end_time': '2015-05-28T14:46:49.334224Z',
  'test_pack_sha': 'c2c82cad08114f973e2c36f0bbfbfb0a78dad911',
  'test_case': 'tests/epg.py::test_that_epg_is_populated',
  'result': 'pass',
  'failure_reason': None
 }
]
Query Parameters:
 
  • filter – A search expression in the same format as the interactive search box in the test-results web interface, documented here. If not specified it will return all results (up to a limit of 2,000 results).
  • sort – “<fieldname>:asc” or “<fieldname>:desc”. Sort results by the specified field in ascending or descending order. <fieldname> can be “category”, “date”, “duration”, “job”, “testcase”, or “result”. Defaults to “date:desc”.
  • tz – A name like “America/Denver” from the Olson timezone database. This is the default timezone used for any dates specified in the filter parameter if the timezone isn’t explicit in those dates. Defaults to “UTC”.

The response consists of a JSON array of JSON objects. Each object corresponds to a test run. Each object contains a subset of the fields from /api/v2/results/(result_id):

Response JSON Object:
 
  • result_id (string) – Identifier that refers to this test result. This is unique across all Stb-tester devices in your test farm.
  • result_url (string) – The REST API URL of this test result. You can use this URL to retrieve more information about the test run – see /api/v2/results/(result_id). You can also retrieve test artifacts such as logs and screenshots by appending /artifacts/(filename) to the url.
  • triage_url (string) – The URL of this test result in the portal, for viewing in a web browser.
  • job_uid (string) – Identifier that refers to this test job. See /api/v2/jobs/(job_uid).
  • start_time (string) – The time at which the test run started as an ISO8601 formatted datetime (for example "2015-05-28T14:46:35.354791Z").
  • end_time (string) – The time at which the test run finished as an ISO8601 formatted datetime.
  • test_case (string) – The name of the testcase as given to /api/v2/run_tests.
  • test_pack_sha (string) – The git sha of the test-pack revision as given to /api/v2/run_tests.
  • result (string) –

    One of the following values:

    • pass – the testcase completed and passed.
    • fail – the testcase completed but failed.
    • error – the testcase couldn’t complete due to an error (see Exceptions in the Python API reference).
  • failure_reason (string) – The exception message when the test failed. null if the test passed.
Response Headers:
 
Status Codes:

Get list of test results (CSV)

GET /api/v2/results.csv

Takes the same parameters as /api/v2/results but returns CSV format (comma-separated values, suitable for opening with Excel) instead of JSON.

Get list of test results (XML)

GET /api/v2/results.xml

Takes the same parameters as /api/v2/results but returns XML data (in jUnit format, which Jenkins knows how to interpret) instead of JSON.

Get detailed information about a test run

GET /api/v2/results/(result_id)/

Retrieve detailed information about a test result.

Example using Python requests:

response = requests.get(
    'https://company.stb-tester.com/api/v2/results/' +
    'stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.44')
print response.json()
{'result_id': '/stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.34'
 'job_uid': '/stb-tester-abcdef123456/0a23/972',
 'result_url': 'https://company.stb-tester.com/api/v2/results/stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.34',
 'triage_url': 'https://company.stb-tester.com/app/#/result//stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.34',
 'start_time': '2015-05-28T14:46:35.354791Z',
 'end_time': '2015-05-28T14:46:42.325432Z',
 'test_case': 'tests/epg.py::test_that_epg_is_populated',
 'test_pack_branch': 'refs/heads/master',
 'test_pack_sha': 'c2c82cad08114f973e2c36f0bbfbfb0a78dad911',
 'username': 'drothlis',
 'result': 'fail',
 'failure_reason': 'EPG is empty',
 'traceback': '''Traceback (most recent call last):
  File "/usr/lib/stbt/stbt-run", line 88, in <module>
    function()
  File "tests/epg.py", line 24, in test_that_epg_is_populated
    assert epg_is_populated(), "EPG is empty"
AssertionError: EPG is empty''',
 'artifacts': {
     'combined.log': {'size': 39381},
     'duration': {'size': 3},
     'exit-status': {'size': 2},
     'failure-reason': {'size': 17},
     'git-commit': {'size': 8},
     'index.html': {'size': 2254},
     'screenshot.png': {'size': 196119},
     'stbt-version.log': {'size': 17},
     'stderr.log': {'size': 39161},
     'stdout.log': {'size': 220},
     'test-args': {'size': 1},
     'test-name': {'size': 70},
     'thumbnail.jpg': {'size': 15220},
     'video.webm': {'size': 262863},
     'my-custom-logfile.log': {'size': 52023},
     'a/file in a subdirectory/another.log': {'size': 2433}
 },
 'tags': {'model': 'T-1000'}
}
Parameters:
  • result_id – Identifier that refers to this test result, as returned from /api/v2/results. This is unique across all Stb-tester devices in your test farm.

The response consists of a JSON object, with the following elements:

Response JSON Object:
 
  • result_id (string) – Identifier that refers to this test result. This is unique across all Stb-tester devices in your test farm.
  • result_url (string) – The REST API URL of this test result.
  • triage_url (string) – The URL of this test result in the portal, for viewing in a web browser.
  • job_uid (string) – Identifier that refers to this test job. See /api/v2/jobs/(job_uid).
  • start_time (string) – The time at which the test run started as an ISO8601 formatted datetime (for example "2015-05-28T14:46:35.354791Z").
  • end_time (string) – The time at which the test run finished as an ISO8601 formatted datetime.
  • test_case (string) – The name of the testcase as given to /api/v2/run_tests.
  • test_pack_sha (string) – The git sha of the test-pack revision given to /api/v2/run_tests.
  • test_pack_branch (string) – The git “ref” name of the test-pack branch. If you specified a git sha instead of a branch name when you submitted /api/v2/run_tests, then this will be null.
  • username (string) – The user who started the test-job.
  • result (string) –

    One of the following values:

    • pass – the testcase completed and passed.
    • fail – the testcase completed but failed.
    • error – the testcase couldn’t complete due to an error (see Exceptions in the Python API reference).
  • failure_reason (string) – The exception message when the test failed. null if the test passed.
  • job_category (string) – The category as passed to /api/v2/run_tests when the tests were run.
  • traceback (string) – The traceback of the exception that caused the test to fail. null if the test passed.
  • artifacts (object) – The files created during the test run. See /api/v2/results/(result_id)/artifacts/ for details.
  • tags (object) – A mapping of name:value tags as given to /api/v2/run_tests.
Response Headers:
 
Status Codes:

Get log output from test run

GET /api/v2/results/(result_id)/stbt.log

Retrieve the output of the test run. This includes logging from stb-tester and any lines printed (written to stderr or stdout) by your testcase during the test run.

Each consists of

iso8601_datetime <space> line

e.g.:

2015-06-18T14:59:00.321421+00:00 A line from the test script

The file is served as utf-8, but no guarantees are made that the contents is valid utf-8.

Example using Python requests:

Show the output of a test run:

result_url = 'https://company.stb-tester.com/api/v2/results/stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.44'
response = requests.get('%s/stbt.log' % result_url')
print response.text
2015-06-16T07:29:17.162452+00:00 stbt-run: Arguments:
2015-06-16T07:29:17.162615+00:00 control: lirc:172.17.0.133:8765:vstb
2015-06-16T07:29:17.162646+00:00 args: ['test_that_when_pressing_back_i_go_back_to_where_i_was_before_action_panel_epg']
2015-06-16T07:29:17.162673+00:00 verbose: 1
2015-06-16T07:29:17.162701+00:00 source_pipeline: ximagesrc use-damage=false remote=true show-pointer=false display-name=:10 ! video/x-raw,framerate=24/1
2015-06-16T07:29:17.162728+00:00 script: /var/lib/stbt/test-pack/tests/brand_rollups.py
2015-06-16T07:29:17.162754+00:00 restart_source: False
2015-06-16T07:29:17.162781+00:00 sink_pipeline: fakesink sync=false
2015-06-16T07:29:17.162808+00:00 write_json: stbt-run.json
2015-06-16T07:29:17.162835+00:00 save_video: video.webm
2015-06-16T07:29:17.212650+00:00 stbt-run: Saving video to 'video.webm'
Parameters:
  • result_id – The desired result’s identifier, as returned from /api/v2/results.
Response Headers:
 
Status Codes:

Get screenshot saved at end of test run

GET /api/v2/results/(result_id)/screenshot.png

At the end of each test-run stb-tester saves a screenshot (in a lossless format) from the device under test. This can be useful for performing automated triage or as a source of new reference images.

This endpoint retrieves that screenshot.

Example usage:

Save the screenshot to disk as screenshot.png, using curl from the command line:

curl -O "https://company.stb-tester.com/api/v2/results/stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.44/screenshot.png"

Save the screenshot to disk from Python code, using the urllib module from the Python standard library:

import urllib
result_url = 'https://company.stb-tester.com/api/v2/results/stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.44'
urllib.urlretrieve('%s/screenshot.png' % result_url, 'screenshot.png')

View the screenshot in IPython notebook, using the Python requests library:

import IPython.display, requests
result_url = 'https://company.stb-tester.com/api/v2/results/stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.44'
response = requests.get('%s/screenshot.png' % result_url)
IPython.display.Image(data=response.content)

Try a stbt.match against the saved screenshot:

import cv2, numpy, requests, stbt
result_url = 'https://company.stb-tester.com/api/v2/results/stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.44'
response = requests.get('%s/screenshot.png' % result_url)
image = cv2.imdecode(numpy.frombuffer(response.content, dtype='uint8'), 1)
print stbt.match('my-reference.png', frame=image)
MatchResult(timestamp=None, match=False, region=Region(x=82, y=48, width=54, height=54), first_pass_result=0.942756436765, frame=1280x720x3, image='my-reference.png')
Parameters:
  • result_id – The desired result’s identifier, as returned from /api/v2/results.
Response Headers:
 
Status Codes:

List artifacts produced during a test run

GET /api/v2/results/(result_id)/artifacts/

List the files saved during a test run. This includes files written by stb-tester and any files written by your test scripts or pre/post_run scripts into the current working directory while the test is running.

Note: The files that stb-tester writes may change depending on the value of test_pack.stbt_version in .stbt.conf. It is therefore recommended to only rely on this endpoint to retrieve test artifacts that the test-scripts explicitly write and to use the values of /api/v2/results/(result_id) for data provided by stb-tester.

Example using Python requests:

List the files produced by a test run.

result_url = 'https://company.stb-tester.com/api/v2/results/stb-tester-abcdef123456/0a23/972/2015-05-28_14.46.44'
response = requests.get('%s/artifacts/ % result_url')
print response.json()
{
  'combined.log': {'size': 39381},
  'duration': {'size': 3},
  'exit-status': {'size': 2},
  'failure-reason': {'size': 17},
  'git-commit': {'size': 8},
  'index.html': {'size': 2254},
  'screenshot.png': {'size': 196119},
  'stbt-version.log': {'size': 17},
  'stderr.log': {'size': 39161},
  'stdout.log': {'size': 220},
  'test-args': {'size': 1},
  'test-name': {'size': 70},
  'thumbnail.jpg': {'size': 15220},
  'video.webm': {'size': 262863},
  'my-custom-logfile.log': {'size': 52023},
  'a/file in a subdirectory/another.log': {'size': 2433}
}
Parameters:
  • result_id – The desired result’s identifier, as returned from /api/v2/results.

The response is a JSON object. The keys of the object are filenames and the values are dictionaries containing additional information about the files. Files in subdirectories are also listed, but the directories themselves won’t appear in the listing.

The information about each file is:

Response JSON Object:
 
  • size (string) – The size of the file in bytes.
Response Headers:
 
Status Codes:

Get an artifact produced during a test run

GET /api/v2/results/(result_id)/artifacts/(filename)

Retrieve files recorded during a test run.

For examples see the examples for the screenshot endpoint.

Parameters:
  • result_id – The desired result’s identifier, as returned from /api/v2/results.
  • filename – The name of the file to retrive.

The response consists of the contents of a file given by filename recorded during a test run.

Response Headers:
 
  • Content-Type – Varies depending on the filename extension.
Status Codes:

Migrating from v1

If you are already familiar with the REST API v1 used by the Stb-tester ONE (our previous-generation product), here are the main differences:

  • You send HTTP requests to your Stb-tester Portal (https://<company>.stb-tester.com), not to individual Stb-tester devices directly.
  • Some endpoints require the node_id parameter, to specify which Stb-tester device to use. This is the name of the device as shown in the portal (also labelled on the physical case of the device). For example stb-tester-abcdef123456.
  • Each HTTP request needs to include an access token. See Authentication above.
  • The remote_control parameter of /api/v2/run_tests doesn’t default to the first remote control alphabetically. You must specify the remote_control parameter in your HTTP request, or specify test_pack.default_remote_control in your test-pack configuration files.
  • The /api/v1/result/… endpoints have been renamed to /api/v2/results/… (plural) for consistency.
  • The deprecated endpoint /api/v1/jobs/(job_uid)/results has been removed. Use /api/v2/results with the filter parameter set to job:<job_uid>.