2 # Copyright (C) 2012 Google Inc. All rights reserved.
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
14 # * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 from datetime import datetime
35 from datetime import timedelta
36 from google.appengine.api import memcache
37 from google.appengine.ext import testbed
38 from time import mktime
40 from models import NumericIdHolder
41 from models import Branch
42 from models import Platform
43 from models import Builder
44 from models import Build
45 from models import Test
46 from models import TestResult
47 from models import ReportLog
48 from models import PersistentCache
49 from models import Runs
50 from models import DashboardImage
51 from models import create_in_transaction_with_numeric_id_holder
52 from models import delete_model_with_numeric_id_holder
53 from models import model_from_numeric_id
56 class DataStoreTestsBase(unittest.TestCase):
58 self.testbed = testbed.Testbed()
59 self.testbed.activate()
60 self.testbed.init_datastore_v3_stub()
63 self.testbed.deactivate()
65 def assertThereIsNoInstanceOf(self, model):
66 self.assertEqual(len(model.all().fetch(5)), 0)
68 def assertOnlyInstance(self, only_instasnce):
69 self.assertOnlyInstances([only_instasnce])
71 def assertOnlyInstances(self, expected_instances):
72 actual_instances = expected_instances[0].__class__.all().fetch(len(expected_instances) + 1)
73 self.assertEqualUnorderedModelList(actual_instances, expected_instances)
75 def assertEqualUnorderedModelList(self, list1, list2):
76 self.assertEqualUnorderedList([item.key() for item in list1], [item.key() for item in list1])
78 def assertEqualUnorderedList(self, list1, list2):
79 self.assertEqual(set(list1), set(list2))
80 self.assertEqual(len(list1), len(list2))
83 class HelperTests(DataStoreTestsBase):
84 def _assert_there_is_exactly_one_id_holder_and_matches(self, id):
85 id_holders = NumericIdHolder.all().fetch(5)
86 self.assertEqual(len(id_holders), 1)
87 self.assertTrue(id_holders[0])
88 self.assertEqual(id_holders[0].key().id(), id)
90 def test_create_in_transaction_with_numeric_id_holder(self):
93 return Branch(id=id, name='some branch', key_name='some-branch').put()
95 self.assertThereIsNoInstanceOf(Branch)
96 self.assertThereIsNoInstanceOf(NumericIdHolder)
98 self.assertTrue(create_in_transaction_with_numeric_id_holder(execute))
100 branches = Branch.all().fetch(5)
101 self.assertEqual(len(branches), 1)
102 self.assertEqual(branches[0].name, 'some branch')
103 self.assertEqual(branches[0].key().name(), 'some-branch')
105 self._assert_there_is_exactly_one_id_holder_and_matches(branches[0].id)
107 def test_failing_in_create_in_transaction_with_numeric_id_holder(self):
112 self.assertThereIsNoInstanceOf(Branch)
113 self.assertThereIsNoInstanceOf(NumericIdHolder)
115 self.assertFalse(create_in_transaction_with_numeric_id_holder(execute))
117 self.assertThereIsNoInstanceOf(Branch)
118 self.assertThereIsNoInstanceOf(NumericIdHolder)
120 def test_raising_in_create_in_transaction_with_numeric_id_holder(self):
126 self.assertThereIsNoInstanceOf(Branch)
127 self.assertThereIsNoInstanceOf(NumericIdHolder)
129 self.assertRaises(TypeError, create_in_transaction_with_numeric_id_holder, (execute))
131 self.assertThereIsNoInstanceOf(Branch)
132 self.assertThereIsNoInstanceOf(NumericIdHolder)
134 def test_delete_model_with_numeric_id_holder(self):
137 return Branch(id=id, name='some branch', key_name='some-branch').put()
139 branch = Branch.get(create_in_transaction_with_numeric_id_holder(execute))
140 self.assertOnlyInstance(branch)
142 delete_model_with_numeric_id_holder(branch)
144 self.assertThereIsNoInstanceOf(Branch)
145 self.assertThereIsNoInstanceOf(NumericIdHolder)
147 def test_model_from_numeric_id(self):
150 return Branch(id=id, name='some branch', key_name='some-branch').put()
152 branch = Branch.get(create_in_transaction_with_numeric_id_holder(execute))
154 self.assertEqual(model_from_numeric_id(branch.id, Branch).key(), branch.key())
155 self.assertEqual(model_from_numeric_id(branch.id + 1, Branch), None)
156 delete_model_with_numeric_id_holder(branch)
157 self.assertEqual(model_from_numeric_id(branch.id, Branch), None)
160 class BranchTests(DataStoreTestsBase):
161 def test_create_if_possible(self):
162 self.assertThereIsNoInstanceOf(Branch)
164 branch = Branch.create_if_possible('some-branch', 'some branch')
165 self.assertTrue(branch)
166 self.assertTrue(branch.key().name(), 'some-branch')
167 self.assertTrue(branch.name, 'some branch')
168 self.assertOnlyInstance(branch)
170 self.assertFalse(Branch.create_if_possible('some-branch', 'some other branch'))
171 self.assertTrue(branch.name, 'some branch')
172 self.assertOnlyInstance(branch)
175 class PlatformTests(DataStoreTestsBase):
176 def test_create_if_possible(self):
177 self.assertThereIsNoInstanceOf(Platform)
179 platform = Platform.create_if_possible('some-platform', 'some platform')
180 self.assertTrue(platform)
181 self.assertTrue(platform.key().name(), 'some-platform')
182 self.assertTrue(platform.name, 'some platform')
183 self.assertOnlyInstance(platform)
185 self.assertFalse(Platform.create_if_possible('some-platform', 'some other platform'))
186 self.assertTrue(platform.name, 'some platform')
187 self.assertOnlyInstance(platform)
190 class BuilderTests(DataStoreTestsBase):
191 def test_create(self):
192 builder_key = Builder.create('some builder', 'some password')
193 self.assertTrue(builder_key)
194 builder = Builder.get(builder_key)
195 self.assertEqual(builder.key().name(), 'some builder')
196 self.assertEqual(builder.name, 'some builder')
197 self.assertEqual(builder.password, Builder._hashed_password('some password'))
199 def test_update_password(self):
200 builder = Builder.get(Builder.create('some builder', 'some password'))
201 self.assertEqual(builder.password, Builder._hashed_password('some password'))
202 builder.update_password('other password')
203 self.assertEqual(builder.password, Builder._hashed_password('other password'))
205 # Make sure it's saved
206 builder = Builder.get(builder.key())
207 self.assertEqual(builder.password, Builder._hashed_password('other password'))
209 def test_hashed_password(self):
210 self.assertNotEqual(Builder._hashed_password('some password'), 'some password')
211 self.assertFalse('some password' in Builder._hashed_password('some password'))
212 self.assertEqual(len(Builder._hashed_password('some password')), 64)
214 def test_authenticate(self):
215 builder = Builder.get(Builder.create('some builder', 'some password'))
216 self.assertTrue(builder.authenticate('some password'))
217 self.assertFalse(builder.authenticate('bad password'))
220 def _create_some_builder():
221 branch = Branch.create_if_possible('some-branch', 'Some Branch')
222 platform = Platform.create_if_possible('some-platform', 'Some Platform')
223 builder_key = Builder.create('some-builder', 'Some Builder')
224 return branch, platform, Builder.get(builder_key)
227 def _create_build(branch, platform, builder, key_name='some-build'):
228 build_key = Build(key_name=key_name, branch=branch, platform=platform, builder=builder,
229 buildNumber=1, revision=100, timestamp=datetime.now()).put()
230 return Build.get(build_key)
233 class BuildTests(DataStoreTestsBase):
234 def test_get_or_insert_from_log(self):
235 branch, platform, builder = _create_some_builder()
237 timestamp = datetime.now().replace(microsecond=0)
238 log = ReportLog(timestamp=timestamp, headers='some headers',
239 payload='{"branch": "some-branch", "platform": "some-platform", "builder-name": "some-builder",' +
240 '"build-number": 123, "webkit-revision": 456, "timestamp": %d}' % int(mktime(timestamp.timetuple())))
242 self.assertThereIsNoInstanceOf(Build)
244 build = Build.get_or_insert_from_log(log)
245 self.assertTrue(build)
246 self.assertEqual(build.branch.key(), branch.key())
247 self.assertEqual(build.platform.key(), platform.key())
248 self.assertEqual(build.builder.key(), builder.key())
249 self.assertEqual(build.buildNumber, 123)
250 self.assertEqual(build.revision, 456)
251 self.assertEqual(build.chromiumRevision, None)
252 self.assertEqual(build.timestamp, timestamp)
254 self.assertOnlyInstance(build)
257 class TestModelTests(DataStoreTestsBase):
258 def test_update_or_insert(self):
259 branch = Branch.create_if_possible('some-branch', 'Some Branch')
260 platform = Platform.create_if_possible('some-platform', 'Some Platform')
262 self.assertThereIsNoInstanceOf(Test)
264 test = Test.update_or_insert('some-test', branch, platform)
265 self.assertTrue(test)
266 self.assertEqual(test.branches, [branch.key()])
267 self.assertEqual(test.platforms, [platform.key()])
268 self.assertOnlyInstance(test)
270 def test_update_or_insert_to_update(self):
271 branch = Branch.create_if_possible('some-branch', 'Some Branch')
272 platform = Platform.create_if_possible('some-platform', 'Some Platform')
273 test = Test.update_or_insert('some-test', branch, platform)
274 self.assertOnlyInstance(test)
276 other_branch = Branch.create_if_possible('other-branch', 'Other Branch')
277 other_platform = Platform.create_if_possible('other-platform', 'Other Platform')
278 test = Test.update_or_insert('some-test', other_branch, other_platform)
279 self.assertOnlyInstance(test)
280 self.assertEqualUnorderedList(test.branches, [branch.key(), other_branch.key()])
281 self.assertEqualUnorderedList(test.platforms, [platform.key(), other_platform.key()])
283 test = Test.get(test.key())
284 self.assertEqualUnorderedList(test.branches, [branch.key(), other_branch.key()])
285 self.assertEqualUnorderedList(test.platforms, [platform.key(), other_platform.key()])
287 def test_merge(self):
288 branch, platform, builder = _create_some_builder()
289 some_build = _create_build(branch, platform, builder)
290 some_result = TestResult.get_or_insert_from_parsed_json('some-test', some_build, 50)
291 some_test = Test.update_or_insert('some-test', branch, platform)
293 other_build = _create_build(branch, platform, builder, 'other-build')
294 other_result = TestResult.get_or_insert_from_parsed_json('other-test', other_build, 30)
295 other_test = Test.update_or_insert('other-test', branch, platform)
297 self.assertOnlyInstances([some_result, other_result])
298 self.assertNotEqual(some_result.key(), other_result.key())
299 self.assertOnlyInstances([some_test, other_test])
301 self.assertRaises(AssertionError, some_test.merge, (some_test))
302 self.assertOnlyInstances([some_test, other_test])
304 some_test.merge(other_test)
305 results_for_some_test = TestResult.all()
306 results_for_some_test.filter('name =', 'some-test')
307 results_for_some_test = results_for_some_test.fetch(5)
308 self.assertEqual(len(results_for_some_test), 2)
310 self.assertEqual(results_for_some_test[0].name, 'some-test')
311 self.assertEqual(results_for_some_test[1].name, 'some-test')
313 if results_for_some_test[0].value == 50:
314 self.assertEqual(results_for_some_test[1].value, 30)
316 self.assertEqual(results_for_some_test[1].value, 50)
319 class TestResultTests(DataStoreTestsBase):
320 def test_get_or_insert_value(self):
321 branch, platform, builder = _create_some_builder()
322 build = _create_build(branch, platform, builder)
323 self.assertThereIsNoInstanceOf(TestResult)
324 result = TestResult.get_or_insert_from_parsed_json('some-test', build, 50)
325 self.assertOnlyInstance(result)
326 self.assertEqual(result.name, 'some-test')
327 self.assertEqual(result.build.key(), build.key())
328 self.assertEqual(result.value, 50.0)
329 self.assertEqual(result.valueMedian, None)
330 self.assertEqual(result.valueStdev, None)
331 self.assertEqual(result.valueMin, None)
332 self.assertEqual(result.valueMax, None)
334 def test_get_or_insert_stat_value(self):
335 branch, platform, builder = _create_some_builder()
336 build = _create_build(branch, platform, builder)
337 self.assertThereIsNoInstanceOf(TestResult)
338 result = TestResult.get_or_insert_from_parsed_json('some-test', build,
339 {"avg": 40, "median": "40.1", "stdev": 3.25, "min": 30.5, "max": 45})
340 self.assertOnlyInstance(result)
341 self.assertEqual(result.name, 'some-test')
342 self.assertEqual(result.build.key(), build.key())
343 self.assertEqual(result.value, 40.0)
344 self.assertEqual(result.valueMedian, 40.1)
345 self.assertEqual(result.valueStdev, 3.25)
346 self.assertEqual(result.valueMin, 30.5)
347 self.assertEqual(result.valueMax, 45)
349 def test_replace_to_change_test_name(self):
350 branch, platform, builder = _create_some_builder()
351 build = _create_build(branch, platform, builder)
352 self.assertThereIsNoInstanceOf(TestResult)
353 result = TestResult.get_or_insert_from_parsed_json('some-test', build, 50)
354 self.assertOnlyInstance(result)
355 self.assertEqual(result.name, 'some-test')
357 new_result = result.replace_to_change_test_name('other-test')
358 self.assertNotEqual(result, new_result)
359 self.assertOnlyInstance(new_result)
361 self.assertEqual(new_result.name, 'other-test')
362 self.assertEqual(new_result.build.key(), result.build.key())
363 self.assertEqual(new_result.value, result.value)
364 self.assertEqual(new_result.valueMedian, None)
365 self.assertEqual(new_result.valueStdev, None)
366 self.assertEqual(new_result.valueMin, None)
367 self.assertEqual(new_result.valueMax, None)
369 def test_replace_to_change_test_name_with_stat_value(self):
370 branch, platform, builder = _create_some_builder()
371 build = _create_build(branch, platform, builder)
372 self.assertThereIsNoInstanceOf(TestResult)
373 result = TestResult.get_or_insert_from_parsed_json('some-test', build,
374 {"avg": 40, "median": "40.1", "stdev": 3.25, "min": 30.5, "max": 45})
375 self.assertOnlyInstance(result)
376 self.assertEqual(result.name, 'some-test')
378 new_result = result.replace_to_change_test_name('other-test')
379 self.assertNotEqual(result, new_result)
380 self.assertOnlyInstance(new_result)
382 self.assertEqual(new_result.name, 'other-test')
383 self.assertEqual(new_result.build.key(), result.build.key())
384 self.assertEqual(new_result.value, result.value)
385 self.assertEqual(result.value, 40.0)
386 self.assertEqual(result.valueMedian, 40.1)
387 self.assertEqual(result.valueStdev, 3.25)
388 self.assertEqual(result.valueMin, 30.5)
389 self.assertEqual(result.valueMax, 45)
391 def test_replace_to_change_test_name_overrides_conflicting_result(self):
392 branch, platform, builder = _create_some_builder()
393 build = _create_build(branch, platform, builder)
394 self.assertThereIsNoInstanceOf(TestResult)
395 result = TestResult.get_or_insert_from_parsed_json('some-test', build, 20)
396 self.assertOnlyInstance(result)
398 conflicting_result = TestResult.get_or_insert_from_parsed_json('other-test', build, 10)
400 new_result = result.replace_to_change_test_name('other-test')
401 self.assertNotEqual(result, new_result)
402 self.assertOnlyInstance(new_result)
404 self.assertEqual(new_result.name, 'other-test')
405 self.assertEqual(TestResult.get(conflicting_result.key()).value, 20)
408 class ReportLogTests(DataStoreTestsBase):
409 def _create_log_with_payload(self, payload):
410 return ReportLog(timestamp=datetime.now(), headers='some headers', payload=payload)
412 def test_parsed_payload(self):
413 log = self._create_log_with_payload('')
414 self.assertFalse('_parsed' in log.__dict__)
415 self.assertEqual(log._parsed_payload(), False)
416 self.assertEqual(log._parsed, False)
418 log = self._create_log_with_payload('{"key": "value", "another key": 1}')
419 self.assertEqual(log._parsed_payload(), {"key": "value", "another key": 1})
420 self.assertEqual(log._parsed, {"key": "value", "another key": 1})
422 def test_get_value(self):
423 log = self._create_log_with_payload('{"string": "value", "integer": 1, "float": 1.1}')
424 self.assertEqual(log.get_value('string'), 'value')
425 self.assertEqual(log.get_value('integer'), 1)
426 self.assertEqual(log.get_value('float'), 1.1)
427 self.assertEqual(log.get_value('bad'), None)
429 def test_results(self):
430 log = self._create_log_with_payload('{"results": 123}')
431 self.assertEqual(log.results(), 123)
433 log = self._create_log_with_payload('{"key": "value"}')
434 self.assertEqual(log.results(), None)
436 def test_builder(self):
437 log = self._create_log_with_payload('{"key": "value"}')
438 self.assertEqual(log.builder(), None)
440 builder_name = "Chromium Mac Release (Perf)"
441 log = self._create_log_with_payload('{"builder-name": "%s"}' % builder_name)
442 self.assertEqual(log.builder(), None)
444 builder_key = Builder.create(builder_name, 'some password')
445 log = self._create_log_with_payload('{"builder-name": "%s"}' % builder_name)
446 self.assertEqual(log.builder().key(), builder_key)
448 def test_branch(self):
449 log = self._create_log_with_payload('{"key": "value"}')
450 self.assertEqual(log.branch(), None)
452 log = self._create_log_with_payload('{"branch": "some-branch"}')
453 self.assertEqual(log.branch(), None)
455 branch = Branch.create_if_possible("some-branch", "Some Branch")
456 log = self._create_log_with_payload('{"branch": "some-branch"}')
457 self.assertEqual(log.branch().key(), branch.key())
459 def test_platform(self):
460 log = self._create_log_with_payload('{"key": "value"}')
461 self.assertEqual(log.platform(), None)
463 log = self._create_log_with_payload('{"platform": "some-platform"}')
464 self.assertEqual(log.platform(), None)
466 platform = Platform.create_if_possible("some-platform", "Some Platform")
467 log = self._create_log_with_payload('{"platform": "some-platform"}')
468 self.assertEqual(log.platform().key(), platform.key())
470 def test_build_number(self):
471 log = self._create_log_with_payload('{"build-number": 123}')
472 self.assertEqual(log.build_number(), 123)
474 log = self._create_log_with_payload('{"key": "value"}')
475 self.assertEqual(log.build_number(), None)
477 def test_webkit_revision(self):
478 log = self._create_log_with_payload('{"key": "value"}')
479 self.assertEqual(log.webkit_revision(), None)
481 log = self._create_log_with_payload('{"webkit-revision": 123}')
482 self.assertEqual(log.webkit_revision(), 123)
484 def chromium_revision(self):
485 log = self._create_log_with_payload('{"chromium-revision": 123}')
486 self.assertEqual(log.webkit_revision(), 123)
488 log = self._create_log_with_payload('{"key": "value"}')
489 self.assertEqual(log.webkit_revision(), None)
492 class PersistentCacheTests(DataStoreTestsBase):
494 super(PersistentCacheTests, self).setUp()
495 self.testbed.init_memcache_stub()
497 def _assert_persistent_cache(self, name, value):
498 self.assertEqual(PersistentCache.get_by_key_name(name).value, value)
499 self.assertEqual(memcache.get(name), value)
501 def test_set_cache(self):
502 self.assertThereIsNoInstanceOf(PersistentCache)
504 PersistentCache.set_cache('some-cache', 'some data')
505 self._assert_persistent_cache('some-cache', 'some data')
507 PersistentCache.set_cache('some-cache', 'some other data')
509 self._assert_persistent_cache('some-cache', 'some other data')
511 def test_get_cache(self):
512 self.assertEqual(memcache.get('some-cache'), None)
513 self.assertEqual(PersistentCache.get_cache('some-cache'), None)
515 PersistentCache.set_cache('some-cache', 'some data')
517 self.assertEqual(memcache.get('some-cache'), 'some data')
518 self.assertEqual(PersistentCache.get_cache('some-cache'), 'some data')
520 memcache.delete('some-cache')
521 self.assertEqual(memcache.get('some-cache'), None)
522 self.assertEqual(PersistentCache.get_cache('some-cache'), 'some data')
525 class RunsTest(DataStoreTestsBase):
527 super(RunsTest, self).setUp()
528 self.testbed.init_memcache_stub()
530 def _create_results(self, branch, platform, builder, test_name, values, timestamps=None, starting_revision=100):
533 for i, value in enumerate(values):
534 build = Build(branch=branch, platform=platform, builder=builder,
535 buildNumber=i, revision=starting_revision + i, timestamp=timestamps[i] if timestamps else datetime.now())
537 result = TestResult(name=test_name, build=build, value=value)
540 results.append(result)
541 return builds, results
543 def test_generate_runs(self):
544 some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
545 some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
546 some_builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
547 some_test = Test.update_or_insert('some-test', some_branch, some_platform)
549 builds, results = self._create_results(some_branch, some_platform, some_builder, 'some-test', [50.0, 51.0, 52.0, 49.0, 48.0])
551 for i, (build, result) in enumerate(Runs._generate_runs(some_branch, some_platform, some_test)):
552 self.assertEqual(build.buildNumber, i)
553 self.assertEqual(build.revision, 100 + i)
554 self.assertEqual(result.name, 'some-test')
555 self.assertEqual(result.value, results[i].value)
557 self.assertTrue(last_i + 1, len(results))
559 def test_update_or_insert(self):
560 some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
561 some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
562 some_builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
563 some_test = Test.update_or_insert('some-test', some_branch, some_platform)
564 self.assertThereIsNoInstanceOf(Runs)
566 runs = Runs.update_or_insert(some_branch, some_platform, some_test)
567 self.assertOnlyInstance(runs)
568 self.assertEqual(runs.json_runs, '')
569 self.assertEqual(runs.json_averages, '')
570 self.assertEqual(runs.json_min, None)
571 self.assertEqual(runs.json_max, None)
572 old_memcache_value = memcache.get(Runs._key_name(some_branch.id, some_platform.id, some_test.id))
573 self.assertTrue(old_memcache_value)
576 self.assertThereIsNoInstanceOf(Runs)
578 builds, results = self._create_results(some_branch, some_platform, some_builder, 'some-test', [50.0])
579 runs = Runs.update_or_insert(some_branch, some_platform, some_test)
580 self.assertOnlyInstance(runs)
581 self.assertTrue(runs.json_runs.startswith('[5, [4, 0, 100, null],'))
582 self.assertEqual(json.loads('{' + runs.json_averages + '}'), {"100": 50.0})
583 self.assertEqual(runs.json_min, 50.0)
584 self.assertEqual(runs.json_max, 50.0)
585 self.assertNotEqual(memcache.get(Runs._key_name(some_branch.id, some_platform.id, some_test.id)), old_memcache_value)
587 def test_update_incrementally(self):
588 some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
589 some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
590 some_builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
591 some_test = Test.update_or_insert('some-test', some_branch, some_platform)
592 self.assertThereIsNoInstanceOf(Runs)
594 timestamps = [datetime.now(), datetime.now()]
595 builds, results = self._create_results(some_branch, some_platform, some_builder, 'some-test', [50.0, 52.0], timestamps)
596 runs = Runs.update_or_insert(some_branch, some_platform, some_test)
597 self.assertOnlyInstance(runs)
598 self.assertEqual(json.loads('[' + runs.json_runs + ']'),
599 [[5, [4, 0, 100, None], mktime(timestamps[0].timetuple()), 50.0, 0, [], None, None],
600 [7, [6, 1, 101, None], mktime(timestamps[1].timetuple()), 52.0, 0, [], None, None]])
601 self.assertEqual(json.loads('{' + runs.json_averages + '}'), {"100": 50.0, "101": 52.0})
602 self.assertEqual(runs.json_min, 50.0)
603 self.assertEqual(runs.json_max, 52.0)
605 timestamps.append(datetime.now())
606 builds, results = self._create_results(some_branch, some_platform, some_builder, 'some-test', [48.0],
607 timestamps[2:], starting_revision=102)
608 runs.update_incrementally(builds[0], results[0])
610 self.assertOnlyInstance(runs)
611 self.assertEqual(json.loads('[' + runs.json_runs + ']'),
612 [[5, [4, 0, 100, None], mktime(timestamps[0].timetuple()), 50.0, 0, [], None, None],
613 [7, [6, 1, 101, None], mktime(timestamps[1].timetuple()), 52.0, 0, [], None, None],
614 [9, [8, 0, 102, None], mktime(timestamps[2].timetuple()), 48.0, 0, [], None, None]])
615 self.assertEqual(json.loads('{' + runs.json_averages + '}'), {"100": 50.0, "101": 52.0, "102": 48.0})
616 self.assertEqual(runs.json_min, 48.0)
617 self.assertEqual(runs.json_max, 52.0)
619 def test_json_by_ids(self):
620 some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
621 some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
622 some_builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
623 some_test = Test.update_or_insert('some-test', some_branch, some_platform)
625 self._create_results(some_branch, some_platform, some_builder, 'some-test', [50.0])
626 runs = Runs.update_or_insert(some_branch, some_platform, some_test)
627 runs_json = runs.to_json()
629 key_name = Runs._key_name(some_branch.id, some_platform.id, some_test.id)
630 self.assertEqual(Runs.json_by_ids(some_branch.id, some_platform.id, some_test.id), runs_json)
631 self.assertEqual(memcache.get(key_name), runs_json)
633 memcache.set(key_name, 'blah')
634 self.assertEqual(Runs.json_by_ids(some_branch.id, some_platform.id, some_test.id), 'blah')
636 memcache.delete(key_name)
637 self.assertEqual(Runs.json_by_ids(some_branch.id, some_platform.id, some_test.id), runs_json)
638 self.assertEqual(memcache.get(key_name), runs_json)
640 def test_to_json_without_results(self):
641 some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
642 some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
643 some_test = Test.update_or_insert('some-test', some_branch, some_platform)
644 self.assertOnlyInstance(some_test)
645 self.assertThereIsNoInstanceOf(TestResult)
646 self.assertEqual(json.loads(Runs.update_or_insert(some_branch, some_platform, some_test).to_json()), {
654 def test_to_json_with_results(self):
655 some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
656 some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
657 some_builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
658 some_test = Test.update_or_insert('some-test', some_branch, some_platform)
659 builds, results = self._create_results(some_branch, some_platform, some_builder, 'some-test', [50.0, 51.0, 52.0, 49.0, 48.0])
661 value = json.loads(Runs.update_or_insert(some_branch, some_platform, some_test).to_json())
662 self.assertEqualUnorderedList(value.keys(), ['test_runs', 'averages', 'min', 'max', 'date_range', 'stat'])
663 self.assertEqual(value['stat'], 'ok')
664 self.assertEqual(value['min'], 48.0)
665 self.assertEqual(value['max'], 52.0)
666 self.assertEqual(value['date_range'], None) # date_range is never given
668 self.assertEqual(len(value['test_runs']), len(results))
669 for i, run in enumerate(value['test_runs']):
671 self.assertEqual(run[0], result.key().id())
672 self.assertEqual(run[1][1], i) # Build number
673 self.assertEqual(run[1][2], 100 + i) # Revision
674 self.assertEqual(run[1][3], None) # Supplementary revision
675 self.assertEqual(run[3], result.value)
676 self.assertEqual(run[6], some_builder.key().id())
677 self.assertEqual(run[7], None) # Statistics
679 def _assert_entry(self, entry, build, result, value, statistics=None, supplementary_revisions=None):
681 entry[2] = None # timestamp
682 self.assertEqual(entry, [result.key().id(), [build.key().id(), build.buildNumber, build.revision, supplementary_revisions],
684 value, 0, # runNumber
686 build.builder.key().id(), statistics])
688 def test_run_from_build_and_result(self):
689 branch = Branch.create_if_possible('some-branch', 'Some Branch')
690 platform = Platform.create_if_possible('some-platform', 'Some Platform')
691 builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
692 test_name = ' some-test'
694 def create_build(build_number, revision):
695 timestamp = datetime.now().replace(microsecond=0)
696 build = Build(branch=branch, platform=platform, builder=builder, buildNumber=build_number,
697 revision=revision, timestamp=timestamp)
701 build = create_build(1, 101)
702 result = TestResult(name=test_name, value=123.0, build=build)
704 self._assert_entry(Runs._entry_from_build_and_result(build, result), build, result, 123.0)
706 build = create_build(2, 102)
707 result = TestResult(name=test_name, value=456.0, valueMedian=789.0, build=build)
709 self._assert_entry(Runs._entry_from_build_and_result(build, result), build, result, 456.0)
711 result.valueStdev = 7.0
713 self._assert_entry(Runs._entry_from_build_and_result(build, result), build, result, 456.0)
715 result.valueStdev = None
716 result.valueMin = 123.0
717 result.valueMax = 789.0
719 self._assert_entry(Runs._entry_from_build_and_result(build, result), build, result, 456.0)
721 result.valueStdev = 8.0
722 result.valueMin = 123.0
723 result.valueMax = 789.0
725 self._assert_entry(Runs._entry_from_build_and_result(build, result), build, result, 456.0,
726 statistics={'stdev': 8.0, 'min': 123.0, 'max': 789.0})
728 result.valueMedian = 345.0 # Median is never used by the frontend.
729 result.valueStdev = 8.0
730 result.valueMin = 123.0
731 result.valueMax = 789.0
733 self._assert_entry(Runs._entry_from_build_and_result(build, result), build, result, 456.0,
734 statistics={'stdev': 8.0, 'min': 123.0, 'max': 789.0})
736 def test_chart_params_with_value(self):
737 some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
738 some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
739 some_builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
740 some_test = Test.update_or_insert('some-test', some_branch, some_platform)
742 start_time = datetime(2011, 2, 21, 12, 0, 0)
743 end_time = datetime(2011, 2, 28, 12, 0, 0)
744 results = self._create_results(some_branch, some_platform, some_builder, 'some-test',
745 [50.0, 51.0, 52.0, 49.0, 48.0, 51.9, 50.7, 51.1],
746 [start_time + timedelta(day) for day in range(0, 8)])
748 # Use int despite of its impreciseness since tests may fail due to rounding errors otherwise.
749 def split_as_int(string):
750 return [int(float(value)) for value in string.split(',')]
752 params = Runs.update_or_insert(some_branch, some_platform, some_test).chart_params(7, end_time)
753 self.assertEqual(params['chxl'], '0:|Feb 21|Feb 22|Feb 23|Feb 24|Feb 25|Feb 26|Feb 27|Feb 28')
754 self.assertEqual(split_as_int(params['chxr']), [1, 0, 57, int(52 * 1.1 / 5 + 0.5)])
755 x_min, x_max, y_min, y_max = split_as_int(params['chds'])
756 self.assertEqual(datetime.fromtimestamp(x_min), start_time)
757 self.assertEqual(datetime.fromtimestamp(x_max), end_time)
758 self.assertEqual(y_min, 0)
759 self.assertEqual(y_max, int(52 * 1.1))
760 self.assertEqual(split_as_int(params['chg']), [int(100 / 7), 20, 0, 0])
762 params = Runs.update_or_insert(some_branch, some_platform, some_test).chart_params(14, end_time)
763 self.assertEqual(params['chxl'], '0:|Feb 14|Feb 16|Feb 18|Feb 20|Feb 22|Feb 24|Feb 26|Feb 28')
764 self.assertEqual(split_as_int(params['chxr']), [1, 0, 57, int(52 * 1.1 / 5 + 0.5)])
765 x_min, x_max, y_min, y_max = split_as_int(params['chds'])
766 self.assertEqual(datetime.fromtimestamp(x_min), datetime(2011, 2, 14, 12, 0, 0))
767 self.assertEqual(datetime.fromtimestamp(x_max), end_time)
768 self.assertEqual(y_min, 0)
769 self.assertEqual(y_max, int(52 * 1.1))
770 self.assertEqual(split_as_int(params['chg']), [int(100 / 7), 20, 0, 0])
773 class DashboardImageTests(DataStoreTestsBase):
775 super(DashboardImageTests, self).setUp()
776 self.testbed.init_memcache_stub()
778 def test_create(self):
779 self.assertEqual(memcache.get('dashboard-image:1:2:3:7'), None)
780 self.assertThereIsNoInstanceOf(DashboardImage)
781 image = DashboardImage.create(1, 2, 3, 7, 'blah')
782 self.assertOnlyInstance(image)
783 self.assertEqual(memcache.get('dashboard-image:1:2:3:7'), 'blah')
786 image = DashboardImage.create(1, 2, 3, 7, 'blah')
787 self.assertEqual(memcache.get('dashboard-image:1:2:3:7'), 'blah')
788 memcache.set('dashboard-image:1:2:3:7', 'new value')
790 # Check twice to make sure the first call doesn't clear memcache
791 self.assertEqual(DashboardImage.get_image(1, 2, 3, 7), 'new value')
792 self.assertEqual(DashboardImage.get_image(1, 2, 3, 7), 'new value')
794 memcache.delete('dashboard-image:1:2:3:7')
795 self.assertEqual(memcache.get('dashboard-image:1:2:3:7'), None)
796 self.assertEqual(DashboardImage.get_image(1, 2, 3, 7), 'blah')
797 self.assertEqual(memcache.get('dashboard-image:1:2:3:7'), 'blah')
799 def test_needs_update(self):
800 self.assertTrue(DashboardImage.needs_update(1, 2, 3, 7))
801 self.assertTrue(DashboardImage.needs_update(1, 2, 3, 30))
802 self.assertTrue(DashboardImage.needs_update(1, 2, 3, 60))
803 self.assertTrue(DashboardImage.needs_update(1, 2, 3, 365))
805 image = DashboardImage(key_name=DashboardImage.key_name(1, 2, 3, 7), image='blah')
807 self.assertOnlyInstance(image)
808 self.assertTrue(DashboardImage.needs_update(1, 2, 3, 7))
810 DashboardImage(key_name=DashboardImage.key_name(1, 2, 3, 30), image='blah').put()
811 self.assertFalse(DashboardImage.needs_update(1, 2, 3, 30, datetime.now() + timedelta(0, 10)))
813 DashboardImage(key_name=DashboardImage.key_name(1, 2, 4, 30), image='blah').put()
814 self.assertTrue(DashboardImage.needs_update(1, 2, 4, 30, datetime.now() + timedelta(1)))
816 DashboardImage(key_name=DashboardImage.key_name(1, 2, 3, 90), image='blah').put()
817 self.assertFalse(DashboardImage.needs_update(1, 2, 3, 90, datetime.now() + timedelta(0, 20)))
819 DashboardImage(key_name=DashboardImage.key_name(1, 2, 4, 90), image='blah').put()
820 self.assertTrue(DashboardImage.needs_update(1, 2, 4, 90, datetime.now() + timedelta(1)))
822 DashboardImage(key_name=DashboardImage.key_name(1, 2, 3, 365), image='blah').put()
823 self.assertFalse(DashboardImage.needs_update(1, 2, 3, 365, datetime.now() + timedelta(1)))
825 DashboardImage(key_name=DashboardImage.key_name(1, 2, 4, 365), image='blah').put()
826 self.assertTrue(DashboardImage.needs_update(1, 2, 4, 365, datetime.now() + timedelta(10)))
829 if __name__ == '__main__':