Changeset 109057 in webkit
- Timestamp:
- Feb 27, 2012 6:14:37 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 1 deleted
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/ChangeLog
r109039 r109057 1 2012-02-27 Ryosuke Niwa <rniwa@webkit.org> 2 3 Extract the logic to merge tests from MergeTestsHandler and add unit tests 4 https://bugs.webkit.org/show_bug.cgi?id=79602 5 6 Reviewed by Hajime Morita. 7 8 Extracted Test.merge and TestResult.replace_to_change_test_name out of MergeTestsHandler, 9 and moved MergeTestsHandler into admin_handlers.py where it belongs. 10 11 Added new backend "model-manipulator" to execute tasks to merge tests. 12 13 Also revive the inadvertently removed manual submission form on the admin page. 14 15 * Websites/webkit-perf.appspot.com/admin_handlers.py: 16 (AdminDashboardHandler.get_tests): 17 (MergeTestsHandler): 18 (MergeTestsHandler.post): 19 * Websites/webkit-perf.appspot.com/app.yaml: 20 * Websites/webkit-perf.appspot.com/backends.yaml: Added. 21 * Websites/webkit-perf.appspot.com/css/admin.css: 22 * Websites/webkit-perf.appspot.com/js/admin.js: 23 * Websites/webkit-perf.appspot.com/main.py: 24 * Websites/webkit-perf.appspot.com/merge_tests_handler.py: Removed. 25 * Websites/webkit-perf.appspot.com/models.py: 26 (Test): 27 (Test.merge): 28 (TestResult.replace_to_change_test_name): 29 * Websites/webkit-perf.appspot.com/models_unittest.py: 30 (DataStoreTestsBase.assertOnlyInstance): 31 (DataStoreTestsBase): 32 (DataStoreTestsBase.assertOnlyInstances): 33 (DataStoreTestsBase.assertEqualUnorderedModelList): 34 (DataStoreTestsBase.assertEqualUnorderedList): 35 (_create_build): 36 (TestModelTests.test_merge): 37 (TestResultTests): 38 (TestResultTests.test_get_or_insert_value): 39 (TestResultTests.test_get_or_insert_stat_value): 40 (TestResultTests.test_replace_to_change_test_name): 41 (TestResultTests.test_replace_to_change_test_name_with_stat_value): 42 (TestResultTests.test_replace_to_change_test_name_overrides_conflicting_result): 43 1 44 2012-02-27 ChangSeok Oh <shivamidow@gmail.com> 2 45 -
trunk/Websites/webkit-perf.appspot.com/admin_handlers.py
r108917 r109057 31 31 import json 32 32 33 from google.appengine.api import taskqueue 33 34 from google.appengine.api import users 34 35 from google.appengine.ext.db import GqlQuery 35 36 from google.appengine.ext.webapp import template 36 37 38 from controller import schedule_runs_update 39 from controller import schedule_dashboard_update 40 from controller import schedule_manifest_update 37 41 from models import Branch 38 42 from models import Builder … … 82 86 self.response.headers['Content-Type'] = 'application/json' 83 87 self.response.out.write(json.dumps([test.name for test in Test.all().fetch(limit=200)])) 88 89 90 class MergeTestsHandler(webapp2.RequestHandler): 91 def post(self, task): 92 self.response.headers['Content-Type'] = 'text/plain; charset=utf-8' 93 94 if task != 'run': 95 try: 96 payload = json.loads(self.request.body) 97 merge = payload.get('merge', '') 98 into = payload.get('into', '') 99 except: 100 self.response.out.write("Failed to parse the payload: %s" % self.request.body) 101 return 102 103 if merge == into or not Test.get_by_key_name(merge) or not Test.get_by_key_name(into): 104 self.response.out.write('Invalid test names') 105 return 106 107 taskqueue.add(url='/admin/merge-tests/run', params={'merge': merge, 'into': into}, target='model-manipulator') 108 self.response.out.write('OK') 109 return 110 111 merge = Test.get_by_key_name(self.request.get('merge')) 112 into = Test.get_by_key_name(self.request.get('into')) 113 114 branches_and_platforms_to_update = into.merge(merge) 115 if branches_and_platforms_to_update == None: 116 # FIXME: This message is invisible. Need to store this somewhere and let the admin page pull it. 117 self.response.out.write('Cannot merge %s into %s. There are conflicting results.' % (merge.name, into.name)) 118 return 119 120 for branch_id, platform_id in branches_and_platforms_to_update: 121 schedule_runs_update(into.id, branch_id, platform_id) 122 123 schedule_dashboard_update() 124 schedule_manifest_update() 125 126 self.response.out.write('OK') -
trunk/Websites/webkit-perf.appspot.com/app.yaml
r108845 r109057 1 1 application: webkit-perf 2 version: 1 42 version: 15 3 3 runtime: python27 4 4 api_version: 1 … … 9 9 static_files: favicon.ico 10 10 upload: favicon\.ico 11 12 - url: /admin/(.+\.html)13 static_files: static/\114 upload: static15 secure: always16 login: admin17 11 18 12 - url: / -
trunk/Websites/webkit-perf.appspot.com/css/admin.css
r108921 r109057 5 5 } 6 6 7 #summary, #manual-submission { 8 font-size: 14px; 9 line-height: 36px; 10 } 11 7 12 #summary { 8 13 margin-top: 49px; 9 font-size: 14px;10 line-height: 36px;11 14 display: table; 12 15 border-collapse: collapse; … … 19 22 border-collapse: collapse; 20 23 min-height: 300px; 21 max-width: 400px;22 24 } 23 25 … … 83 85 } 84 86 87 #manual-submission form { 88 padding: 0; 89 } 90 #manual-submission textarea { 91 font-family: monospace; 92 font-size: 14px; 93 border: none; 94 } 95 85 96 #footer { 86 97 margin: 10px; -
trunk/Websites/webkit-perf.appspot.com/js/admin.js
r108917 r109057 60 60 event.preventDefault(); 61 61 62 var contents = {} 63 for (var i = 0; i < this.elements.length; i++) 64 contents[this.elements[i].name] = this.elements[i].value; 62 var payload; 63 if (this.payload) 64 payload = this.payload.value; 65 else { 66 var contents = {}; 67 for (var i = 0; i < this.elements.length; i++) 68 contents[this.elements[i].name] = this.elements[i].value; 69 payload = JSON.stringify(contents); 70 } 65 71 66 72 var xhr = new XMLHttpRequest; … … 72 78 else if (xhr.responseText != 'OK') 73 79 error(xhr.responseText); 74 75 80 } 76 81 xhr.open(this.method, this.action, true); 77 xhr.send( JSON.stringify(contents));82 xhr.send(payload); 78 83 79 84 $(this).trigger('reload'); 80 85 }); 86 87 $('#manual-submission textarea').val(JSON.stringify({ 88 'branch': 'webkit-trunk', 89 'platform': 'chromium-mac', 90 'builder-name': 'Chromium Mac Release (Perf)', 91 'build-number': '123', 92 'timestamp': parseInt(Date.now() / 1000), 93 'webkit-revision': 104856, 94 'chromium-revision': 123059, 95 'results': 96 { 97 'webkit_style_test': {'avg': 100, 'median': 102, 'stdev': 5, 'min': 90, 'max': 110}, 98 'some_test': 54, 99 }, 100 }, null, ' ')); -
trunk/Websites/webkit-perf.appspot.com/main.py
r108917 r109057 21 21 import json 22 22 23 from admin_handlers import AdminDashboardHandler 23 24 from admin_handlers import IsAdminHandler 24 from admin_handlers import AdminDashboardHandler25 from admin_handlers import MergeTestsHandler 25 26 from controller import CachedDashboardHandler 26 27 from controller import CachedManifestHandler … … 34 35 from report_process_handler import ReportProcessHandler 35 36 from report_logs_handler import ReportLogsHandler 36 from merge_tests_handler import MergeTestsHandler37 37 38 38 routes = [ 39 39 ('/admin/report/?', AdminReportHandler), 40 ( '/admin/merge-tests/?', MergeTestsHandler),40 (r'/admin/merge-tests(?:/(.*))?', MergeTestsHandler), 41 41 ('/admin/report-logs/?', ReportLogsHandler), 42 42 ('/admin/create/(.*)', CreateHandler), -
trunk/Websites/webkit-perf.appspot.com/models.py
r108399 r109057 143 143 id = db.IntegerProperty(required=True) 144 144 name = db.StringProperty(required=True) 145 # FIXME: Storing branches and platforms separately is flawed since a test maybe available on 146 # one platform but only on some branch and vice versa. 145 147 branches = db.ListProperty(db.Key) 146 148 platforms = db.ListProperty(db.Key) … … 171 173 return create_in_transaction_with_numeric_id_holder(execute) or existing_test[0] 172 174 175 def merge(self, other): 176 assert self.key() != other.key() 177 178 merged_results = TestResult.all() 179 merged_results.filter('name =', other.name) 180 181 # FIXME: We should be doing this check in a transaction but only ancestor queries are allowed 182 for result in merged_results: 183 if TestResult.get_by_key_name(TestResult.key_name(result.build, self.name)): 184 return None 185 186 branches_and_platforms_to_update = set() 187 for result in merged_results: 188 branches_and_platforms_to_update.add((result.build.branch.id, result.build.platform.id)) 189 result.replace_to_change_test_name(self.name) 190 191 delete_model_with_numeric_id_holder(other) 192 193 return branches_and_platforms_to_update 194 173 195 174 196 class TestResult(db.Model): … … 201 223 valueMedian=_float_or_none(result, 'median'), valueStdev=_float_or_none(result, 'stdev'), 202 224 valueMin=_float_or_none(result, 'min'), valueMax=_float_or_none(result, 'max')) 225 226 def replace_to_change_test_name(self, new_name): 227 clone = TestResult(key_name=TestResult.key_name(self.build, new_name), name=new_name, build=self.build, 228 value=self.value, valueMedian=self.valueMedian, valueStdev=self.valueMin, valueMin=self.valueMin, valueMax=self.valueMax) 229 clone.put() 230 self.delete() 231 return clone 203 232 204 233 -
trunk/Websites/webkit-perf.appspot.com/models_unittest.py
r108399 r109057 50 50 51 51 def assertOnlyInstance(self, only_instasnce): 52 self.assertEqual(len(only_instasnce.__class__.all().fetch(5)), 1) 53 self.assertTrue(only_instasnce.__class__.get(only_instasnce.key())) 52 self.assertOnlyInstances([only_instasnce]) 53 54 def assertOnlyInstances(self, expected_instances): 55 actual_instances = expected_instances[0].__class__.all().fetch(len(expected_instances) + 1) 56 self.assertEqualUnorderedModelList(actual_instances, expected_instances) 57 58 def assertEqualUnorderedModelList(self, list1, list2): 59 self.assertEqualUnorderedList([item.key() for item in list1], [item.key() for item in list1]) 54 60 55 61 def assertEqualUnorderedList(self, list1, list2): 56 62 self.assertEqual(set(list1), set(list2)) 63 self.assertEqual(len(list1), len(list2)) 57 64 58 65 … … 199 206 builder_key = models.Builder.create('some-builder', 'Some Builder') 200 207 return branch, platform, models.Builder.get(builder_key) 208 209 210 def _create_build(branch, platform, builder, key_name='some-build'): 211 build_key = models.Build(key_name=key_name, branch=branch, platform=platform, builder=builder, 212 buildNumber=1, revision=100, timestamp=datetime.now()).put() 213 return models.Build.get(build_key) 201 214 202 215 … … 255 268 self.assertEqualUnorderedList(test.platforms, [platform.key(), other_platform.key()]) 256 269 270 def test_merge(self): 271 branch, platform, builder = _create_some_builder() 272 some_build = _create_build(branch, platform, builder) 273 some_result = models.TestResult.get_or_insert_from_parsed_json('some-test', some_build, 50) 274 some_test = models.Test.update_or_insert('some-test', branch, platform) 275 276 other_build = _create_build(branch, platform, builder, 'other-build') 277 other_result = models.TestResult.get_or_insert_from_parsed_json('other-test', other_build, 30) 278 other_test = models.Test.update_or_insert('other-test', branch, platform) 279 280 self.assertOnlyInstances([some_result, other_result]) 281 self.assertNotEqual(some_result.key(), other_result.key()) 282 self.assertOnlyInstances([some_test, other_test]) 283 284 self.assertRaises(AssertionError, some_test.merge, (some_test)) 285 self.assertOnlyInstances([some_test, other_test]) 286 287 some_test.merge(other_test) 288 results_for_some_test = models.TestResult.all() 289 results_for_some_test.filter('name =', 'some-test') 290 results_for_some_test = results_for_some_test.fetch(5) 291 self.assertEqual(len(results_for_some_test), 2) 292 293 self.assertEqual(results_for_some_test[0].name, 'some-test') 294 self.assertEqual(results_for_some_test[1].name, 'some-test') 295 296 if results_for_some_test[0].value == 50: 297 self.assertEqual(results_for_some_test[1].value, 30) 298 else: 299 self.assertEqual(results_for_some_test[1].value, 50) 300 257 301 258 302 class TestResultTests(DataStoreTestsBase): 259 def _create_build(self):260 branch, platform, builder = _create_some_builder()261 build_key = models.Build(key_name='some-build', branch=branch, platform=platform, builder=builder,262 buildNumber=1, revision=100, timestamp=datetime.now()).put()263 return models.Build.get(build_key)264 265 303 def test_get_or_insert_value(self): 266 build = self._create_build() 304 branch, platform, builder = _create_some_builder() 305 build = _create_build(branch, platform, builder) 267 306 self.assertThereIsNoInstanceOf(models.TestResult) 268 307 result = models.TestResult.get_or_insert_from_parsed_json('some-test', build, 50) … … 277 316 278 317 def test_get_or_insert_stat_value(self): 279 build = self._create_build() 318 branch, platform, builder = _create_some_builder() 319 build = _create_build(branch, platform, builder) 280 320 self.assertThereIsNoInstanceOf(models.TestResult) 281 321 result = models.TestResult.get_or_insert_from_parsed_json('some-test', build, … … 290 330 self.assertEqual(result.valueMax, 45) 291 331 332 def test_replace_to_change_test_name(self): 333 branch, platform, builder = _create_some_builder() 334 build = _create_build(branch, platform, builder) 335 self.assertThereIsNoInstanceOf(models.TestResult) 336 result = models.TestResult.get_or_insert_from_parsed_json('some-test', build, 50) 337 self.assertOnlyInstance(result) 338 self.assertEqual(result.name, 'some-test') 339 340 new_result = result.replace_to_change_test_name('other-test') 341 self.assertNotEqual(result, new_result) 342 self.assertOnlyInstance(new_result) 343 344 self.assertEqual(new_result.name, 'other-test') 345 self.assertEqual(new_result.build.key(), result.build.key()) 346 self.assertEqual(new_result.value, result.value) 347 self.assertEqual(new_result.valueMedian, None) 348 self.assertEqual(new_result.valueStdev, None) 349 self.assertEqual(new_result.valueMin, None) 350 self.assertEqual(new_result.valueMax, None) 351 352 def test_replace_to_change_test_name_with_stat_value(self): 353 branch, platform, builder = _create_some_builder() 354 build = _create_build(branch, platform, builder) 355 self.assertThereIsNoInstanceOf(models.TestResult) 356 result = models.TestResult.get_or_insert_from_parsed_json('some-test', build, 357 {"avg": 40, "median": "40.1", "stdev": 3.25, "min": 30.5, "max": 45}) 358 self.assertOnlyInstance(result) 359 self.assertEqual(result.name, 'some-test') 360 361 new_result = result.replace_to_change_test_name('other-test') 362 self.assertNotEqual(result, new_result) 363 self.assertOnlyInstance(new_result) 364 365 self.assertEqual(new_result.name, 'other-test') 366 self.assertEqual(new_result.build.key(), result.build.key()) 367 self.assertEqual(new_result.value, result.value) 368 self.assertEqual(result.value, 40.0) 369 self.assertEqual(result.valueMedian, 40.1) 370 self.assertEqual(result.valueStdev, 3.25) 371 self.assertEqual(result.valueMin, 30.5) 372 self.assertEqual(result.valueMax, 45) 373 374 def test_replace_to_change_test_name_overrides_conflicting_result(self): 375 branch, platform, builder = _create_some_builder() 376 build = _create_build(branch, platform, builder) 377 self.assertThereIsNoInstanceOf(models.TestResult) 378 result = models.TestResult.get_or_insert_from_parsed_json('some-test', build, 20) 379 self.assertOnlyInstance(result) 380 381 conflicting_result = models.TestResult.get_or_insert_from_parsed_json('other-test', build, 10) 382 383 new_result = result.replace_to_change_test_name('other-test') 384 self.assertNotEqual(result, new_result) 385 self.assertOnlyInstance(new_result) 386 387 self.assertEqual(new_result.name, 'other-test') 388 self.assertEqual(models.TestResult.get(conflicting_result.key()).value, 20) 389 292 390 293 391 class ReportLogTests(DataStoreTestsBase):
Note: See TracChangeset
for help on using the changeset viewer.