blob: 93e400c45725f941cb2068cd9a3209ad9393b9e7 [file] [log] [blame] [edit]
# Check that the LNT REST JSON API is working.
# create temporary instance
# RUN: rm -rf %t.instance
# RUN: python %{shared_inputs}/create_temp_instance.py \
# RUN: %s %{shared_inputs}/SmallInstance \
# RUN: %t.instance %S/Inputs/V4Pages_extra_records.sql
#
# RUN: python %s %t.instance
from V4Pages import check_json
import lnt.server.db.migrate
import lnt.server.ui.app
import logging
import sys
import unittest
import yaml
logging.basicConfig(level=logging.DEBUG)
machines_expected_response = [{u'hardware': u'x86_64',
u'os': u'Darwin 11.3.0',
u'id': 1,
u'name': u'localhost__clang_DEV__x86_64',
u'hostname': u'localhost',
u'uname': u'Darwin localhost 11.3.0 Darwin Kernel Version 11.3.0: Thu Jan 12'
u' 18:47:41 PST 2012; root:xnu-1699.24.23~1/RELEASE_X86_64 x86_64'},
{u'hardware': u'AArch64',
u'os': u'linux',
u'id': 2,
u'name': u'machine2'},
{u'hardware': u'AArch64',
u'os': u'linux',
u'id': 3,
u'name': u'machine3'}]
order_expected_response = {u'llvm_project_revision': u'154331',
u'id': 1}
sample_expected_response = {u'id': 1,
u'execution_time': 0.0003,
u'test_id': 1,
u'compile_time': 0.007}
graph_data = [[u'152292', 1.0,
{u'date': u'2012-05-01 16:28:23',
u'label': u'152292',
u'runID': u'5'}],
[u'152293', 10.0,
{u'date': u'2012-05-03 16:28:24',
u'label': u'152293',
u'runID': u'6'}]]
graph_data2 = [[u'152293', 10.0,
{u'date': u'2012-05-03 16:28:24',
u'label': u'152293',
u'runID': u'6'}]]
possible_run_keys = {
u'ARCH',
u'CC_UNDER_TEST_IS_CLANG',
u'CC_UNDER_TEST_TARGET_IS_X86_64',
u'DISABLE_CBE',
u'DISABLE_JIT',
u'ENABLE_HASHED_PROGRAM_OUTPUT',
u'ENABLE_OPTIMIZED',
u'LLC_OPTFLAGS',
u'LLI_OPTFLAGS',
u'OPTFLAGS',
u'TARGET_CC',
u'TARGET_CXX',
u'TARGET_FLAGS',
u'TARGET_LLVMGCC',
u'TARGET_LLVMGXX',
u'TEST',
u'USE_REFERENCE_OUTPUT',
u'__report_version__',
u'cc1_exec_hash',
u'cc_alt_src_branch',
u'cc_alt_src_revision',
u'cc_as_version',
u'cc_build',
u'cc_exec_hash',
u'cc_ld_version',
u'cc_name',
u'cc_src_branch',
u'cc_src_revision',
u'cc_target',
u'cc_version',
u'cc_version_number',
u'end_time',
u'id',
u'inferred_run_order',
u'llvm_project_revision',
u'no_errors',
u'order_by',
u'order_id',
u'start_time',
u'sw_vers',
u'test_suite_revision',
}
possible_machine_keys = {u'name',
u'hostname',
u'hardware',
u'os',
u'id',
u'uname'}
class JSONAPITester(unittest.TestCase):
"""Test the REST api."""
def setUp(self):
"""Bind to the LNT test instance."""
_, instance_path = sys.argv
self.instance_path = instance_path
app = lnt.server.ui.app.App.create_standalone(instance_path)
app.testing = True
self.client = app.test_client()
def _check_response_is_well_formed(self, response):
"""API Should always return the generated by field in the top level dict."""
# All API calls should return a top level dict.
self.assertEqual(type(response), dict)
# There should be no unexpected top level keys.
all_top_level_keys = {'generated_by', 'machine', 'machines', 'runs', 'run', 'orders', 'tests', 'samples'}
keys = set(response.keys())
self.assertTrue(keys.issubset(all_top_level_keys),
"{} not subset of {}".format(keys, all_top_level_keys))
# All API calls should return as generated by.
self.assertIn("LNT Server v", response['generated_by'])
def test_machine_api(self):
"""Check /machines/ and /machines/n return expected results from testdb.
"""
client = self.client
# All machines returns the list of machines with parameters, but no runs.
j = check_json(client, 'api/db_default/v4/nts/machines/')
self._check_response_is_well_formed(j)
self.assertEqual(j['machines'], machines_expected_response)
self.assertIsNone(j.get('runs'))
j = check_json(client, 'api/db_default/v4/nts/machines')
self._check_response_is_well_formed(j)
self.assertEqual(j['machines'], machines_expected_response)
self.assertIsNone(j.get('runs'))
# Machine + properties + run information.
j = check_json(client, 'api/db_default/v4/nts/machines/1')
self._check_response_is_well_formed(j)
self.assertEqual(j['machine'], machines_expected_response[0])
self.assertEqual(len(j['runs']), 2)
for run in j['runs']:
self.assertSetEqual(set(run.keys()), possible_run_keys)
# Specify machine by name
j = check_json(client, 'api/db_default/v4/nts/machines/localhost__clang_DEV__x86_64')
self._check_response_is_well_formed(j)
self.assertEqual(j['machine'], machines_expected_response[0])
# Invalid machine ids are 404.
check_json(client, 'api/db_default/v4/nts/machines/99', expected_code=404)
check_json(client, 'api/db_default/v4/nts/machines/foo', expected_code=404)
def test_run_api(self):
"""Check /runs/n returns expected run information."""
client = self.client
j = check_json(client, 'api/db_default/v4/nts/runs/1')
self._check_response_is_well_formed(j)
expected = {"end_time": "2012-04-11T16:28:58",
"start_time": "2012-04-11T16:28:23",
"id": 1,
"llvm_project_revision": u'154331'}
self.assertEqual(j['run'], j['run'] | expected)
self.assertEqual(len(j['tests']), 2)
# This should not be a run.
check_json(client, 'api/db_default/v4/nts/runs/100', expected_code=404)
def test_order_api(self):
"""Check /orders/n returns the expected order information."""
client = self.client
j = check_json(client, 'api/db_default/v4/nts/orders/1')
self.assertEqual(j['orders'][0], order_expected_response)
self._check_response_is_well_formed(j)
check_json(client, 'api/db_default/v4/nts/orders/100', expected_code=404)
def test_single_sample_api(self):
"""Check /samples/n returns the expected sample information."""
client = self.client
j = check_json(client, 'api/db_default/v4/nts/samples/1')
self._check_response_is_well_formed(j)
self.assertEqual(sample_expected_response, j['samples'][0])
check_json(client, 'api/db_default/v4/nts/samples/1000', expected_code=404)
def test_graph_api(self):
"""Check that /graph/x/y/z returns what we expect."""
client = self.client
j = check_json(client, 'api/db_default/v4/nts/graph/2/4/2')
# TODO: Graph API needs redesign to be well formed.
# self._check_response_is_well_formed(j)
self.assertEqual(graph_data, j)
# Now check that limit works.
j2 = check_json(client, 'api/db_default/v4/nts/graph/2/4/2?limit=1')
# self._check_response_is_well_formed(j)
self.assertEqual(graph_data2, j2)
def test_samples_api(self):
"""Samples API."""
client = self.client
# Run IDs must be passed, so 400 if they are not.
check_json(client, 'api/db_default/v4/nts/samples',
expected_code=400)
# Simple single run.
j = check_json(client, 'api/db_default/v4/nts/samples?runid=1')
self._check_response_is_well_formed(j)
expected = [
{u'compile_time': 0.007, u'llvm_project_revision': u'154331',
u'name': u'SingleSource/UnitTests/2006-12-01-float_varg',
u'run_id': 1, u'execution_time': 0.0003, u'id': 1},
{u'compile_time': 0.0072, u'llvm_project_revision': u'154331',
u'name': u'SingleSource/UnitTests/2006-12-04-DynAllocAndRestore',
u'run_id': 1,
u'execution_time': 0.0003,
u'id': 2}]
self.assertEqual(j['samples'], expected)
# Check that other args are ignored.
extra_param = check_json(client,
'api/db_default/v4/nts/samples?runid=1&foo=bar')
self._check_response_is_well_formed(extra_param)
self.assertEqual(j, extra_param)
# There is only one run in the DB.
two_runs = check_json(client,
'api/db_default/v4/nts/samples?runid=1&runid=2')
self._check_response_is_well_formed(two_runs)
self.assertEqual(j, two_runs)
def test_fields_api(self):
"""Fields API."""
client = self.client
j = check_json(client, 'api/db_default/v4/nts/fields')
fields = j['fields']
# check number of fields
self.assertEqual(9, len(fields))
# check first field
f0 = fields[0]
self.assertEqual(0, f0['column_id'])
self.assertEqual('compile_time', f0['column_name'])
self.assertEqual('FLOAT', f0['column_type'])
def test_tests_api(self):
"""Tests API."""
client = self.client
j = check_json(client, 'api/db_default/v4/nts/tests')
tests = j['tests']
# check number of tests
self.assertEqual(9, len(tests))
# check first test
t0 = tests[0]
self.assertEqual(1, t0['id'])
self.assertEqual('SingleSource/UnitTests/2006-12-01-float_varg', t0['name'])
def test_schema(self):
client = self.client
rest_schema = check_json(client, 'api/db_default/v4/nts/schema')
# The reported schema should be the same as the yaml one on the top.
with open('%s/schemas/nts.yaml' % self.instance_path) as syaml:
yaml_schema = yaml.safe_load(syaml)
# Do some massaging to make it similar to the rest API result.
for m in yaml_schema['metrics']:
if 'unit' not in m:
m['unit'] = None
if 'unit_abbrev' not in m:
m['unit_abbrev'] = None
if 'display_name' not in m:
m['display_name'] = m['name']
if 'bigger_is_better' not in m:
m['bigger_is_better'] = False
yaml_schema['metrics'].sort(key=lambda x: x['name'])
yaml_schema['run_fields'].sort(key=lambda x: x['name'])
yaml_schema['machine_fields'].sort(key=lambda x: x['name'])
self.assertEqual(rest_schema, yaml_schema)
if __name__ == '__main__':
unittest.main(argv=[sys.argv[0], ])