blob: 8d80afcc752d3cf509976ca1105b28058f8211c1 [file] [log] [blame]
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import unittest
import mock
import webapp2
import webtest
from google.appengine.ext import ndb
from dashboard import graph_json
from dashboard import testing_common
from dashboard import utils
from dashboard.models import anomaly
from dashboard.models import graph_data
class GraphJsonTest(testing_common.TestCase):
def setUp(self):
super(GraphJsonTest, self).setUp()
app = webapp2.WSGIApplication(
[('/graph_json', graph_json.GraphJsonHandler)])
self.testapp = webtest.TestApp(app)
self.PatchDatastoreHooksRequest()
# TODO(qyearsley): graph_json_test is very slow (it takes 60+ seconds
# to run sometimes), and I have a hypothesis that most of the time is
# spent in _AddTestColumns. Investigate this hypothesis and make changes
# accordingly.
def _AddTestColumns(self, start_rev=15000, end_rev=16500, step=3):
"""Adds a bunch of test data to the mock datastore.
In particular, add Rows with revisions in the given range (but skipping
some numbers, so the revisions are non-contiguous) under the dromaeo/dom
test for winXP, win7, mac.
Args:
start_rev: Starting revision number.
end_rev: Ending revision number.
step: Difference between adjacent revisions.
"""
master = graph_data.Master(id='ChromiumGPU')
master.put()
bots = []
rows = []
for name in ['winXP', 'win7', 'mac']:
bot = graph_data.Bot(id=name, parent=master.key)
bot.put()
bots.append(bot)
test = graph_data.Test(id='dromaeo', parent=bot.key)
test.put()
for sub_name in ['dom', 'jslib']:
sub_test = graph_data.Test(id=sub_name, parent=test.key,
improvement_direction=anomaly.UP,
has_rows=True).put()
test_container_key = utils.GetTestContainerKey(sub_test)
for i in range(start_rev, end_rev, step):
# Add Rows for one bot with revision numbers that aren't lined up
# with the other bots.
rev = i + 1 if name == 'mac' else i
row = graph_data.Row(
parent=test_container_key, id=rev, value=float(i * 2),
r_webkit=int(i * 0.25), a_str='some_string',
buildnumber=i - start_rev,
a_tracing_uri='http://trace/%d' % i,
a_trace_rerun_options={'foo': '--foo'})
rows.append(row)
ndb.put_multi(rows)
def _AddLongTestColumns(self, start_rev=15000, end_rev=16500, step=3):
"""Adds test data with long nested sub test to the mock datastore.
Args:
start_rev: Starting revision number.
end_rev: Ending revision number.
step: Difference between adjacent revisions.
"""
master = graph_data.Master(id='master')
master.put()
bot = graph_data.Bot(id='bot', parent=master.key)
bot.put()
test = graph_data.Test(id='suite', parent=bot.key)
test.put()
rows = []
for sub_name in ['sub1', 'sub2', 'sub3', 'sub4', 'sub5']:
test = graph_data.Test(id=sub_name, parent=test.key,
improvement_direction=anomaly.UP,
has_rows=True)
test.put()
test_container_key = utils.GetTestContainerKey(test.key)
for i in range(start_rev, end_rev, step):
row = graph_data.Row(
parent=test_container_key, id=i, value=float(i * 2),
r_webkit=int(i * 0.25), a_str='some_string',
buildnumber=i - start_rev,
a_tracing_uri='http://trace/%d' % i,
a_trace_rerun_options={'foo': '--foo'})
rows.append(row)
ndb.put_multi(rows)
def _GetSeriesIndex(self, flot, test_path):
series = flot['annotations']['series']
for index in series:
if series[index]['path'] == test_path:
return index
return None
def CheckFlotJson(
self, json_str, num_rows, num_cols, start_rev, end_rev, step=3):
"""Checks whether a JSON string output by GetGraphJson is correct.
It's assumed that data should match data that might be added by the
_AddTestColumns method above.
In general, the Flot JSON should at contain a dict with the key 'data'
which is mapped to a list of dicts (which represent data series), each of
which also has a key called 'data', which is mapped to a list of 2-element
lists (which represent points). For example:
{data: {data: [[1, 10], [2, 20]]}, {data: [[3, 30], [4, 40]]}}
Args:
json_str: The JSON string to check.
num_rows: The expected number of points in each trace.
num_cols: The expected number of trace lines.
start_rev: Starting revision number.
end_rev: End revision number.
step: Expected difference between adjacent revision numbers.
"""
try:
flot = json.loads(json_str)
except ValueError:
self.fail('GetGraphJson returned invalid JSON')
data = flot.get('data')
if not data:
self.fail('No flot data generated by GetGraphJson')
self.assertEqual(num_cols, len(data))
for key in data:
col = data[key]
if not col.get('data'):
self.fail('No flot columns generated by GetGraphJson')
self.assertEqual(num_rows, len(col['data']))
for index, rev in enumerate(range(start_rev, end_rev, step)):
self.assertEqual(rev, col['data'][index][0])
self.assertEqual(rev * 2, col['data'][index][1])
def testPost_ValidRequest(self):
self._AddTestColumns(start_rev=15700, end_rev=16000, step=1)
graphs = {
'test_path_dict': {
'ChromiumGPU/winXP/dromaeo/dom': [],
'ChromiumGPU/winXP/dromaeo/jslib': [],
}
}
# If the request is valid, a valid response will be returned.
response = self.testapp.post(
'/graph_json', {'graphs': json.dumps(graphs)})
flot_json_str = response.body
self.CheckFlotJson(flot_json_str, 150, 2, 15850, 16000, step=1)
self.assertEqual('*', response.headers.get('Access-Control-Allow-Origin'))
def testPost_InvalidRequest_ReportsError(self):
self.testapp.post('/graph_json', {}, status=500)
self.testapp.post('/graph_json', {'graphs': ''}, status=500)
self.testapp.post('/graph_json', {'graphs': '{}'}, status=500)
def testPost_LongTestPathWithSelected(self):
self._AddLongTestColumns(start_rev=15700, end_rev=16000, step=1)
graphs = {
'test_path_dict': {
'master/bot/suite/sub1/sub2/sub3/sub4/sub5': ['sub5']
},
'is_selected': True
}
# If the request is valid, a valid response will be returned.
response = self.testapp.post(
'/graph_json', {'graphs': json.dumps(graphs)})
flot_json_str = response.body
self.CheckFlotJson(flot_json_str, 150, 1, 15850, 16000, step=1)
def testPost_LongTestPathWithUnSelected(self):
self._AddLongTestColumns(start_rev=15700, end_rev=16000, step=1)
graphs = {
'test_path_dict': {
'master/bot/suite/sub1/sub2/sub3/sub4': ['sub4']
}
}
# If the request is valid, a valid response will be returned.
response = self.testapp.post(
'/graph_json', {'graphs': json.dumps(graphs)})
flot_json_str = response.body
self.CheckFlotJson(flot_json_str, 150, 1, 15850, 16000, step=1)
def testPost_LongTestPathWithUnSelectedAndNoSubTest_NoGraphData(self):
self._AddLongTestColumns(start_rev=15700, end_rev=16000, step=1)
graphs = {
'test_path_dict': {
'master/bot/suite/sub1/sub2/sub3/sub4/sub5': ['sub5']
},
}
# If the request is valid, a valid response will be returned.
response = self.testapp.post(
'/graph_json', {'graphs': json.dumps(graphs)})
flot_json_str = response.body
flot = json.loads(flot_json_str)
self.assertEqual(0, len(flot['data']))
def testRequest_NoSubTest_ShowsSummaryTests(self):
"""Tests the post method of the request handler."""
self._AddTestColumns(start_rev=15700, end_rev=16000, step=1)
graphs = {
'test_path_dict': {
'ChromiumGPU/winXP/dromaeo': [],
}
}
# If the request is valid, a valid response will be returned.
response = self.testapp.post(
'/graph_json', {'graphs': json.dumps(graphs)})
flot_json_str = response.body
self.CheckFlotJson(flot_json_str, 150, 2, 15850, 16000, step=1)
def testGetGraphJsonNoArgs(self):
self._AddTestColumns(start_rev=16047)
flot_json_str = graph_json.GetGraphJson(
{'ChromiumGPU/win7/dromaeo/dom': []})
self.CheckFlotJson(flot_json_str, 150, 1, 16050, 16500)
def testGetGraphJsonRevisionStart(self):
self._AddTestColumns(end_rev=15500)
flot_json_str = graph_json.GetGraphJson(
{'ChromiumGPU/win7/dromaeo/dom': []}, rev=15000)
self.CheckFlotJson(flot_json_str, 76, 1, 15000, 15228)
def testGetGraphJsonRevisionMiddle(self):
self._AddTestColumns(end_rev=15600)
flot_json_str = graph_json.GetGraphJson(
{'ChromiumGPU/win7/dromaeo/dom': []}, rev=15300)
self.CheckFlotJson(flot_json_str, 151, 1, 15075, 15525)
def testGetGraphJsonNumPoints(self):
self._AddTestColumns(end_rev=15500)
flot_json_str = graph_json.GetGraphJson(
{'ChromiumGPU/win7/dromaeo/dom': []}, rev=15300, num_points=8)
self.CheckFlotJson(flot_json_str, 9, 1, 15288, 15315)
def testGetGraphJsonStartEndRev(self):
self._AddTestColumns(start_rev=15991)
flot_json_str = graph_json.GetGraphJson(
{'ChromiumGPU/win7/dromaeo/dom': []}, start_rev=16000,
end_rev=16030)
self.CheckFlotJson(flot_json_str, 11, 1, 16000, 16030)
def testGetGraphJsonMultipleBots(self):
self._AddTestColumns(start_rev=16047)
flot_json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/dom': [],
'ChromiumGPU/winXP/dromaeo/dom': [],
})
self.CheckFlotJson(flot_json_str, 150, 2, 16050, 16500)
def testGetGraphJsonMultipleTests(self):
self._AddTestColumns(start_rev=16047)
flot_json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/dom': [],
'ChromiumGPU/win7/dromaeo/jslib': [],
})
self.CheckFlotJson(flot_json_str, 150, 2, 16050, 16500)
def testGetGraphJsonError(self):
self._AddTestColumns(start_rev=15000, end_rev=15015)
rows = graph_data.Row.query(
graph_data.Row.parent_test == ndb.Key(
'Master', 'ChromiumGPU', 'Bot', 'win7',
'Test', 'dromaeo', 'Test', 'dom')).fetch()
for row in rows:
row.error = 1 + ((row.revision - 15000) * 0.25)
ndb.put_multi(rows)
flot_json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/dom': [],
})
flot = json.loads(flot_json_str)
self.assertEqual(1, len(flot['error_bars'].keys()))
rev = 0
for col_dom, col_top, col_bottom in zip(
flot['data']['0']['data'],
flot['error_bars']['0'][1]['data'],
flot['error_bars']['0'][0]['data']):
error = 1 + (rev * 0.25)
self.assertEqual(rev + 15000, col_top[0])
self.assertEqual(col_dom[1] + error, col_top[1])
self.assertEqual(rev + 15000, col_bottom[0])
self.assertEqual(col_dom[1] - error, col_bottom[1])
rev += 3
def testGetGraphJsonSkewedRevisions(self):
self._AddTestColumns(end_rev=15500)
json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/dom': [],
'ChromiumGPU/mac/dromaeo/dom': [],
},
rev=15000, num_points=8)
flot = json.loads(json_str)
data = flot.get('data')
win7_index = self._GetSeriesIndex(flot, 'ChromiumGPU/win7/dromaeo/dom')
mac_index = self._GetSeriesIndex(flot, 'ChromiumGPU/mac/dromaeo/dom')
if not data:
self.fail('No flot data generated by GetGraphJson')
self.assertEqual(2, len(data))
self.assertEqual(
[[15000, 30000.0], [15003, 30006.0], [15006, 30012.0]],
data[win7_index].get('data'))
self.assertEqual(
[[15001, 30000.0], [15004, 30006.0]],
data[mac_index].get('data'))
def testGetGraphJson_ClampsRevisions(self):
self._AddTestColumns(end_rev=15500)
# No revision specified, clamps to the last 9 rows.
json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/dom': [],
'ChromiumGPU/mac/dromaeo/dom': [],
},
num_points=8)
flot = json.loads(json_str)
data = flot.get('data')
win7_index = self._GetSeriesIndex(flot, 'ChromiumGPU/win7/dromaeo/dom')
mac_index = self._GetSeriesIndex(flot, 'ChromiumGPU/mac/dromaeo/dom')
# Two columns
self.assertEqual(2, len(data))
# Clamped from 15487-15499 by 3 steps. First row doesn't contain 15487.
self.assertEqual(
[
[15489, 30978.0],
[15492, 30984.0],
[15495, 30990.0],
[15498, 30996.0]
],
data[win7_index].get('data'))
self.assertEqual(
[
[15487, 30972.0],
[15490, 30978.0],
[15493, 30984.0],
[15496, 30990.0],
[15499, 30996.0]
],
data[mac_index].get('data'))
# Revision 100 (way before data starts) specified, clamp to the first 8 rows
json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/dom': [],
'ChromiumGPU/mac/dromaeo/dom': [],
},
rev=100, num_points=8)
flot = json.loads(json_str)
data = flot.get('data')
win7_index = self._GetSeriesIndex(flot, 'ChromiumGPU/win7/dromaeo/dom')
mac_index = self._GetSeriesIndex(flot, 'ChromiumGPU/mac/dromaeo/dom')
# Two columns
self.assertEqual(2, len(data))
# 15000-15012.
self.assertEqual(
[
[15000, 30000.0],
[15003, 30006.0],
[15006, 30012.0],
[15009, 30018.0]
],
data[win7_index].get('data'))
self.assertEqual(
[
[15001, 30000.0],
[15004, 30006.0],
[15007, 30012.0],
[15010, 30018.0]
],
data[mac_index].get('data'))
# Revision 15530 (valid) specified, clamp 4 rows before/after
json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/dom': [],
'ChromiumGPU/mac/dromaeo/dom': [],
},
rev=15030, num_points=8)
flot = json.loads(json_str)
data = flot.get('data')
win7_index = self._GetSeriesIndex(flot, 'ChromiumGPU/win7/dromaeo/dom')
mac_index = self._GetSeriesIndex(flot, 'ChromiumGPU/mac/dromaeo/dom')
# Two columns
self.assertEqual(2, len(data))
# 15524-15536.
self.assertEqual(
[
[15024, 30048.0],
[15027, 30054.0],
[15030, 30060.0],
[15033, 30066.0],
[15036, 30072.0]
],
data[win7_index].get('data'))
self.assertEqual(
[
[15025, 30048.0],
[15028, 30054.0],
[15031, 30060.0],
[15034, 30066.0]
],
data[mac_index].get('data'))
# Revision 15498 specified, clamp 4 rows before and after is cut off
json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/dom': [],
'ChromiumGPU/mac/dromaeo/dom': [],
},
rev=15498, num_points=7)
flot = json.loads(json_str)
data = flot.get('data')
win7_index = self._GetSeriesIndex(flot, 'ChromiumGPU/win7/dromaeo/dom')
mac_index = self._GetSeriesIndex(flot, 'ChromiumGPU/mac/dromaeo/dom')
# Two columns
self.assertEqual(2, len(data))
# 15493-15499.
self.assertEqual(
[[15495, 30990.0], [15498, 30996.0]],
data[win7_index].get('data'))
self.assertEqual(
[[15493, 30984.0], [15496, 30990.0], [15499, 30996.0]],
data[mac_index].get('data'))
# Revision 15001 specified, before is cut off and clamp 4 rows after
json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/dom': [],
'ChromiumGPU/mac/dromaeo/dom': [],
},
rev=15001, num_points=8)
flot = json.loads(json_str)
data = flot.get('data')
win7_index = self._GetSeriesIndex(flot, 'ChromiumGPU/win7/dromaeo/dom')
mac_index = self._GetSeriesIndex(flot, 'ChromiumGPU/mac/dromaeo/dom')
# Two columns
self.assertEqual(2, len(data))
# 15493-15499.
self.assertEqual(
[[15000, 30000.0], [15003, 30006.0], [15006, 30012.0]],
data[win7_index].get('data'))
self.assertEqual(
[[15001, 30000.0], [15004, 30006.0], [15007, 30012.0]],
data[mac_index].get('data'))
def testGetGraphJson_GraphJsonAnnotations(self):
self._AddTestColumns(end_rev=15500)
flot_json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/dom': [],
},
rev=15000, num_points=8)
flot = json.loads(flot_json_str)
annotations = flot['annotations']
self.assertEqual(5, len(flot['data']['0']['data']))
for i, _ in enumerate(flot['data']['0']['data']):
rev = flot['data']['0']['data'][i][0]
self.assertEqual(int(int(rev) * 0.25),
annotations['0'][str(i)]['r_webkit'])
def testGetGraphJson_WithAnomalies_ReturnsCorrectAnomalyAnnotations(self):
self._AddTestColumns()
anomaly1 = anomaly.Anomaly(
start_revision=14999, end_revision=15000,
test=utils.TestKey('ChromiumGPU/win7/dromaeo/dom'),
median_before_anomaly=100,
median_after_anomaly=200)
anomaly1.SetIsImprovement()
key1 = anomaly1.put()
anomaly2 = anomaly.Anomaly(
start_revision=15004, end_revision=15006,
test=utils.TestKey('ChromiumGPU/win7/dromaeo/dom'),
median_before_anomaly=200,
median_after_anomaly=100,
bug_id=12345)
anomaly2.SetIsImprovement()
key2 = anomaly2.put()
test = utils.TestKey('ChromiumGPU/win7/dromaeo/dom').get()
test.description = 'About this test'
test.units = 'ms'
test.buildername = 'Windows 7 (1)'
test.put()
flot_json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/dom': [],
},
rev=15000, num_points=8)
flot = json.loads(flot_json_str)
annotations = flot['annotations']
self.assertEqual(5, len(annotations['0']))
# Verify key fields of the annotation dictionary for the first anomaly.
anomaly_one_annotation = annotations['0']['0']['g_anomaly']
self.assertEqual(14999, anomaly_one_annotation['start_revision'])
self.assertEqual(15000, anomaly_one_annotation['end_revision'])
self.assertEqual('100.0%', anomaly_one_annotation['percent_changed'])
self.assertIsNone(anomaly_one_annotation['bug_id'])
self.assertEqual(key1.urlsafe(), anomaly_one_annotation['key'])
self.assertTrue(anomaly_one_annotation['improvement'])
# Verify key fields of the annotation dictionary for th second anomaly.
anomaly_two_annotation = annotations['0']['2']['g_anomaly']
self.assertEqual(15004, anomaly_two_annotation['start_revision'])
self.assertEqual(15006, anomaly_two_annotation['end_revision'])
self.assertEqual('50.0%', anomaly_two_annotation['percent_changed'])
self.assertEqual(12345, anomaly_two_annotation['bug_id'])
self.assertEqual(key2.urlsafe(), anomaly_two_annotation['key'])
self.assertFalse(anomaly_two_annotation['improvement'])
# Verify the tracing link annotations
self.assertEqual('http://trace/15000',
annotations['0']['0']['a_tracing_uri'])
self.assertEqual('http://trace/15012',
annotations['0']['4']['a_tracing_uri'])
# Verify the tracing rerun options
self.assertEqual({'foo': '--foo'},
annotations['0']['0']['a_trace_rerun_options'])
# Verify the series annotations.
self.assertEqual({
'0': {
'name': 'dom',
'path': 'ChromiumGPU/win7/dromaeo/dom',
'units': 'ms',
'better': 'Higher',
'description': 'About this test'
}
}, annotations['series'])
def testGetGraphJson_SomeDataDeprecated_OmitsDeprecatedData(self):
self._AddTestColumns(start_rev=15000, end_rev=15050)
dom = utils.TestKey('ChromiumGPU/win7/dromaeo/dom').get()
dom.deprecated = True
dom.put()
jslib = utils.TestKey('ChromiumGPU/win7/dromaeo/jslib').get()
jslib.deprecated = True
jslib.put()
flot_json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/dom': [],
'ChromiumGPU/win7/dromaeo/jslib': [],
'ChromiumGPU/mac/dromaeo/dom': [],
'ChromiumGPU/mac/dromaeo/jslib': [],
},
rev=15000, num_points=8)
flot = json.loads(flot_json_str)
# The win7 tests are deprecated and the mac tests are not. So only the mac
# tests should be returned.
self.assertEqual(2, len(flot['data']))
self.assertEqual(2, len(flot['annotations']['series']))
self.assertIsNotNone(
self._GetSeriesIndex(flot, 'ChromiumGPU/mac/dromaeo/dom'))
self.assertIsNotNone(
self._GetSeriesIndex(flot, 'ChromiumGPU/mac/dromaeo/jslib'))
def testGetGraphJson_WithSelectedTrace(self):
self._AddTestColumns(start_rev=15000, end_rev=15050)
rows = graph_data.Row.query(
graph_data.Row.parent_test == utils.TestKey(
'ChromiumGPU/win7/dromaeo/jslib')).fetch()
for row in rows:
row.error = 1 + ((row.revision - 15000) * 0.25)
ndb.put_multi(rows)
flot_json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/jslib': ['jslib'],
},
rev=15000, num_points=8, is_selected=True)
flot = json.loads(flot_json_str)
self.assertEqual(1, len(flot['data']))
self.assertEqual(5, len(flot['data']['0']['data']))
self.assertEqual(1, len(flot['annotations']['series']))
self.assertEqual(5, len(flot['annotations'].get('0').keys()))
self.assertEqual(5, len(flot['error_bars']['0'][0]['data']))
self.assertEqual(5, len(flot['error_bars']['0'][1]['data']))
def testGetGraphJson_UnSelectedTrace(self):
self._AddTestColumns(start_rev=15000, end_rev=15050)
test_key = ndb.Key(
'Master', 'ChromiumGPU', 'Bot', 'win7',
'Test', 'dromaeo', 'Test', 'jslib')
rows = graph_data.Row.query(graph_data.Row.parent_test == test_key).fetch()
for row in rows:
row.error = 1 + ((row.revision - 15000) * 0.25)
ndb.put_multi(rows)
# Insert sub tests to jslib.
rows = []
start_rev = 15000
end_rev = 15050
for name in ['sub_test_a', 'sub_test_b']:
sub_test = graph_data.Test(id=name, parent=test_key,
improvement_direction=anomaly.UP,
has_rows=True).put()
sub_test_container_key = utils.GetTestContainerKey(sub_test)
for i in range(start_rev, end_rev, 3):
# Add Rows for one bot with revision numbers that aren't lined up
# with the other bots.
row = graph_data.Row(
parent=sub_test_container_key, id=i, value=float(i * 2),
r_webkit=int(i * 0.25), a_str='some_string',
buildnumber=i - start_rev,
a_tracing_uri='http://trace/%d' % i,
a_trace_rerun_options={'foo': '--foo'})
rows.append(row)
ndb.put_multi(rows)
flot_json_str = graph_json.GetGraphJson(
{
'ChromiumGPU/win7/dromaeo/jslib': ['jslib'],
},
rev=15000, num_points=8, is_selected=False)
flot = json.loads(flot_json_str)
sub_test_a_index = self._GetSeriesIndex(
flot, 'ChromiumGPU/win7/dromaeo/jslib/sub_test_a')
sub_test_b_index = self._GetSeriesIndex(
flot, 'ChromiumGPU/win7/dromaeo/jslib/sub_test_b')
self.assertEqual(2, len(flot['data']))
self.assertEqual(5, len(flot['data'][sub_test_a_index]['data']))
self.assertEqual(2, len(flot['annotations']['series']))
self.assertEqual(5, len(flot['annotations'].get(sub_test_a_index).keys()))
self.assertEqual(5, len(flot['annotations'].get(sub_test_b_index).keys()))
def testGetGraphJson_ManyUnselected_ReturnsNothing(self):
testing_common.AddTests(
['M'], ['b'], {'suite': {str(i): {} for i in range(100)}})
test_paths = ['M/b/suite/%s' % i for i in range(100)]
for p in test_paths:
testing_common.AddRows(p, [1])
response = graph_json.GetGraphJson(
test_path_dict={p: [] for p in test_paths}, is_selected=False)
self.assertEqual(
{'data': {}, 'annotations': {}, 'error_bars': {}},
json.loads(response))
class GraphJsonParseRequestArgumentsTest(testing_common.TestCase):
def _HandlerWithMockRequestParams(self, **params):
"""Returns a GraphJsonHandler object with canned request parameters."""
request_params = {
'test_path_dict': {
'Master/b1/scrolling/frame_times/about.com': [],
'Master/b2/scrolling/frame_times/about.com': [],
'Master/linux/dromaeo.domcoremodify/dom': [],
}
}
request_params.update(params)
handler = graph_json.GraphJsonHandler()
handler.request = mock.MagicMock()
handler.request.get = mock.MagicMock(
return_value=json.dumps(request_params))
return handler
def testParseRequestArguments(self):
# The numerical arguments get converted to integers, and the
# unspecified arguments get set to None.
handler = self._HandlerWithMockRequestParams(rev='12345', num_points='123')
expected = {
'test_path_dict': {
'Master/b1/scrolling/frame_times/about.com': [],
'Master/b2/scrolling/frame_times/about.com': [],
'Master/linux/dromaeo.domcoremodify/dom': [],
},
'rev': 12345,
'num_points': 123,
'start_rev': None,
'end_rev': None,
'is_selected': None,
}
self.assertEqual(expected, handler._ParseRequestArguments())
def testParseRequestArguments_OnlyTestPathDictSpecified(self):
# No revision or number of points is specified, so they're set to None.
handler = self._HandlerWithMockRequestParams()
expected = {
'test_path_dict': {
'Master/b1/scrolling/frame_times/about.com': [],
'Master/b2/scrolling/frame_times/about.com': [],
'Master/linux/dromaeo.domcoremodify/dom': [],
},
'rev': None,
'num_points': graph_json._DEFAULT_NUM_POINTS,
'start_rev': None,
'end_rev': None,
'is_selected': None,
}
self.assertEqual(expected, handler._ParseRequestArguments())
def testParseRequestArguments_NegativeRevision(self):
# Negative revision is invalid; it's the same as no revision.
handler = self._HandlerWithMockRequestParams(rev='-1')
expected = {
'test_path_dict': {
'Master/b1/scrolling/frame_times/about.com': [],
'Master/b2/scrolling/frame_times/about.com': [],
'Master/linux/dromaeo.domcoremodify/dom': [],
},
'rev': None,
'num_points': graph_json._DEFAULT_NUM_POINTS,
'start_rev': None,
'end_rev': None,
'is_selected': None,
}
self.assertEqual(expected, handler._ParseRequestArguments())
class GraphJsonHelperFunctionTest(testing_common.TestCase):
def testPointInfoDict_StdioUriMarkdown(self):
testing_common.AddTests(['Master'], ['b'], {'my_suite': {}})
test = utils.TestKey('Master/b/my_suite').get()
test.buildername = 'MyBuilder'
test_container_key = utils.GetTestContainerKey(test)
row = graph_data.Row(id=345, buildnumber=456, parent=test_container_key)
row.a_stdio_uri = ('[Build stdio](http://build.chromium.org/p/my.master.id/'
'builders/MyBuilder/builds/456/steps/my_suite/logs/'
'stdio)')
point_info = graph_json._PointInfoDict(row, {})
self.assertEqual(row.a_stdio_uri, point_info['a_stdio_uri'])
def testPointInfoDict_RowHasNoTracingUri_ResultHasNoTracingUri(self):
testing_common.AddTests(['Master'], ['b'], {'my_suite': {}})
rows = testing_common.AddRows('Master/b/my_suite', [345])
# This row has no a_tracing_uri property, so there should be no
# trace annotation returned by _PointInfoDict.
point_info = graph_json._PointInfoDict(rows[0], {})
self.assertFalse(hasattr(rows[0], 'a_tracing_uri'))
self.assertNotIn('a_tracing_uri', point_info)
if __name__ == '__main__':
unittest.main()