aboutsummaryrefslogtreecommitdiffhomepage
path: root/gm
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2015-01-16 12:08:52 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-01-16 12:08:54 -0800
commit15b125d40122e966bd723d23e82c3224b1da4898 (patch)
tree8acf6fcd9bc9146680e8ca09047f5cbf210dc09e /gm
parentf7094c4ed01d500f31b993ed2620c2737093e383 (diff)
delete old things!
NOTREECHECKS=true Review URL: https://codereview.chromium.org/855003006
Diffstat (limited to 'gm')
-rw-r--r--gm/__init__.py1
-rwxr-xr-xgm/copy_config.py104
-rw-r--r--gm/display_json_results.py114
-rw-r--r--gm/gm_error.h163
-rw-r--r--gm/gm_expectations.cpp239
-rw-r--r--gm/gm_json.py193
-rw-r--r--gm/gmmain.cpp2549
-rw-r--r--gm/rebaseline_server/__init__.py1
-rwxr-xr-xgm/rebaseline_server/base_unittest.py41
-rw-r--r--gm/rebaseline_server/column.py70
-rwxr-xr-xgm/rebaseline_server/compare_configs.py209
-rwxr-xr-xgm/rebaseline_server/compare_configs_test.py60
-rwxr-xr-xgm/rebaseline_server/compare_rendered_pictures.py504
-rwxr-xr-xgm/rebaseline_server/compare_rendered_pictures_test.py227
-rwxr-xr-xgm/rebaseline_server/compare_to_expectations.py415
-rwxr-xr-xgm/rebaseline_server/compare_to_expectations_test.py58
-rwxr-xr-xgm/rebaseline_server/download_actuals.py289
-rwxr-xr-xgm/rebaseline_server/download_actuals_test.py52
-rw-r--r--gm/rebaseline_server/imagediffdb.py477
-rwxr-xr-xgm/rebaseline_server/imagediffdb_test.py101
-rw-r--r--gm/rebaseline_server/imagepair.py128
-rwxr-xr-xgm/rebaseline_server/imagepair_test.py214
-rw-r--r--gm/rebaseline_server/imagepairset.py234
-rwxr-xr-xgm/rebaseline_server/imagepairset_test.py210
-rwxr-xr-xgm/rebaseline_server/results.py343
-rwxr-xr-xgm/rebaseline_server/results_test.py81
-rwxr-xr-xgm/rebaseline_server/rs_fixpypath.py20
-rwxr-xr-xgm/rebaseline_server/server.py967
-rw-r--r--gm/rebaseline_server/static/.gitignore3
-rw-r--r--gm/rebaseline_server/static/constants.js100
-rw-r--r--gm/rebaseline_server/static/live-loader.js1024
-rw-r--r--gm/rebaseline_server/static/live-view.html446
-rw-r--r--gm/rebaseline_server/static/loader.js1035
-rw-r--r--gm/rebaseline_server/static/new/bower.json22
-rw-r--r--gm/rebaseline_server/static/new/css/app.css71
-rw-r--r--gm/rebaseline_server/static/new/js/app.js1130
-rw-r--r--gm/rebaseline_server/static/new/new-index.html37
-rw-r--r--gm/rebaseline_server/static/new/partials/index-view.html22
-rw-r--r--gm/rebaseline_server/static/new/partials/rebaseline-view.html207
-rw-r--r--gm/rebaseline_server/static/utils.js12
-rw-r--r--gm/rebaseline_server/static/view.css104
-rw-r--r--gm/rebaseline_server/static/view.html417
-rwxr-xr-xgm/rebaseline_server/test_all.py25
-rw-r--r--gm/rebaseline_server/testdata/.gitattributes2
-rw-r--r--gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/3x3bitmaprect/16998423976396106083.png1
-rw-r--r--gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png1
-rw-r--r--gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/aaclip/14456211900777561488.png1
-rw-r--r--gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/aaclip/6190901827590820995.png1
-rw-r--r--gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bigblurs/17309852422285247848.png1
-rw-r--r--gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bigblurs/2422083043229439955.png1
-rw-r--r--gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bitmapsource/16289727936158057543.png1
-rw-r--r--gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bitmapsource/17503582803589749280.png1
-rw-r--r--gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_192_192/3154864687054945306.png1
-rw-r--r--gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_192_192/4719210487426381700.png1
-rw-r--r--gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_32_2/15528304435129737588.png1
-rw-r--r--gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_32_2/712827739969462165.png1
-rw-r--r--gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/texdata/3695033638604474475.png1
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Android-GalaxyNexus-SGX540-Arm7-Release/actual-results.json97
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Builder-We-Have-No-Expectations-File-For/actual-results.json88
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/actual-results.json103
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release-Valgrind/actual-results.json1
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN/actual-results.json1
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-TSAN/actual-results.json1
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Win7-ShuttleA-HD2000-x86_64-Debug-Trybot/actual-results.json1
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Android-GalaxyNexus-SGX540-Arm7-Release/expected-results.json109
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json145
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release-Valgrind/expected-results.json1
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN/expected-results.json1
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-TSAN/expected-results.json1
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Win7-ShuttleA-HD2000-x86_64-Debug-Trybot/expected-results.json1
-rw-r--r--gm/rebaseline_server/testdata/inputs/gm-expectations/ignored-tests.txt10
-rw-r--r--gm/rebaseline_server/testdata/inputs/skp-summaries/actuals/summary.json32
-rw-r--r--gm/rebaseline_server/testdata/inputs/skp-summaries/expectations/summary.json32
-rw-r--r--gm/rebaseline_server/testdata/outputs/.gitignore1
-rw-r--r--gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/3x3bitmaprect.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/aaclip.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/bigblurs.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/bitmapsource.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_192_192.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_32_2.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/3x3bitmaprect.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/aaclip.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/bigblurs.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/bitmapsource.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_192_192.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_32_2.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/gpu/texdata.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/compare_configs_test.CompareConfigsTest.test_gm/gm.json337
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_endToEnd/compare_rendered_pictures.json237
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_endToEnd_withImageBaseGSUrl/compare_rendered_pictures.json237
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_repo_url/compare_rendered_pictures.json233
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/compare_to_expectations_test.CompareToExpectationsTest.test_gm/gm.json646
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/3x3bitmaprect.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/aaclip.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/bigblurs.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/bitmapsource.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_192_192.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_32_2.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/3x3bitmaprect.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/aaclip.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/bigblurs.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/bitmapsource.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_192_192.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_32_2.png1
-rw-r--r--gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/gpu/texdata.png1
-rw-r--r--gm/rebaseline_server/writable_expectations.py183
-rwxr-xr-xgm/rename_config.py104
-rwxr-xr-xgm/test_all.py25
-rw-r--r--gm/tests/.gitignore1
-rw-r--r--gm/tests/outputs/.gitignore1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/json-summary.txt31
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/pdf-poppler/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/pdf/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/pdf-poppler/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/pdf-poppler/selftest1.png1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/pdf/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/return_value1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf-poppler/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf-poppler/selftest1.png1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf/bogusfile1
-rw-r--r--gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf/selftest1.pdf1
-rw-r--r--gm/tests/outputs/checksum-based-filenames/output-expected/json-summary.txt25
-rw-r--r--gm/tests/outputs/checksum-based-filenames/output-expected/mismatchPath/bitmap-64bitMD5_selftest1_1209453360120438698.png1
-rw-r--r--gm/tests/outputs/checksum-based-filenames/output-expected/mismatchPath/bitmap-64bitMD5_selftest1_12927999507540085554.png1
-rw-r--r--gm/tests/outputs/checksum-based-filenames/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/checksum-based-filenames/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/checksum-based-filenames/output-expected/return_value1
-rw-r--r--gm/tests/outputs/checksum-based-filenames/output-expected/writePath/bitmap-64bitMD5_selftest1_1209453360120438698.png1
-rw-r--r--gm/tests/outputs/checksum-based-filenames/output-expected/writePath/bitmap-64bitMD5_selftest1_12927999507540085554.png1
-rw-r--r--gm/tests/outputs/checksum-based-filenames/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/json-summary.txt25
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/return_value1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/json-summary.txt25
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/return_value1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/json-summary.txt31
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/565/selftest2.png1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/8888/selftest2.png1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/return_value1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/565/selftest2.png1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/8888/selftest2.png1
-rw-r--r--gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-images/output-expected/json-summary.txt25
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-images/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-images/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-images/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-images/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-images/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-images/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-images/output-expected/return_value1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-json/output-expected/json-summary.txt25
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-json/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-json/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-json/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-json/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-json/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-json/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-json/output-expected/return_value1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-images/output-expected/json-summary.txt25
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-images/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-images/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-images/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-images/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-images/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-images/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-images/output-expected/return_value1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-json/output-expected/json-summary.txt25
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-json/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-json/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-json/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-json/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-json/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-json/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-json/output-expected/return_value1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/compared-against-nonexistent-dir/output-expected/return_value1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/json-summary.txt25
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/return_value1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/json-summary.txt40
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/565/selftest2.png1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/8888/selftest2.png1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/return_value1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/writePath/565/selftest2.png1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/writePath/8888/selftest2.png1
-rw-r--r--gm/tests/outputs/ignoring-one-test/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/json-summary.txt26
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/return_value1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/ignoring-some-failures/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/json-summary.txt14
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/return_value1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/565/selftest2.png1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/8888/selftest2.png1
-rw-r--r--gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/no-hierarchy/output-expected/json-summary.txt25
-rw-r--r--gm/tests/outputs/no-hierarchy/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/no-hierarchy/output-expected/mismatchPath/selftest1_565.png1
-rw-r--r--gm/tests/outputs/no-hierarchy/output-expected/mismatchPath/selftest1_8888.png1
-rw-r--r--gm/tests/outputs/no-hierarchy/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/no-hierarchy/output-expected/return_value1
-rw-r--r--gm/tests/outputs/no-hierarchy/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/no-hierarchy/output-expected/writePath/selftest1_565.png1
-rw-r--r--gm/tests/outputs/no-hierarchy/output-expected/writePath/selftest1_8888.png1
-rw-r--r--gm/tests/outputs/no-readpath/output-expected/json-summary.txt12
-rw-r--r--gm/tests/outputs/no-readpath/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/no-readpath/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/no-readpath/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/no-readpath/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/no-readpath/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/no-readpath/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/no-readpath/output-expected/return_value1
-rw-r--r--gm/tests/outputs/no-readpath/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/no-readpath/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/no-readpath/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/no-readpath/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/no-readpath/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/json-summary.txt21
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/return_value1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/nonverbose/output-expected/writePath/bogusfile1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/json-summary.txt40
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/565/selftest1-pipe.png1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/8888/selftest1-pipe.png1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/bogusfile1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/missingExpectationsPath/565/bogusfile1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/missingExpectationsPath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/missingExpectationsPath/bogusfile1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/return_value1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/writePath/565/bogusfile1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/writePath/565/selftest1.png1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/writePath/8888/bogusfile1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/writePath/8888/selftest1.png1
-rw-r--r--gm/tests/outputs/pipe-playback-failure/output-expected/writePath/bogusfile1
-rwxr-xr-xgm/tests/rebaseline.sh71
-rwxr-xr-xgm/tests/run.sh277
361 files changed, 0 insertions, 16409 deletions
diff --git a/gm/__init__.py b/gm/__init__.py
deleted file mode 100644
index 55c15fe5da..0000000000
--- a/gm/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Allow Python import of this directory.
diff --git a/gm/copy_config.py b/gm/copy_config.py
deleted file mode 100755
index 57743ae895..0000000000
--- a/gm/copy_config.py
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/usr/bin/python
-# Copyright (c) 2014 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.
-
-"""Utility to duplicate a config in some subset of our GM expectation files.
-
-Created for http://skbug.com/2752 ('split existing "gpu" GM results into "gl"
-and "gles"')
-
-Run with -h to see usage.
-
-Example command lines:
- copy_config.py gl gles '.*Mac10.7.*'
-
-TODO(epoger): Once https://codereview.chromium.org/397103003/ is committed,
-we should add a unittest. Until then, we can test this as follows:
-
-OLD=expectations/gm && NEW=/tmp/expectations && \
- rm -rf $NEW && \
- cp -a $OLD $NEW && \
- gm/copy_config.py 8888 8888-copy '.*Mac10.7.*' \
- --expectations-root $NEW && \
- diff --recursive $OLD $NEW
-"""
-__author__ = 'Elliot Poger'
-
-import argparse
-import os
-import re
-
-import gm_json
-
-DEFAULT_EXPECTATIONS_ROOT = os.path.join(
- os.path.dirname(__file__), os.pardir, 'expectations', 'gm')
-IMAGE_FILENAME_RE = re.compile(gm_json.IMAGE_FILENAME_PATTERN)
-
-
-class Copier(object):
-
- def __init__(self, args):
- """
- Params:
- args: the Namespace object generated by argparse.parse_args()
- """
- self._args = args
-
- def run(self):
- """Perform all the duplications."""
- for path in self._get_file_list():
- self._duplicate_config(path=path,
- old=self._args.old_config_name,
- new=self._args.new_config_name)
-
- def _duplicate_config(self, path, old, new):
- """Duplicates all instances of a config within a GM expectations file.
-
- Params:
- path: path to file which will be modified in place
- old: old config name
- new: new config name
- """
- dic = gm_json.LoadFromFile(file_path=path)
- expected_results = dic[gm_json.JSONKEY_EXPECTEDRESULTS]
- orig_keys = expected_results.keys()
- for key in orig_keys:
- result = expected_results[key]
- (testname, config) = IMAGE_FILENAME_RE.match(key).groups()
- if config == old:
- config = new
- key = '%s_%s.png' % (testname, config)
- expected_results[key] = result
- gm_json.WriteToFile(json_dict=dic, file_path=path)
-
- def _get_file_list(self):
- """Returns the list of files we want to operate on (the complete path
- to each file)."""
- root = self._args.expectations_root
- regex = re.compile(self._args.builder_name_pattern)
- return [os.path.join(root, builder, 'expected-results.json')
- for builder in os.listdir(root)
- if regex.match(builder)]
-
-
-def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('old_config_name',
- help=('Config we want to duplicate.'))
- parser.add_argument('new_config_name',
- help=('Name of the new config we want to create.'))
- parser.add_argument('builder_name_pattern',
- help=('Regex pattern describing which builders we want '
- 'to make the duplication for; \'.*\' to perform '
- 'the duplication on all builders.'))
- parser.add_argument('--expectations-root',
- default=DEFAULT_EXPECTATIONS_ROOT,
- help=('Root of the GM expectations dir; defaults to '
- '%(default)s'))
- args = parser.parse_args()
- copier = Copier(args)
- copier.run()
-
-if __name__ == '__main__':
- main()
diff --git a/gm/display_json_results.py b/gm/display_json_results.py
deleted file mode 100644
index 647e25101f..0000000000
--- a/gm/display_json_results.py
+++ /dev/null
@@ -1,114 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2013 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.
-
-"""Utility to display a summary of JSON-format GM results, and exit with
-a nonzero errorcode if there were non-ignored failures in the GM results.
-
-Usage:
- python display_json_results.py <filename>
-
-TODO(epoger): We may want to add flags to set the following:
-- which error types cause a nonzero return code
-- maximum number of tests to list for any one ResultAccumulator
- (to keep the output reasonably short)
-"""
-
-__author__ = 'Elliot Poger'
-
-
-# system-level imports
-import sys
-
-# local imports
-import gm_json
-
-
-class ResultAccumulator(object):
- """Object that accumulates results of a given type, and can generate a
- summary upon request."""
-
- def __init__(self, name, do_list, do_fail):
- """name: name of the category this result type falls into
- do_list: whether to list all of the tests with this results type
- do_fail: whether to return with nonzero exit code if there are any
- results of this type
- """
- self._name = name
- self._do_list = do_list
- self._do_fail = do_fail
- self._testnames = []
-
- def AddResult(self, testname):
- """Adds a result of this particular type.
- testname: (string) name of the test"""
- self._testnames.append(testname)
-
- def ShouldSignalFailure(self):
- """Returns true if this result type is serious (self._do_fail is True)
- and there were any results of this type."""
- if self._do_fail and self._testnames:
- return True
- else:
- return False
-
- def GetSummaryLine(self):
- """Returns a single-line string summary of all results added to this
- accumulator so far."""
- summary = ''
- if self._do_fail:
- summary += '[*] '
- else:
- summary += '[ ] '
- summary += str(len(self._testnames))
- summary += ' '
- summary += self._name
- if self._do_list:
- summary += ': '
- for testname in self._testnames:
- summary += testname
- summary += ' '
- return summary
-
-
-def Display(filepath):
- """Displays a summary of the results in a JSON file.
- Returns True if the results are free of any significant failures.
- filepath: (string) path to JSON file"""
-
- # Map labels within the JSON file to the ResultAccumulator for each label.
- results_map = {
- gm_json.JSONKEY_ACTUALRESULTS_FAILED:
- ResultAccumulator(name='ExpectationsMismatch',
- do_list=True, do_fail=True),
- gm_json.JSONKEY_ACTUALRESULTS_FAILUREIGNORED:
- ResultAccumulator(name='IgnoredExpectationsMismatch',
- do_list=True, do_fail=False),
- gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON:
- ResultAccumulator(name='MissingExpectations',
- do_list=False, do_fail=False),
- gm_json.JSONKEY_ACTUALRESULTS_SUCCEEDED:
- ResultAccumulator(name='Passed',
- do_list=False, do_fail=False),
- }
-
- success = True
- json_dict = gm_json.LoadFromFile(filepath)
- actual_results = json_dict[gm_json.JSONKEY_ACTUALRESULTS]
- for label, accumulator in results_map.iteritems():
- results = actual_results[label]
- if results:
- for result in results:
- accumulator.AddResult(result)
- print accumulator.GetSummaryLine()
- if accumulator.ShouldSignalFailure():
- success = False
- print '(results marked with [*] will cause nonzero return value)'
- return success
-
-
-if '__main__' == __name__:
- if len(sys.argv) != 2:
- raise Exception('usage: %s <input-json-filepath>' % sys.argv[0])
- sys.exit(0 if Display(sys.argv[1]) else 1)
diff --git a/gm/gm_error.h b/gm/gm_error.h
deleted file mode 100644
index e2274c4ffa..0000000000
--- a/gm/gm_error.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/*
- * Error codes used by gmmain.cpp.
- */
-
-#ifndef gm_error_DEFINED
-#define gm_error_DEFINED
-
-#include "gm.h"
-
-namespace skiagm {
-
- /**
- * The complete list of error types we might encounter in GM.
- */
- enum ErrorType {
- // Even though kNoGpuContext_ErrorType only occurs when SK_SUPPORT_GPU
- // is turned on, we always include this type in our enum so that
- // reports will be consistent whether SK_SUPPORT_GPU is turned on
- // or off (as long as the number of these errors is 0).
- kNoGpuContext_ErrorType,
-
- kIntentionallySkipped_ErrorType,
- kRenderModeMismatch_ErrorType,
- kGeneratePdfFailed_ErrorType,
- kExpectationsMismatch_ErrorType,
- kMissingExpectations_ErrorType,
- kWritingReferenceImage_ErrorType,
- kLast_ErrorType = kWritingReferenceImage_ErrorType
- };
-
- /**
- * Returns the name of the given ErrorType.
- */
- static const char *getErrorTypeName(ErrorType type) {
- switch(type) {
- case kNoGpuContext_ErrorType:
- return "NoGpuContext";
- case kIntentionallySkipped_ErrorType:
- return "IntentionallySkipped";
- case kRenderModeMismatch_ErrorType:
- return "RenderModeMismatch";
- case kGeneratePdfFailed_ErrorType:
- return "GeneratePdfFailed";
- case kExpectationsMismatch_ErrorType:
- return "ExpectationsMismatch";
- case kMissingExpectations_ErrorType:
- return "MissingExpectations";
- case kWritingReferenceImage_ErrorType:
- return "WritingReferenceImage";
- }
- // control should never reach here
- SkDEBUGFAIL("getErrorTypeName() called with unknown type");
- return "Unknown";
- }
-
- /**
- * Fills in "type" with the ErrorType associated with name "name".
- * Returns true if we found one, false if it is an unknown type name.
- */
- static bool getErrorTypeByName(const char name[], ErrorType *type) {
- for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
- ErrorType thisType = static_cast<ErrorType>(typeInt);
- const char *thisTypeName = getErrorTypeName(thisType);
- if (0 == strcmp(thisTypeName, name)) {
- *type = thisType;
- return true;
- }
- }
- return false;
- }
-
- /**
- * A combination of 0 or more ErrorTypes.
- */
- class ErrorCombination {
- public:
- ErrorCombination() : fBitfield(0) {}
- ErrorCombination(const ErrorType type) : fBitfield(1 << type) {}
-
- /**
- * Returns true iff there are NO errors.
- */
- bool isEmpty() const {
- return (0 == this->fBitfield);
- }
-
- /**
- * Adds this ErrorType to this ErrorCombination.
- */
- void add(const ErrorType type) {
- this->fBitfield |= (1 << type);
- }
-
- /**
- * Adds all ErrorTypes in "other" to this ErrorCombination.
- */
- void add(const ErrorCombination other) {
- this->fBitfield |= other.fBitfield;
- }
-
- /**
- * Returns true iff this ErrorCombination includes this ErrorType.
- */
- bool includes(const ErrorType type) const {
- return !(0 == (this->fBitfield & (1 << type)));
- }
-
- /**
- * Returns a string representation of all ErrorTypes in this
- * ErrorCombination.
- *
- * @param separator text with which to separate ErrorType names
- */
- SkString asString(const char separator[]) const {
- SkString s;
- for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
- ErrorType type = static_cast<ErrorType>(typeInt);
- if (this->includes(type)) {
- if (!s.isEmpty()) {
- s.append(separator);
- }
- s.append(getErrorTypeName(type));
- }
- }
- return s;
- }
-
- /**
- * Returns a new ErrorCombination, which includes the union of all
- * ErrorTypes in two ErrorCombination objects (this and other).
- */
- ErrorCombination plus(const ErrorCombination& other) const {
- ErrorCombination retval;
- retval.fBitfield = this->fBitfield | other.fBitfield;
- return retval;
- }
-
- /**
- * Returns a new ErrorCombination, which is a copy of "this"
- * but with all ErrorTypes in "other" removed.
- */
- ErrorCombination minus(const ErrorCombination& other) const {
- ErrorCombination retval;
- retval.fBitfield = this->fBitfield & ~(other.fBitfield);
- return retval;
- }
-
- private:
- int fBitfield;
- };
-
- // No errors at all.
- const static ErrorCombination kEmpty_ErrorCombination;
-}
-
-#endif // ifndef gm_error_DEFINED
diff --git a/gm/gm_expectations.cpp b/gm/gm_expectations.cpp
deleted file mode 100644
index db6abdf404..0000000000
--- a/gm/gm_expectations.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * TODO(epoger): Combine this with tools/image_expectations.cpp, or eliminate one of the two.
- */
-
-#include "gm_expectations.h"
-#include "SkBitmapHasher.h"
-#include "SkData.h"
-#include "SkImageDecoder.h"
-
-#define DEBUGFAIL_SEE_STDERR SkDEBUGFAIL("see stderr for message")
-
-// See gm_json.py for descriptions of each of these JSON keys.
-// These constants must be kept in sync with the ones in that Python file!
-const static char kJsonKey_ActualResults[] = "actual-results";
-const static char kJsonKey_ActualResults_Failed[] = "failed";
-const static char kJsonKey_ActualResults_FailureIgnored[]= "failure-ignored";
-const static char kJsonKey_ActualResults_NoComparison[] = "no-comparison";
-const static char kJsonKey_ActualResults_Succeeded[] = "succeeded";
-const static char kJsonKey_ExpectedResults[] = "expected-results";
-const static char kJsonKey_ExpectedResults_AllowedDigests[] = "allowed-digests";
-const static char kJsonKey_ExpectedResults_IgnoreFailure[] = "ignore-failure";
-
-// Types of result hashes we support in the JSON file.
-const static char kJsonKey_Hashtype_Bitmap_64bitMD5[] = "bitmap-64bitMD5";
-
-
-namespace skiagm {
-
- Json::Value CreateJsonTree(Json::Value expectedResults,
- Json::Value actualResultsFailed,
- Json::Value actualResultsFailureIgnored,
- Json::Value actualResultsNoComparison,
- Json::Value actualResultsSucceeded) {
- Json::Value actualResults;
- actualResults[kJsonKey_ActualResults_Failed] = actualResultsFailed;
- actualResults[kJsonKey_ActualResults_FailureIgnored] = actualResultsFailureIgnored;
- actualResults[kJsonKey_ActualResults_NoComparison] = actualResultsNoComparison;
- actualResults[kJsonKey_ActualResults_Succeeded] = actualResultsSucceeded;
- Json::Value root;
- root[kJsonKey_ActualResults] = actualResults;
- root[kJsonKey_ExpectedResults] = expectedResults;
- return root;
- }
-
- // GmResultDigest class...
-
- GmResultDigest::GmResultDigest(const SkBitmap &bitmap) {
- fIsValid = SkBitmapHasher::ComputeDigest(bitmap, &fHashDigest);
- }
-
- GmResultDigest::GmResultDigest(const Json::Value &jsonTypeValuePair) {
- fIsValid = false;
- if (!jsonTypeValuePair.isArray()) {
- SkDebugf("found non-array json value when parsing GmResultDigest: %s\n",
- jsonTypeValuePair.toStyledString().c_str());
- DEBUGFAIL_SEE_STDERR;
- } else if (2 != jsonTypeValuePair.size()) {
- SkDebugf("found json array with wrong size when parsing GmResultDigest: %s\n",
- jsonTypeValuePair.toStyledString().c_str());
- DEBUGFAIL_SEE_STDERR;
- } else {
- // TODO(epoger): The current implementation assumes that the
- // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
- Json::Value jsonHashValue = jsonTypeValuePair[1];
- if (!jsonHashValue.isIntegral()) {
- SkDebugf("found non-integer jsonHashValue when parsing GmResultDigest: %s\n",
- jsonTypeValuePair.toStyledString().c_str());
- DEBUGFAIL_SEE_STDERR;
- } else {
- fHashDigest = jsonHashValue.asUInt64();
- fIsValid = true;
- }
- }
- }
-
- bool GmResultDigest::isValid() const {
- return fIsValid;
- }
-
- bool GmResultDigest::equals(const GmResultDigest &other) const {
- // TODO(epoger): The current implementation assumes that this
- // and other are always of type kJsonKey_Hashtype_Bitmap_64bitMD5
- return (this->fIsValid && other.fIsValid && (this->fHashDigest == other.fHashDigest));
- }
-
- Json::Value GmResultDigest::asJsonTypeValuePair() const {
- // TODO(epoger): The current implementation assumes that the
- // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
- Json::Value jsonTypeValuePair;
- if (fIsValid) {
- jsonTypeValuePair.append(Json::Value(kJsonKey_Hashtype_Bitmap_64bitMD5));
- jsonTypeValuePair.append(Json::UInt64(fHashDigest));
- } else {
- jsonTypeValuePair.append(Json::Value("INVALID"));
- }
- return jsonTypeValuePair;
- }
-
- SkString GmResultDigest::getHashType() const {
- // TODO(epoger): The current implementation assumes that the
- // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
- return SkString(kJsonKey_Hashtype_Bitmap_64bitMD5);
- }
-
- SkString GmResultDigest::getDigestValue() const {
- // TODO(epoger): The current implementation assumes that the
- // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
- SkString retval;
- retval.appendU64(fHashDigest);
- return retval;
- }
-
-
- // Expectations class...
-
- Expectations::Expectations(bool ignoreFailure) {
- fIgnoreFailure = ignoreFailure;
- }
-
- Expectations::Expectations(const SkBitmap& bitmap, bool ignoreFailure) {
- fBitmap = bitmap;
- fIgnoreFailure = ignoreFailure;
- fAllowedResultDigests.push_back(GmResultDigest(bitmap));
- }
-
- Expectations::Expectations(const BitmapAndDigest& bitmapAndDigest) {
- fBitmap = bitmapAndDigest.fBitmap;
- fIgnoreFailure = false;
- fAllowedResultDigests.push_back(bitmapAndDigest.fDigest);
- }
-
- Expectations::Expectations(Json::Value jsonElement) {
- if (jsonElement.empty()) {
- fIgnoreFailure = kDefaultIgnoreFailure;
- } else {
- Json::Value ignoreFailure = jsonElement[kJsonKey_ExpectedResults_IgnoreFailure];
- if (ignoreFailure.isNull()) {
- fIgnoreFailure = kDefaultIgnoreFailure;
- } else if (!ignoreFailure.isBool()) {
- SkDebugf("found non-boolean json value for key '%s' in element '%s'\n",
- kJsonKey_ExpectedResults_IgnoreFailure,
- jsonElement.toStyledString().c_str());
- DEBUGFAIL_SEE_STDERR;
- fIgnoreFailure = kDefaultIgnoreFailure;
- } else {
- fIgnoreFailure = ignoreFailure.asBool();
- }
-
- Json::Value allowedDigests = jsonElement[kJsonKey_ExpectedResults_AllowedDigests];
- if (allowedDigests.isNull()) {
- // ok, we'll just assume there aren't any AllowedDigests to compare against
- } else if (!allowedDigests.isArray()) {
- SkDebugf("found non-array json value for key '%s' in element '%s'\n",
- kJsonKey_ExpectedResults_AllowedDigests,
- jsonElement.toStyledString().c_str());
- DEBUGFAIL_SEE_STDERR;
- } else {
- for (Json::ArrayIndex i=0; i<allowedDigests.size(); i++) {
- fAllowedResultDigests.push_back(GmResultDigest(allowedDigests[i]));
- }
- }
- }
- }
-
- bool Expectations::match(GmResultDigest actualGmResultDigest) const {
- for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
- GmResultDigest allowedResultDigest = this->fAllowedResultDigests[i];
- if (allowedResultDigest.equals(actualGmResultDigest)) {
- return true;
- }
- }
- return false;
- }
-
- Json::Value Expectations::asJsonValue() const {
- Json::Value allowedDigestArray;
- if (!this->fAllowedResultDigests.empty()) {
- for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
- allowedDigestArray.append(this->fAllowedResultDigests[i].asJsonTypeValuePair());
- }
- }
-
- Json::Value jsonExpectations;
- jsonExpectations[kJsonKey_ExpectedResults_AllowedDigests] = allowedDigestArray;
- jsonExpectations[kJsonKey_ExpectedResults_IgnoreFailure] = this->ignoreFailure();
- return jsonExpectations;
- }
-
- // IndividualImageExpectationsSource class...
-
- Expectations IndividualImageExpectationsSource::get(const char *testName) const {
- SkString path = SkOSPath::Join(fRootDir.c_str(), testName);
- SkBitmap referenceBitmap;
- bool decodedReferenceBitmap =
- SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap, kN32_SkColorType,
- SkImageDecoder::kDecodePixels_Mode, NULL);
- if (decodedReferenceBitmap) {
- return Expectations(referenceBitmap);
- } else {
- return Expectations();
- }
- }
-
-
- // JsonExpectationsSource class...
-
- JsonExpectationsSource::JsonExpectationsSource(const char *jsonPath) {
- Parse(jsonPath, &fJsonRoot);
- fJsonExpectedResults = fJsonRoot[kJsonKey_ExpectedResults];
- }
-
- Expectations JsonExpectationsSource::get(const char *testName) const {
- return Expectations(fJsonExpectedResults[testName]);
- }
-
- /*static*/ bool JsonExpectationsSource::Parse(const char *jsonPath, Json::Value *jsonRoot) {
- SkAutoDataUnref dataRef(SkData::NewFromFileName(jsonPath));
- if (NULL == dataRef.get()) {
- SkDebugf("error reading JSON file %s\n", jsonPath);
- DEBUGFAIL_SEE_STDERR;
- return false;
- }
-
- const char *bytes = reinterpret_cast<const char *>(dataRef.get()->data());
- size_t size = dataRef.get()->size();
- Json::Reader reader;
- if (!reader.parse(bytes, bytes+size, *jsonRoot)) {
- SkDebugf("error parsing JSON file %s\n", jsonPath);
- DEBUGFAIL_SEE_STDERR;
- return false;
- }
- return true;
- }
-}
diff --git a/gm/gm_json.py b/gm/gm_json.py
deleted file mode 100644
index 453cca8e44..0000000000
--- a/gm/gm_json.py
+++ /dev/null
@@ -1,193 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2013 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.
-
-"""Schema of the JSON summary file written out by the GM tool.
-
-This must be kept in sync with the kJsonKey_ constants in gm_expectations.cpp !
-"""
-
-__author__ = 'Elliot Poger'
-
-
-# system-level imports
-import io
-import json
-import os
-import posixpath
-import re
-
-
-# Key strings used in GM results JSON files (both expected-results.json and
-# actual-results.json).
-#
-# NOTE: These constants must be kept in sync with the kJsonKey_ constants in
-# gm_expectations.cpp and tools/PictureRenderer.cpp !
-# Eric suggests: create gm/gm_expectations_constants.h containing ONLY variable
-# declarations so as to be readable by both gm/gm_expectations.cpp and Python.
-
-
-JSONKEY_ACTUALRESULTS = 'actual-results'
-
-# Tests whose results failed to match expectations.
-JSONKEY_ACTUALRESULTS_FAILED = 'failed'
-
-# Tests whose results failed to match expectations, but IGNOREFAILURE causes
-# us to take them less seriously.
-JSONKEY_ACTUALRESULTS_FAILUREIGNORED = 'failure-ignored'
-
-# Tests for which we do not have any expectations. They may be new tests that
-# we haven't had a chance to check in expectations for yet, or we may have
-# consciously decided to leave them without expectations because we are unhappy
-# with the results (although we should try to move away from that, and instead
-# check in expectations with the IGNOREFAILURE flag set).
-JSONKEY_ACTUALRESULTS_NOCOMPARISON = 'no-comparison'
-
-# Tests whose results matched their expectations.
-JSONKEY_ACTUALRESULTS_SUCCEEDED = 'succeeded'
-
-
-# Descriptions of the result set as a whole.
-JSONKEY_DESCRIPTIONS = 'descriptions'
-JSONKEY_DESCRIPTIONS_BUILDER = 'builder'
-JSONKEY_DESCRIPTIONS_RENDER_MODE = 'renderMode'
-
-JSONKEY_EXPECTEDRESULTS = 'expected-results'
-
-# One or more [HashType/DigestValue] pairs representing valid results for this
-# test. Typically, there will just be one pair, but we allow for multiple
-# expectations, and the test will pass if any one of them is matched.
-JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS = 'allowed-digests'
-
-# Optional: one or more integers listing Skia bugs (under
-# https://code.google.com/p/skia/issues/list ) that pertain to this expectation.
-JSONKEY_EXPECTEDRESULTS_BUGS = 'bugs'
-
-# If IGNOREFAILURE is set to True, a failure of this test will be reported
-# within the FAILUREIGNORED section (thus NOT causing the buildbots to go red)
-# rather than the FAILED section (which WOULD cause the buildbots to go red).
-JSONKEY_EXPECTEDRESULTS_IGNOREFAILURE = 'ignore-failure'
-
-# Optional: a free-form text string with human-readable information about
-# this expectation.
-JSONKEY_EXPECTEDRESULTS_NOTES = 'notes'
-
-# Optional: boolean indicating whether this expectation was reviewed/approved
-# by a human being.
-# If True: a human looked at this image and approved it.
-# If False: this expectation was committed blind. (In such a case, please
-# add notes indicating why!)
-# If absent: this expectation was committed by a tool that didn't enforce human
-# review of expectations.
-JSONKEY_EXPECTEDRESULTS_REVIEWED = 'reviewed-by-human'
-
-# Allowed hash types for test expectations.
-JSONKEY_HASHTYPE_BITMAP_64BITMD5 = 'bitmap-64bitMD5'
-
-JSONKEY_HEADER = 'header'
-JSONKEY_HEADER_TYPE = 'type'
-JSONKEY_HEADER_REVISION = 'revision'
-JSONKEY_IMAGE_CHECKSUMALGORITHM = 'checksumAlgorithm'
-JSONKEY_IMAGE_CHECKSUMVALUE = 'checksumValue'
-JSONKEY_IMAGE_COMPARISONRESULT = 'comparisonResult'
-JSONKEY_IMAGE_FILEPATH = 'filepath'
-JSONKEY_SOURCE_TILEDIMAGES = 'tiled-images'
-JSONKEY_SOURCE_WHOLEIMAGE = 'whole-image'
-JSONKEY_IMAGE_BASE_GS_URL = 'image-base-gs-url'
-
-
-# Root directory where the buildbots store their actually-generated images...
-# as a publicly readable HTTP URL:
-GM_ACTUALS_ROOT_HTTP_URL = (
- 'http://chromium-skia-gm.commondatastorage.googleapis.com/gm')
-# as a GS URL that allows credential-protected write access:
-GM_ACTUALS_ROOT_GS_URL = 'gs://chromium-skia-gm/gm'
-
-# Pattern used to assemble each image's filename
-IMAGE_FILENAME_PATTERN = '(.+)_(.+)\.png' # matches (testname, config)
-
-# Pattern used to create image URLs, relative to some base URL.
-GM_RELATIVE_URL_FORMATTER = '%s/%s/%s.png' # pass in (hash_type, test_name,
- # hash_digest)
-GM_RELATIVE_URL_PATTERN = '(.+)/(.+)/(.+).png' # matches (hash_type, test_name,
- # hash_digest)
-GM_RELATIVE_URL_RE = re.compile(GM_RELATIVE_URL_PATTERN)
-
-
-def CreateGmActualUrl(test_name, hash_type, hash_digest,
- gm_actuals_root_url=GM_ACTUALS_ROOT_HTTP_URL):
- """Return the URL we can use to download a particular version of
- the actually-generated image for this particular GM test.
-
- test_name: name of the test, e.g. 'perlinnoise'
- hash_type: string indicating the hash type used to generate hash_digest,
- e.g. JSONKEY_HASHTYPE_BITMAP_64BITMD5
- hash_digest: the hash digest of the image to retrieve
- gm_actuals_root_url: root url where actual images are stored
- """
- return posixpath.join(
- gm_actuals_root_url, CreateGmRelativeUrl(
- test_name=test_name, hash_type=hash_type, hash_digest=hash_digest))
-
-
-def CreateGmRelativeUrl(test_name, hash_type, hash_digest):
- """Returns a relative URL pointing at a test result's image.
-
- Returns the URL we can use to download a particular version of
- the actually-generated image for this particular GM test,
- relative to the URL root.
-
- Args:
- test_name: name of the test, e.g. 'perlinnoise'
- hash_type: string indicating the hash type used to generate hash_digest,
- e.g. JSONKEY_HASHTYPE_BITMAP_64BITMD5
- hash_digest: the hash digest of the image to retrieve
- """
- return GM_RELATIVE_URL_FORMATTER % (hash_type, test_name, hash_digest)
-
-
-def SplitGmRelativeUrl(url):
- """Splits the relative URL into (test_name, hash_type, hash_digest) tuple.
-
- This is the inverse of CreateGmRelativeUrl().
-
- Args:
- url: a URL generated with CreateGmRelativeUrl().
-
- Returns: (test_name, hash_type, hash_digest) tuple.
- """
- hash_type, test_name, hash_digest = GM_RELATIVE_URL_RE.match(url).groups()
- return (test_name, hash_type, hash_digest)
-
-
-def LoadFromString(file_contents):
- """Loads the JSON summary written out by the GM tool.
-
- Returns a dictionary keyed by the values listed as JSONKEY_ constants
- above; if file_contents is empty, returns None."""
- # TODO(epoger): we should add a version number to the JSON file to ensure
- # that the writer and reader agree on the schema (raising an exception
- # otherwise).
- if not file_contents:
- return None
- json_dict = json.loads(file_contents)
- return json_dict
-
-
-def LoadFromFile(file_path):
- """Loads the JSON summary written out by the GM tool.
- Returns a dictionary keyed by the values listed as JSONKEY_ constants
- above."""
- file_contents = open(file_path, 'r').read()
- return LoadFromString(file_contents)
-
-
-def WriteToFile(json_dict, file_path):
- """Writes the JSON summary in json_dict out to file_path.
-
- The file is written Unix-style (each line ends with just LF, not CRLF);
- see https://code.google.com/p/skia/issues/detail?id=1815 for reasons."""
- with io.open(file_path, mode='w', newline='', encoding='utf-8') as outfile:
- outfile.write(unicode(json.dumps(json_dict, outfile, sort_keys=True,
- indent=2)))
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
deleted file mode 100644
index 8f6d53a255..0000000000
--- a/gm/gmmain.cpp
+++ /dev/null
@@ -1,2549 +0,0 @@
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/*
- * Code for the "gm" (Golden Master) rendering comparison tool.
- *
- * If you make changes to this, re-run the self-tests at gm/tests/run.sh
- * to make sure they still pass... you may need to change the expected
- * results of the self-test.
- */
-
-#include "gm.h"
-#include "gm_error.h"
-#include "gm_expectations.h"
-#include "system_preferences.h"
-#include "CrashHandler.h"
-#include "ProcStats.h"
-#include "Resources.h"
-#include "SamplePipeControllers.h"
-#include "SkBitmap.h"
-#include "SkColorPriv.h"
-#include "SkCommandLineFlags.h"
-#include "SkData.h"
-#include "SkDeferredCanvas.h"
-#include "SkDevice.h"
-#include "SkDocument.h"
-#include "SkDrawFilter.h"
-#include "SkForceLinking.h"
-#include "SkGPipe.h"
-#include "SkGraphics.h"
-#include "SkImageDecoder.h"
-#include "SkImageEncoder.h"
-#include "SkJSONCPP.h"
-#include "SkMultiPictureDraw.h"
-#include "SkOSFile.h"
-#include "SkPDFRasterizer.h"
-#include "SkPicture.h"
-#include "SkPictureRecorder.h"
-#include "SkRefCnt.h"
-#include "SkScalar.h"
-#include "SkStream.h"
-#include "SkString.h"
-#include "SkSurface.h"
-#include "SkTArray.h"
-#include "SkTDict.h"
-
-#ifdef SK_DEBUG
-static const bool kDebugOnly = true;
-#define GR_DUMP_FONT_CACHE 0
-#else
-static const bool kDebugOnly = false;
-#endif
-
-__SK_FORCE_IMAGE_DECODER_LINKING;
-
-#if SK_SUPPORT_GPU
-#include "GrContextFactory.h"
-#include "SkGpuDevice.h"
-typedef GrContextFactory::GLContextType GLContextType;
-#define DEFAULT_CACHE_VALUE -1
-static int gGpuCacheSizeBytes;
-static int gGpuCacheSizeCount;
-#else
-class GrContextFactory;
-class GrContext;
-class GrSurface;
-typedef int GLContextType;
-typedef int GrGLStandard;
-#endif
-
-#define DEBUGFAIL_SEE_STDERR SkDEBUGFAIL("see stderr for message")
-
-DECLARE_bool(useDocumentInsteadOfDevice);
-
-#ifdef SK_SUPPORT_PDF
- #include "SkPDFDevice.h"
- #include "SkPDFDocument.h"
-#endif
-
-// Until we resolve http://code.google.com/p/skia/issues/detail?id=455 ,
-// stop writing out XPS-format image baselines in gm.
-#undef SK_SUPPORT_XPS
-#ifdef SK_SUPPORT_XPS
- #include "SkXPSDevice.h"
-#endif
-
-#ifdef SK_BUILD_FOR_MAC
- #include "SkCGUtils.h"
-#endif
-
-using namespace skiagm;
-
-class Iter {
-public:
- Iter() {
- this->reset();
- }
-
- void reset() {
- fReg = GMRegistry::Head();
- }
-
- GM* next() {
- if (fReg) {
- GMRegistry::Factory fact = fReg->factory();
- fReg = fReg->next();
- return fact(0);
- }
- return NULL;
- }
-
- static int Count() {
- const GMRegistry* reg = GMRegistry::Head();
- int count = 0;
- while (reg) {
- count += 1;
- reg = reg->next();
- }
- return count;
- }
-
-private:
- const GMRegistry* fReg;
-};
-
-// TODO(epoger): Right now, various places in this code assume that all the
-// image files read/written by GM use this file extension.
-// Search for references to this constant to find these assumptions.
-const static char kPNG_FileExtension[] = "png";
-
-enum Backend {
- kRaster_Backend,
- kGPU_Backend,
- kPDF_Backend,
- kXPS_Backend,
-};
-
-enum BbhType {
- kNone_BbhType,
- kRTree_BbhType,
-};
-
-enum ConfigFlags {
- kNone_ConfigFlag = 0x0,
- /* Write GM images if a write path is provided. */
- kWrite_ConfigFlag = 0x1,
- /* Read reference GM images if a read path is provided. */
- kRead_ConfigFlag = 0x2,
- kRW_ConfigFlag = (kWrite_ConfigFlag | kRead_ConfigFlag),
- /* Use distance fields for rendering text */
- kDFText_ConfigFlag = 0x4,
- kRWDFT_ConfigFlag = (kRW_ConfigFlag | kDFText_ConfigFlag),
-};
-
-struct ConfigData {
- SkColorType fColorType;
- Backend fBackend;
- GLContextType fGLContextType; // GPU backend only
- int fSampleCnt; // GPU backend only
- ConfigFlags fFlags;
- const char* fName;
- bool fRunByDefault;
-};
-
-struct PDFRasterizerData {
- bool (*fRasterizerFunction)(SkStream*, SkBitmap*);
- const char* fName;
- bool fRunByDefault;
-};
-
-class BWTextDrawFilter : public SkDrawFilter {
-public:
- bool filter(SkPaint*, Type) SK_OVERRIDE;
-};
-bool BWTextDrawFilter::filter(SkPaint* p, Type t) {
- if (kText_Type == t) {
- p->setAntiAlias(false);
- }
- return true;
-}
-
-struct PipeFlagComboData {
- const char* name;
- uint32_t flags;
-};
-
-static PipeFlagComboData gPipeWritingFlagCombos[] = {
- { "", 0 },
- { " cross-process", SkGPipeWriter::kCrossProcess_Flag },
- { " cross-process, shared address", SkGPipeWriter::kCrossProcess_Flag
- | SkGPipeWriter::kSharedAddressSpace_Flag }
-};
-
-static SkData* encode_to_dct_data(size_t* pixelRefOffset, const SkBitmap& bitmap);
-DECLARE_int32(pdfRasterDpi);
-
-const static ErrorCombination kDefaultIgnorableErrorTypes = ErrorCombination()
- .plus(kMissingExpectations_ErrorType)
- .plus(kIntentionallySkipped_ErrorType);
-
-class GMMain {
-public:
- GMMain() : fUseFileHierarchy(false), fWriteChecksumBasedFilenames(false),
- fIgnorableErrorTypes(kDefaultIgnorableErrorTypes),
- fMismatchPath(NULL), fMissingExpectationsPath(NULL), fTestsRun(0),
- fRenderModesEncountered(1) {}
-
- /**
- * Assemble shortNamePlusConfig from (surprise!) shortName and configName.
- *
- * The method for doing so depends on whether we are using hierarchical naming.
- * For example, shortName "selftest1" and configName "8888" could be assembled into
- * either "selftest1_8888" or "8888/selftest1".
- */
- SkString make_shortname_plus_config(const char *shortName, const char *configName) {
- SkString name;
- if (0 == strlen(configName)) {
- name.append(shortName);
- } else if (fUseFileHierarchy) {
- name.appendf("%s%c%s", configName, SkPATH_SEPARATOR, shortName);
- } else {
- name.appendf("%s_%s", shortName, configName);
- }
- return name;
- }
-
- /**
- * Assemble filename, suitable for writing out the results of a particular test.
- */
- SkString make_filename(const char *path,
- const char *shortName,
- const char *configName,
- const char *renderModeDescriptor,
- const char *suffix) {
- SkString filename = make_shortname_plus_config(shortName, configName);
- filename.append(renderModeDescriptor);
- filename.appendUnichar('.');
- filename.append(suffix);
- return SkOSPath::Join(path, filename.c_str());
- }
-
- /**
- * Assemble filename suitable for writing out an SkBitmap.
- */
- SkString makeBitmapFilename(const char *path,
- const char *shortName,
- const char *configName,
- const char *renderModeDescriptor,
- const GmResultDigest &bitmapDigest) {
- if (fWriteChecksumBasedFilenames) {
- SkString filename;
- filename.append(bitmapDigest.getHashType());
- filename.appendUnichar('_');
- filename.append(shortName);
- filename.appendUnichar('_');
- filename.append(bitmapDigest.getDigestValue());
- filename.appendUnichar('.');
- filename.append(kPNG_FileExtension);
- return SkOSPath::Join(path, filename.c_str());
- } else {
- return make_filename(path, shortName, configName, renderModeDescriptor,
- kPNG_FileExtension);
- }
- }
-
- /* since PNG insists on unpremultiplying our alpha, we take no
- precision chances and force all pixels to be 100% opaque,
- otherwise on compare we may not get a perfect match.
- */
- static void force_all_opaque(const SkBitmap& bitmap) {
- SkColorType colorType = bitmap.colorType();
- switch (colorType) {
- case kN32_SkColorType:
- force_all_opaque_8888(bitmap);
- break;
- case kRGB_565_SkColorType:
- // nothing to do here; 565 bitmaps are inherently opaque
- break;
- default:
- SkDebugf("unsupported bitmap colorType %d\n", colorType);
- DEBUGFAIL_SEE_STDERR;
- }
- }
-
- static void force_all_opaque_8888(const SkBitmap& bitmap) {
- SkAutoLockPixels lock(bitmap);
- for (int y = 0; y < bitmap.height(); y++) {
- for (int x = 0; x < bitmap.width(); x++) {
- *bitmap.getAddr32(x, y) |= (SK_A32_MASK << SK_A32_SHIFT);
- }
- }
- }
-
- static ErrorCombination WriteBitmap(const SkString& path, const SkBitmap& bitmap) {
- // TODO(epoger): Now that we have removed force_all_opaque()
- // from this method, we should be able to get rid of the
- // transformation to 8888 format also.
- SkBitmap copy;
- bitmap.copyTo(&copy, kN32_SkColorType);
- if (!SkImageEncoder::EncodeFile(path.c_str(), copy,
- SkImageEncoder::kPNG_Type,
- 100)) {
- SkDebugf("FAILED to write bitmap: %s\n", path.c_str());
- return ErrorCombination(kWritingReferenceImage_ErrorType);
- }
- return kEmpty_ErrorCombination;
- }
-
- /**
- * Add all render modes encountered thus far to the "modes" array.
- */
- void GetRenderModesEncountered(SkTArray<SkString> &modes) {
- SkTDict<int>::Iter iter(this->fRenderModesEncountered);
- const char* mode;
- while ((mode = iter.next(NULL)) != NULL) {
- SkString modeAsString = SkString(mode);
- // TODO(epoger): It seems a bit silly that all of these modes were
- // recorded with a leading "-" which we have to remove here
- // (except for mode "", which means plain old original mode).
- // But that's how renderModeDescriptor has been passed into
- // compare_test_results_to_reference_bitmap() historically,
- // and changing that now may affect other parts of our code.
- if (modeAsString.startsWith("-")) {
- modeAsString.remove(0, 1);
- }
- modes.push_back(modeAsString);
- }
- }
-
- /**
- * Returns true if failures on this test should be ignored.
- */
- bool shouldIgnoreTest(const char *name) const {
- for (int i = 0; i < fIgnorableTestNames.count(); i++) {
- if (fIgnorableTestNames[i].equals(name)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Calls RecordTestResults to record that we skipped a test.
- *
- * Depending on the backend, this may mean that we skipped a single rendermode, or all
- * rendermodes; see http://skbug.com/1994 and https://codereview.chromium.org/129203002/
- */
- void RecordSkippedTest(const SkString& shortNamePlusConfig,
- const char renderModeDescriptor [], Backend backend) {
- if (kRaster_Backend == backend) {
- // Skipping a test on kRaster_Backend means that we will skip ALL renderModes
- // (as opposed to other backends, on which we only run the default renderMode).
- //
- // We cannot call RecordTestResults yet, because we won't know the full set of
- // renderModes until we have run all tests.
- fTestsSkippedOnAllRenderModes.push_back(shortNamePlusConfig);
- } else {
- this->RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
- renderModeDescriptor);
- }
- }
-
- /**
- * Records the results of this test in fTestsRun and fFailedTests.
- *
- * We even record successes, and errors that we regard as
- * "ignorable"; we can filter them out later.
- */
- void RecordTestResults(const ErrorCombination& errorCombination,
- const SkString& shortNamePlusConfig,
- const char renderModeDescriptor []) {
- // Things to do regardless of errorCombination.
- fTestsRun++;
- int renderModeCount = 0;
- this->fRenderModesEncountered.find(renderModeDescriptor, &renderModeCount);
- renderModeCount++;
- this->fRenderModesEncountered.set(renderModeDescriptor, renderModeCount);
-
- if (errorCombination.isEmpty()) {
- return;
- }
-
- // Things to do only if there is some error condition.
- SkString fullName = shortNamePlusConfig;
- fullName.append(renderModeDescriptor);
- for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
- ErrorType type = static_cast<ErrorType>(typeInt);
- if (errorCombination.includes(type)) {
- fFailedTests[type].push_back(fullName);
- }
- }
- }
-
- /**
- * Return the number of significant (non-ignorable) errors we have
- * encountered so far.
- */
- int NumSignificantErrors() {
- int significantErrors = 0;
- for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
- ErrorType type = static_cast<ErrorType>(typeInt);
- if (!fIgnorableErrorTypes.includes(type)) {
- significantErrors += fFailedTests[type].count();
- }
- }
- return significantErrors;
- }
-
- /**
- * Display the summary of results with this ErrorType.
- *
- * @param type which ErrorType
- * @param verbose whether to be all verbose about it
- */
- void DisplayResultTypeSummary(ErrorType type, bool verbose) {
- bool isIgnorableType = fIgnorableErrorTypes.includes(type);
-
- SkString line;
- if (isIgnorableType) {
- line.append("[ ] ");
- } else {
- line.append("[*] ");
- }
-
- SkTArray<SkString> *failedTestsOfThisType = &fFailedTests[type];
- int count = failedTestsOfThisType->count();
- line.appendf("%d %s", count, getErrorTypeName(type));
- if (!isIgnorableType || verbose) {
- line.append(":");
- for (int i = 0; i < count; ++i) {
- line.append(" ");
- line.append((*failedTestsOfThisType)[i]);
- }
- }
- SkDebugf("%s\n", line.c_str());
- }
-
- /**
- * List contents of fFailedTests to stdout.
- *
- * @param verbose whether to be all verbose about it
- */
- void ListErrors(bool verbose) {
- // First, print a single summary line.
- SkString summary;
- summary.appendf("Ran %d tests:", fTestsRun);
- for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
- ErrorType type = static_cast<ErrorType>(typeInt);
- summary.appendf(" %s=%d", getErrorTypeName(type), fFailedTests[type].count());
- }
- SkDebugf("%s\n", summary.c_str());
-
- // Now, for each failure type, list the tests that failed that way.
- for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
- this->DisplayResultTypeSummary(static_cast<ErrorType>(typeInt), verbose);
- }
- SkDebugf("(results marked with [*] will cause nonzero return value)\n");
- }
-
- static ErrorCombination write_document(const SkString& path, SkStreamAsset* asset) {
- SkFILEWStream stream(path.c_str());
- if (!stream.writeStream(asset, asset->getLength())) {
- SkDebugf("FAILED to write document: %s\n", path.c_str());
- return ErrorCombination(kWritingReferenceImage_ErrorType);
- }
- return kEmpty_ErrorCombination;
- }
-
- /**
- * Prepare an SkBitmap to render a GM into.
- *
- * After you've rendered the GM into the SkBitmap, you must call
- * complete_bitmap()!
- *
- * @todo thudson 22 April 2011 - could refactor this to take in
- * a factory to generate the context, always call readPixels()
- * (logically a noop for rasters, if wasted time), and thus collapse the
- * GPU special case and also let this be used for SkPicture testing.
- */
- static void setup_bitmap(const ConfigData& gRec, const SkISize& size,
- SkBitmap* bitmap) {
- bitmap->allocPixels(SkImageInfo::Make(size.width(), size.height(),
- gRec.fColorType, kPremul_SkAlphaType));
- bitmap->eraseColor(SK_ColorTRANSPARENT);
- }
-
- /**
- * Any finalization steps we need to perform on the SkBitmap after
- * we have rendered the GM into it.
- *
- * It's too bad that we are throwing away alpha channel data
- * we could otherwise be examining, but this had always been happening
- * before... it was buried within the compare() method at
- * https://code.google.com/p/skia/source/browse/trunk/gm/gmmain.cpp?r=7289#305 .
- *
- * Apparently we need this, at least for bitmaps that are either:
- * (a) destined to be written out as PNG files, or
- * (b) compared against bitmaps read in from PNG files
- * for the reasons described just above the force_all_opaque() method.
- *
- * Neglecting to do this led to the difficult-to-diagnose
- * http://code.google.com/p/skia/issues/detail?id=1079 ('gm generating
- * spurious pixel_error messages as of r7258')
- *
- * TODO(epoger): Come up with a better solution that allows us to
- * compare full pixel data, including alpha channel, while still being
- * robust in the face of transformations to/from PNG files.
- * Options include:
- *
- * 1. Continue to call force_all_opaque(), but ONLY for bitmaps that
- * will be written to, or compared against, PNG files.
- * PRO: Preserve/compare alpha channel info for the non-PNG cases
- * (comparing different renderModes in-memory)
- * CON: The bitmaps (and hash digests) for these non-PNG cases would be
- * different than those for the PNG-compared cases, and in the
- * case of a failed renderMode comparison, how would we write the
- * image to disk for examination?
- *
- * 2. Always compute image hash digests from PNG format (either
- * directly from the the bytes of a PNG file, or capturing the
- * bytes we would have written to disk if we were writing the
- * bitmap out as a PNG).
- * PRO: I think this would allow us to never force opaque, and to
- * the extent that alpha channel data can be preserved in a PNG
- * file, we could observe it.
- * CON: If we read a bitmap from disk, we need to take its hash digest
- * from the source PNG (we can't compute it from the bitmap we
- * read out of the PNG, because we will have already premultiplied
- * the alpha).
- * CON: Seems wasteful to convert a bitmap to PNG format just to take
- * its hash digest. (Although we're wasting lots of effort already
- * calling force_all_opaque().)
- *
- * 3. Make the alpha premultiply/unpremultiply routines 100% consistent,
- * so we can transform images back and forth without fear of off-by-one
- * errors.
- * CON: Math is hard.
- *
- * 4. Perform a "close enough" comparison of bitmaps (+/- 1 bit in each
- * channel), rather than demanding absolute equality.
- * CON: Can't do this with hash digests.
- */
- static void complete_bitmap(SkBitmap* bitmap) {
- force_all_opaque(*bitmap);
- }
-
- static void InstallFilter(SkCanvas* canvas);
-
- static void invokeGM(GM* gm, SkCanvas* canvas, bool isPDF, bool isDeferred) {
- SkAutoCanvasRestore acr(canvas, true);
-
- if (!isPDF) {
- canvas->concat(gm->getInitialTransform());
- }
- InstallFilter(canvas);
- gm->setCanvasIsDeferred(isDeferred);
- gm->draw(canvas);
- canvas->setDrawFilter(NULL);
- }
-
- static ErrorCombination generate_image(GM* gm, const ConfigData& gRec,
- GrSurface* gpuTarget,
- SkBitmap* bitmap,
- bool deferred) {
- const SkISize size (gm->getISize());
-
- SkAutoTUnref<SkSurface> surface(CreateSurface(gRec, size, gpuTarget));
- SkAutoTUnref<SkCanvas> canvas;
-
- if (deferred) {
- canvas.reset(SkDeferredCanvas::Create(surface));
- } else {
- canvas.reset(SkRef(surface->getCanvas()));
- }
- invokeGM(gm, canvas, false, deferred);
- canvas->flush();
-
- setup_bitmap(gRec, size, bitmap);
- surface->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0);
- complete_bitmap(bitmap);
- return kEmpty_ErrorCombination;
- }
-
- static void DrawPictureToSurface(SkSurface* surf,
- const SkPicture* pict,
- SkScalar scale,
- bool tile,
- bool useMPD) {
- SkASSERT(surf->width() == pict->cullRect().width() &&
- surf->height() == pict->cullRect().height());
-
- if (tile) {
- SkMultiPictureDraw mpd;
- SkTDArray<SkSurface*> surfaces;
-
- const SkISize tileSize = SkISize::Make(16, 16);
-
- const SkImageInfo ii = surf->getCanvas()->imageInfo().makeWH(tileSize.width(),
- tileSize.height());
-
- for (int tileY = 0; tileY < pict->cullRect().height(); tileY += tileSize.height()) {
- for (int tileX = 0; tileX < pict->cullRect().width(); tileX += tileSize.width()) {
-
- *surfaces.append() = surf->getCanvas()->newSurface(ii);
-
- InstallFilter(surfaces.top()->getCanvas());
-
- SkMatrix matrix;
- matrix.setTranslate(-pict->cullRect().fLeft, -pict->cullRect().fTop);
- matrix.postTranslate(-SkIntToScalar(tileX), -SkIntToScalar(tileY));
- matrix.postScale(scale, scale);
-
- if (useMPD) {
- mpd.add(surfaces.top()->getCanvas(), pict, &matrix, NULL);
- } else {
- surfaces.top()->getCanvas()->drawPicture(pict, &matrix, NULL);
- }
- }
- }
-
- mpd.draw();
-
- SkPaint gatherPaint;
- gatherPaint.setXfermodeMode(SkXfermode::kSrc_Mode);
-
- int tileIndex = 0;
- for (int tileY = 0; tileY < pict->cullRect().height(); tileY += tileSize.height()) {
- for (int tileX = 0; tileX < pict->cullRect().width(); tileX += tileSize.width()) {
- surf->getCanvas()->drawImage(surfaces[tileIndex]->newImageSnapshot(),
- SkIntToScalar(tileX), SkIntToScalar(tileY),
- &gatherPaint);
- surfaces[tileIndex]->unref();
- tileIndex++;
- }
- }
- } else {
- InstallFilter(surf->getCanvas());
-
- SkMatrix matrix;
- matrix.setTranslate(-pict->cullRect().fLeft, -pict->cullRect().fTop);
- matrix.postScale(scale, scale);
-
- if (useMPD) {
- SkMultiPictureDraw mpd;
- mpd.add(surf->getCanvas(), pict, &matrix, NULL);
- mpd.draw();
- } else {
- surf->getCanvas()->drawPicture(pict, &matrix, NULL);
- }
- }
- }
-
- static void generate_image_from_picture(GM* gm, const ConfigData& config,
- GrSurface* gpuTarget,
- SkPicture* pict, SkBitmap* bitmap,
- SkScalar scale = SK_Scalar1,
- bool tile = false) {
- const SkISize size = gm->getISize();
-
- SkAutoTUnref<SkSurface> surf(CreateSurface(config, size, gpuTarget));
-
- DrawPictureToSurface(surf, pict, scale, tile, false);
-
- setup_bitmap(config, size, bitmap);
-
- surf->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0);
-
- complete_bitmap(bitmap);
- }
-
- static bool generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) {
-#ifdef SK_SUPPORT_PDF
- SkMatrix initialTransform = gm->getInitialTransform();
- if (FLAGS_useDocumentInsteadOfDevice) {
- SkISize pageISize = gm->getISize();
- SkAutoTUnref<SkDocument> pdfDoc(
- SkDocument::CreatePDF(&pdf, NULL,
- encode_to_dct_data,
- SkIntToScalar(FLAGS_pdfRasterDpi)));
-
- if (!pdfDoc.get()) {
- return false;
- }
-
- SkCanvas* canvas = NULL;
- canvas = pdfDoc->beginPage(SkIntToScalar(pageISize.width()),
- SkIntToScalar(pageISize.height()));
- canvas->concat(initialTransform);
-
- invokeGM(gm, canvas, true, false);
-
- return pdfDoc->close();
- } else {
- SkISize pageSize = gm->getISize();
- SkPDFDevice* dev = NULL;
- if (initialTransform.isIdentity()) {
- dev = new SkPDFDevice(pageSize, pageSize, initialTransform);
- } else {
- SkRect content = SkRect::MakeWH(SkIntToScalar(pageSize.width()),
- SkIntToScalar(pageSize.height()));
- initialTransform.mapRect(&content);
- if (!content.intersect(0, 0, SkIntToScalar(pageSize.width()),
- SkIntToScalar(pageSize.height()))) {
- content.setEmpty();
- }
- SkISize contentSize =
- SkISize::Make(SkScalarRoundToInt(content.width()),
- SkScalarRoundToInt(content.height()));
- dev = new SkPDFDevice(pageSize, contentSize, initialTransform);
- }
- dev->setDCTEncoder(encode_to_dct_data);
- dev->setRasterDpi(SkIntToScalar(FLAGS_pdfRasterDpi));
- SkAutoUnref aur(dev);
- SkCanvas c(dev);
- invokeGM(gm, &c, true, false);
- SkPDFDocument doc;
- doc.appendPage(dev);
- doc.emitPDF(&pdf);
- }
-#endif // SK_SUPPORT_PDF
- return true; // Do not report failure if pdf is not supported.
- }
-
- static void generate_xps(GM* gm, SkDynamicMemoryWStream& xps) {
-#ifdef SK_SUPPORT_XPS
- SkISize size = gm->getISize();
-
- SkSize trimSize = SkSize::Make(SkIntToScalar(size.width()),
- SkIntToScalar(size.height()));
- static const SkScalar inchesPerMeter = SkScalarDiv(10000, 254);
- static const SkScalar upm = 72 * inchesPerMeter;
- SkVector unitsPerMeter = SkPoint::Make(upm, upm);
- static const SkScalar ppm = 200 * inchesPerMeter;
- SkVector pixelsPerMeter = SkPoint::Make(ppm, ppm);
-
- SkXPSDevice* dev = new SkXPSDevice();
- SkAutoUnref aur(dev);
-
- SkCanvas c(dev);
- dev->beginPortfolio(&xps);
- dev->beginSheet(unitsPerMeter, pixelsPerMeter, trimSize);
- invokeGM(gm, &c, false, false);
- dev->endSheet();
- dev->endPortfolio();
-
-#endif
- }
-
- /**
- * Log more detail about the mistmatch between expectedBitmap and
- * actualBitmap.
- */
- void report_bitmap_diffs(const SkBitmap& expectedBitmap, const SkBitmap& actualBitmap,
- const char *testName) {
- const int expectedWidth = expectedBitmap.width();
- const int expectedHeight = expectedBitmap.height();
- const int width = actualBitmap.width();
- const int height = actualBitmap.height();
- if ((expectedWidth != width) || (expectedHeight != height)) {
- SkDebugf("---- %s: dimension mismatch -- expected [%d %d], actual [%d %d]\n",
- testName, expectedWidth, expectedHeight, width, height);
- return;
- }
-
- if ((kN32_SkColorType != expectedBitmap.colorType()) ||
- (kN32_SkColorType != actualBitmap.colorType())) {
- SkDebugf("---- %s: not computing max per-channel pixel mismatch because non-8888\n",
- testName);
- return;
- }
-
- SkAutoLockPixels alp0(expectedBitmap);
- SkAutoLockPixels alp1(actualBitmap);
- int errR = 0;
- int errG = 0;
- int errB = 0;
- int errA = 0;
- int differingPixels = 0;
-
- for (int y = 0; y < height; ++y) {
- const SkPMColor* expectedPixelPtr = expectedBitmap.getAddr32(0, y);
- const SkPMColor* actualPixelPtr = actualBitmap.getAddr32(0, y);
- for (int x = 0; x < width; ++x) {
- SkPMColor expectedPixel = *expectedPixelPtr++;
- SkPMColor actualPixel = *actualPixelPtr++;
- if (expectedPixel != actualPixel) {
- differingPixels++;
- errR = SkMax32(errR, SkAbs32((int)SkGetPackedR32(expectedPixel) -
- (int)SkGetPackedR32(actualPixel)));
- errG = SkMax32(errG, SkAbs32((int)SkGetPackedG32(expectedPixel) -
- (int)SkGetPackedG32(actualPixel)));
- errB = SkMax32(errB, SkAbs32((int)SkGetPackedB32(expectedPixel) -
- (int)SkGetPackedB32(actualPixel)));
- errA = SkMax32(errA, SkAbs32((int)SkGetPackedA32(expectedPixel) -
- (int)SkGetPackedA32(actualPixel)));
- }
- }
- }
- SkDebugf("---- %s: %d (of %d) differing pixels, "
- "max per-channel mismatch R=%d G=%d B=%d A=%d\n",
- testName, differingPixels, width*height, errR, errG, errB, errA);
- }
-
- /**
- * Compares actual hash digest to expectations, returning the set of errors
- * (if any) that we saw along the way.
- *
- * If fMismatchPath has been set, and there are pixel diffs, then the
- * actual bitmap will be written out to a file within fMismatchPath.
- * And similarly for fMissingExpectationsPath...
- *
- * @param expectations what expectations to compare actualBitmap against
- * @param actualBitmapAndDigest the SkBitmap we actually generated, and its GmResultDigest
- * @param shortName name of test, e.g. "selftest1"
- * @param configName name of config, e.g. "8888"
- * @param renderModeDescriptor e.g., "-rtree", "-deferred"
- * @param addToJsonSummary whether to add these results (both actual and
- * expected) to the JSON summary. Regardless of this setting, if
- * we find an image mismatch in this test, we will write these
- * results to the JSON summary. (This is so that we will always
- * report errors across rendering modes, such as pipe vs tiled.
- * See https://codereview.chromium.org/13650002/ )
- */
- ErrorCombination compare_to_expectations(Expectations expectations,
- const BitmapAndDigest& actualBitmapAndDigest,
- const char *shortName, const char *configName,
- const char *renderModeDescriptor,
- bool addToJsonSummary) {
- ErrorCombination errors;
- SkString shortNamePlusConfig = make_shortname_plus_config(shortName, configName);
- SkString completeNameString(shortNamePlusConfig);
- completeNameString.append(renderModeDescriptor);
- completeNameString.append(".");
- completeNameString.append(kPNG_FileExtension);
- const char* completeName = completeNameString.c_str();
-
- if (expectations.empty()) {
- errors.add(kMissingExpectations_ErrorType);
-
- // Write out the "actuals" for any tests without expectations, if we have
- // been directed to do so.
- if (fMissingExpectationsPath) {
- SkString path = this->makeBitmapFilename(fMissingExpectationsPath, shortName,
- configName, renderModeDescriptor,
- actualBitmapAndDigest.fDigest);
- WriteBitmap(path, actualBitmapAndDigest.fBitmap);
- }
-
- } else if (!expectations.match(actualBitmapAndDigest.fDigest)) {
- addToJsonSummary = true;
- // The error mode we record depends on whether this was running
- // in a non-standard renderMode.
- if ('\0' == *renderModeDescriptor) {
- errors.add(kExpectationsMismatch_ErrorType);
- } else {
- errors.add(kRenderModeMismatch_ErrorType);
- }
-
- // Write out the "actuals" for any mismatches, if we have
- // been directed to do so.
- if (fMismatchPath) {
- SkString path = this->makeBitmapFilename(fMismatchPath, shortName, configName,
- renderModeDescriptor,
- actualBitmapAndDigest.fDigest);
- WriteBitmap(path, actualBitmapAndDigest.fBitmap);
- }
-
- // If we have access to a single expected bitmap, log more
- // detail about the mismatch.
- const SkBitmap *expectedBitmapPtr = expectations.asBitmap();
- if (expectedBitmapPtr) {
- report_bitmap_diffs(*expectedBitmapPtr, actualBitmapAndDigest.fBitmap,
- completeName);
- }
- }
-
- if (addToJsonSummary) {
- add_actual_results_to_json_summary(completeName, actualBitmapAndDigest.fDigest, errors,
- expectations.ignoreFailure());
- add_expected_results_to_json_summary(completeName, expectations);
- }
-
- return errors;
- }
-
- /**
- * Add this result to the appropriate JSON collection of actual results (but just ONE),
- * depending on errors encountered.
- */
- void add_actual_results_to_json_summary(const char testName[],
- const GmResultDigest &actualResultDigest,
- ErrorCombination errors,
- bool ignoreFailure) {
- Json::Value jsonActualResults = actualResultDigest.asJsonTypeValuePair();
- Json::Value *resultCollection = NULL;
-
- if (errors.isEmpty()) {
- resultCollection = &this->fJsonActualResults_Succeeded;
- } else if (errors.includes(kRenderModeMismatch_ErrorType)) {
- resultCollection = &this->fJsonActualResults_Failed;
- } else if (errors.includes(kExpectationsMismatch_ErrorType)) {
- if (ignoreFailure) {
- resultCollection = &this->fJsonActualResults_FailureIgnored;
- } else {
- resultCollection = &this->fJsonActualResults_Failed;
- }
- } else if (errors.includes(kMissingExpectations_ErrorType)) {
- // TODO: What about the case where there IS an expected
- // image hash digest, but that gm test doesn't actually
- // run? For now, those cases will always be ignored,
- // because gm only looks at expectations that correspond
- // to gm tests that were actually run.
- //
- // Once we have the ability to express expectations as a
- // JSON file, we should fix this (and add a test case for
- // which an expectation is given but the test is never
- // run).
- resultCollection = &this->fJsonActualResults_NoComparison;
- }
-
- // If none of the above cases match, we don't add it to ANY tally of actual results.
- if (resultCollection) {
- (*resultCollection)[testName] = jsonActualResults;
- }
- }
-
- /**
- * Add this test to the JSON collection of expected results.
- */
- void add_expected_results_to_json_summary(const char testName[],
- Expectations expectations) {
- this->fJsonExpectedResults[testName] = expectations.asJsonValue();
- }
-
- /**
- * Compare actualBitmap to expectations stored in this->fExpectationsSource.
- *
- * @param gm which test generated the actualBitmap
- * @param gRec
- * @param configName The config name to look for in the expectation file.
- * @param actualBitmapAndDigest ptr to bitmap generated by this run, or NULL
- * if we don't have a usable bitmap representation
- */
- ErrorCombination compareTestResultsToStoredExpectations(
- GM* gm, const ConfigData& gRec, const char* configName,
- const BitmapAndDigest* actualBitmapAndDigest) {
- ErrorCombination errors;
-
- if (NULL == actualBitmapAndDigest) {
- // Note that we intentionally skipped validating the results for
- // this test, because we don't know how to generate an SkBitmap
- // version of the output.
- errors.add(ErrorCombination(kIntentionallySkipped_ErrorType));
- } else if (!(gRec.fFlags & kWrite_ConfigFlag)) {
- // We don't record the results for this test or compare them
- // against any expectations, because the output image isn't
- // meaningful.
- // See https://code.google.com/p/skia/issues/detail?id=1410 ('some
- // GM result images not available for download from Google Storage')
- errors.add(ErrorCombination(kIntentionallySkipped_ErrorType));
- } else {
- ExpectationsSource *expectationsSource = this->fExpectationsSource.get();
- SkString nameWithExtension = make_shortname_plus_config(gm->getName(), configName);
- nameWithExtension.append(".");
- nameWithExtension.append(kPNG_FileExtension);
-
- if (expectationsSource && (gRec.fFlags & kRead_ConfigFlag)) {
- /*
- * Get the expected results for this test, as one or more allowed
- * hash digests. The current implementation of expectationsSource
- * get this by computing the hash digest of a single PNG file on disk.
- *
- * TODO(epoger): This relies on the fact that
- * force_all_opaque() was called on the bitmap before it
- * was written to disk as a PNG in the first place. If
- * not, the hash digest returned here may not match the
- * hash digest of actualBitmap, which *has* been run through
- * force_all_opaque().
- * See comments above complete_bitmap() for more detail.
- */
- Expectations expectations = expectationsSource->get(nameWithExtension.c_str());
- if (this->shouldIgnoreTest(gm->getName())) {
- expectations.setIgnoreFailure(true);
- }
- errors.add(compare_to_expectations(expectations, *actualBitmapAndDigest,
- gm->getName(), configName, "", true));
- } else {
- // If we are running without expectations, we still want to
- // record the actual results.
- add_actual_results_to_json_summary(nameWithExtension.c_str(),
- actualBitmapAndDigest->fDigest,
- ErrorCombination(kMissingExpectations_ErrorType),
- false);
- errors.add(ErrorCombination(kMissingExpectations_ErrorType));
- }
- }
- return errors;
- }
-
- /**
- * Compare actualBitmap to referenceBitmap.
- *
- * @param shortName test name, e.g. "selftest1"
- * @param configName configuration name, e.g. "8888"
- * @param renderModeDescriptor
- * @param actualBitmap actual bitmap generated by this run
- * @param referenceBitmap bitmap we expected to be generated
- */
- ErrorCombination compare_test_results_to_reference_bitmap(
- const char *shortName, const char *configName, const char *renderModeDescriptor,
- SkBitmap& actualBitmap, const SkBitmap* referenceBitmap) {
-
- SkASSERT(referenceBitmap);
- Expectations expectations(*referenceBitmap);
- BitmapAndDigest actualBitmapAndDigest(actualBitmap);
-
- // TODO: Eliminate RecordTestResults from here.
- // Results recording code for the test_drawing path has been refactored so that
- // RecordTestResults is only called once, at the topmost level. However, the
- // other paths have not yet been refactored, and RecordTestResults has been added
- // here to maintain proper behavior for calls not coming from the test_drawing path.
- ErrorCombination errors;
- errors.add(compare_to_expectations(expectations, actualBitmapAndDigest, shortName,
- configName, renderModeDescriptor, false));
- SkString shortNamePlusConfig = make_shortname_plus_config(shortName, configName);
- RecordTestResults(errors, shortNamePlusConfig, renderModeDescriptor);
-
- return errors;
- }
-
- static SkPicture* generate_new_picture(GM* gm, BbhType bbhType, uint32_t recordFlags,
- SkScalar scale = SK_Scalar1) {
- SkScalar width = SkScalarMul(SkIntToScalar(gm->getISize().width()), scale);
- SkScalar height = SkScalarMul(SkIntToScalar(gm->getISize().height()), scale);
-
- SkAutoTDelete<SkBBHFactory> factory;
- if (kRTree_BbhType == bbhType) {
- factory.reset(SkNEW(SkRTreeFactory));
- }
- SkPictureRecorder recorder;
- SkCanvas* cv = recorder.beginRecording(width, height, factory.get(), recordFlags);
- cv->scale(scale, scale);
- invokeGM(gm, cv, false, false);
- return recorder.endRecording();
- }
-
- static SkPicture* stream_to_new_picture(const SkPicture& src) {
- SkDynamicMemoryWStream storage;
- src.serialize(&storage);
- SkAutoTUnref<SkStreamAsset> pictReadback(storage.detachAsStream());
- SkPicture* retval = SkPicture::CreateFromStream(pictReadback,
- &SkImageDecoder::DecodeMemory);
- return retval;
- }
-
- // Test: draw into a bitmap or pdf.
- // Depending on flags, possibly compare to an expected image.
- // If writePath is not NULL, also write images (or documents) to the specified path.
- ErrorCombination test_drawing(GM* gm, const ConfigData& gRec,
- const SkTDArray<const PDFRasterizerData*> &pdfRasterizers,
- const char writePath [],
- GrSurface* gpuTarget,
- SkBitmap* bitmap) {
- ErrorCombination errors;
- SkDynamicMemoryWStream document;
-
- if (gRec.fBackend == kRaster_Backend ||
- gRec.fBackend == kGPU_Backend) {
- // Early exit if we can't generate the image.
- errors.add(generate_image(gm, gRec, gpuTarget, bitmap, false));
- if (!errors.isEmpty()) {
- // TODO: Add a test to exercise what the stdout and
- // JSON look like if we get an "early error" while
- // trying to generate the image.
- return errors;
- }
-
- errors.add(this->writeBitmap(gm, gRec, gRec.fName, writePath, *bitmap));
- } else if (gRec.fBackend == kPDF_Backend) {
- if (!generate_pdf(gm, document)) {
- errors.add(kGeneratePdfFailed_ErrorType);
- } else {
- SkAutoTUnref<SkStreamAsset> documentStream(document.detachAsStream());
- if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
- SkString path = make_filename(writePath, gm->getName(), gRec.fName, "", "pdf");
- errors.add(write_document(path, documentStream));
- }
-
- if (!(gm->getFlags() & GM::kSkipPDFRasterization_Flag)) {
- for (int i = 0; i < pdfRasterizers.count(); i++) {
- SkBitmap pdfBitmap;
- documentStream->rewind();
- bool success = (*pdfRasterizers[i]->fRasterizerFunction)(
- documentStream.get(), &pdfBitmap);
- if (!success) {
- SkDebugf("FAILED to render PDF for %s using renderer %s\n",
- gm->getName(),
- pdfRasterizers[i]->fName);
- continue;
- }
-
- SkString configName(gRec.fName);
- configName.append("-");
- configName.append(pdfRasterizers[i]->fName);
-
- errors.add(this->writeBitmap(gm, gRec, configName.c_str(),
- writePath, pdfBitmap));
- }
- } else {
- errors.add(kIntentionallySkipped_ErrorType);
- }
- }
- } else if (gRec.fBackend == kXPS_Backend) {
- generate_xps(gm, document);
- SkAutoTUnref<SkStreamAsset> documentStream(document.detachAsStream());
-
- errors.add(this->compareTestResultsToStoredExpectations(
- gm, gRec, gRec.fName, NULL));
-
- if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
- SkString path = make_filename(writePath, gm->getName(), gRec.fName, "", "xps");
- errors.add(write_document(path, documentStream));
- }
- } else {
- SkASSERT(false);
- }
- return errors;
- }
-
- ErrorCombination test_deferred_drawing(GM* gm,
- const ConfigData& gRec,
- const SkBitmap& referenceBitmap,
- GrSurface* gpuTarget) {
- if (gRec.fBackend == kRaster_Backend ||
- gRec.fBackend == kGPU_Backend) {
- const char renderModeDescriptor[] = "-deferred";
- SkBitmap bitmap;
- // Early exit if we can't generate the image, but this is
- // expected in some cases, so don't report a test failure.
- ErrorCombination errors = generate_image(gm, gRec, gpuTarget, &bitmap, true);
- // TODO(epoger): This logic is the opposite of what is
- // described above... if we succeeded in generating the
- // -deferred image, we exit early! We should fix this
- // ASAP, because it is hiding -deferred errors... but for
- // now, I'm leaving the logic as it is so that the
- // refactoring change
- // https://codereview.chromium.org/12992003/ is unblocked.
- //
- // Filed as https://code.google.com/p/skia/issues/detail?id=1180
- // ('image-surface gm test is failing in "deferred" mode,
- // and gm is not reporting the failure')
- if (errors.isEmpty()) {
- // TODO(epoger): Report this as a new ErrorType,
- // something like kImageGeneration_ErrorType?
- return kEmpty_ErrorCombination;
- }
- return compare_test_results_to_reference_bitmap(
- gm->getName(), gRec.fName, renderModeDescriptor, bitmap, &referenceBitmap);
- }
- return kEmpty_ErrorCombination;
- }
-
- static SkSurface* CreateSurface(const ConfigData& config,
- const SkISize& size,
- GrSurface* gpuTarget) {
- if (config.fBackend == kRaster_Backend) {
- SkImageInfo ii = SkImageInfo::Make(size.width(), size.height(),
- config.fColorType, kPremul_SkAlphaType);
-
- return SkSurface::NewRaster(ii);
- }
-#if SK_SUPPORT_GPU
- else {
- uint32_t flags = (config.fFlags & kDFText_ConfigFlag) ?
- SkSurfaceProps::kUseDistanceFieldFonts_Flag : 0;
- SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
- return SkSurface::NewRenderTargetDirect(gpuTarget->asRenderTarget(), &props);
- }
-#endif
-
- return NULL;
- }
-
- ErrorCombination writeBitmap(GM* gm,
- const ConfigData& config,
- const char* configName,
- const char* writePath,
- const SkBitmap& bitmap) {
- ErrorCombination errors;
-
- BitmapAndDigest bitmapAndDigest(bitmap);
- errors.add(this->compareTestResultsToStoredExpectations(gm, config,
- configName, &bitmapAndDigest));
-
- if (writePath && (config.fFlags & kWrite_ConfigFlag)) {
- SkString path;
-
- path = this->makeBitmapFilename(writePath, gm->getName(), configName,
- "", bitmapAndDigest.fDigest);
- errors.add(WriteBitmap(path, bitmapAndDigest.fBitmap));
- }
-
- return errors;
- }
-
- ErrorCombination testMPDDrawing(GM* gm,
- const ConfigData& config,
- const char* writePath,
- GrSurface* gpuTarget,
- const SkBitmap& referenceBitmap) {
- SkASSERT(kRaster_Backend == config.fBackend || kGPU_Backend == config.fBackend);
-
- static const uint32_t kMPDFlags = SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag;
-
- SkAutoTUnref<SkPicture> pict(generate_new_picture(gm, kRTree_BbhType, kMPDFlags));
-
- SkAutoTUnref<SkSurface> surf(CreateSurface(config, gm->getISize(), gpuTarget));
-
- DrawPictureToSurface(surf, pict, SK_Scalar1, false, true);
-
- SkBitmap bitmap;
-
- setup_bitmap(config, gm->getISize(), &bitmap);
-
- surf->readPixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
- complete_bitmap(&bitmap);
-
- SkString configName(config.fName);
- configName.append("-mpd");
-
- return this->writeBitmap(gm, config, configName.c_str(), writePath, bitmap);
- }
-
- ErrorCombination test_pipe_playback(GM* gm, const ConfigData& gRec,
- const SkBitmap& referenceBitmap, bool simulateFailure) {
- const SkString shortNamePlusConfig = make_shortname_plus_config(gm->getName(),
- gRec.fName);
- ErrorCombination errors;
- for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) {
- SkString renderModeDescriptor("-pipe");
- renderModeDescriptor.append(gPipeWritingFlagCombos[i].name);
-
- if (gm->getFlags() & GM::kSkipPipe_Flag
- || (gPipeWritingFlagCombos[i].flags == SkGPipeWriter::kCrossProcess_Flag
- && gm->getFlags() & GM::kSkipPipeCrossProcess_Flag)) {
- RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
- renderModeDescriptor.c_str());
- errors.add(kIntentionallySkipped_ErrorType);
- } else {
- SkBitmap bitmap;
- SkISize size = gm->getISize();
- setup_bitmap(gRec, size, &bitmap);
- SkCanvas canvas(bitmap);
- InstallFilter(&canvas);
- // Pass a decoding function so the factory GM (which has an SkBitmap
- // with encoded data) will not fail playback.
- PipeController pipeController(&canvas, &SkImageDecoder::DecodeMemory);
- SkGPipeWriter writer;
- SkCanvas* pipeCanvas = writer.startRecording(&pipeController,
- gPipeWritingFlagCombos[i].flags,
- size.width(), size.height());
- if (!simulateFailure) {
- invokeGM(gm, pipeCanvas, false, false);
- }
- complete_bitmap(&bitmap);
- writer.endRecording();
- errors.add(compare_test_results_to_reference_bitmap(
- gm->getName(), gRec.fName, renderModeDescriptor.c_str(), bitmap,
- &referenceBitmap));
- if (!errors.isEmpty()) {
- break;
- }
- }
- }
- return errors;
- }
-
- ErrorCombination test_tiled_pipe_playback(GM* gm, const ConfigData& gRec,
- const SkBitmap& referenceBitmap) {
- const SkString shortNamePlusConfig = make_shortname_plus_config(gm->getName(),
- gRec.fName);
- ErrorCombination errors;
- for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) {
- SkString renderModeDescriptor("-tiled pipe");
- renderModeDescriptor.append(gPipeWritingFlagCombos[i].name);
-
- if ((gm->getFlags() & GM::kSkipPipe_Flag) ||
- (gm->getFlags() & GM::kSkipTiled_Flag)) {
- RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
- renderModeDescriptor.c_str());
- errors.add(kIntentionallySkipped_ErrorType);
- } else {
- SkBitmap bitmap;
- SkISize size = gm->getISize();
- setup_bitmap(gRec, size, &bitmap);
- SkCanvas canvas(bitmap);
- InstallFilter(&canvas);
- TiledPipeController pipeController(bitmap, &SkImageDecoder::DecodeMemory);
- SkGPipeWriter writer;
- SkCanvas* pipeCanvas = writer.startRecording(&pipeController,
- gPipeWritingFlagCombos[i].flags,
- size.width(), size.height());
- invokeGM(gm, pipeCanvas, false, false);
- complete_bitmap(&bitmap);
- writer.endRecording();
- errors.add(compare_test_results_to_reference_bitmap(gm->getName(), gRec.fName,
- renderModeDescriptor.c_str(),
- bitmap, &referenceBitmap));
- if (!errors.isEmpty()) {
- break;
- }
- }
- }
- return errors;
- }
-
- //
- // member variables.
- // They are public for now, to allow easier setting by tool_main().
- //
-
- bool fUseFileHierarchy, fWriteChecksumBasedFilenames;
- ErrorCombination fIgnorableErrorTypes;
- SkTArray<SkString> fIgnorableTestNames;
-
- const char* fMismatchPath;
- const char* fMissingExpectationsPath;
-
- // collection of tests that have failed with each ErrorType
- SkTArray<SkString> fFailedTests[kLast_ErrorType+1];
- SkTArray<SkString> fTestsSkippedOnAllRenderModes;
- int fTestsRun;
- SkTDict<int> fRenderModesEncountered;
-
- // Where to read expectations (expected image hash digests, etc.) from.
- // If unset, we don't do comparisons.
- SkAutoTUnref<ExpectationsSource> fExpectationsSource;
-
- // JSON summaries that we generate as we go (just for output).
- Json::Value fJsonExpectedResults;
- Json::Value fJsonActualResults_Failed;
- Json::Value fJsonActualResults_FailureIgnored;
- Json::Value fJsonActualResults_NoComparison;
- Json::Value fJsonActualResults_Succeeded;
-}; // end of GMMain class definition
-
-#if SK_SUPPORT_GPU
-static const GLContextType kDontCare_GLContextType = GrContextFactory::kNative_GLContextType;
-#else
-static const GLContextType kDontCare_GLContextType = 0;
-#endif
-
-static const ConfigData gRec[] = {
- { kN32_SkColorType, kRaster_Backend, kDontCare_GLContextType, 0, kRW_ConfigFlag, "8888", true },
- { kRGB_565_SkColorType, kRaster_Backend, kDontCare_GLContextType, 0, kRW_ConfigFlag, "565", true },
-#if SK_SUPPORT_GPU
- { kN32_SkColorType, kGPU_Backend, GrContextFactory::kNative_GLContextType, 0, kRW_ConfigFlag, "gpu", true },
- { kN32_SkColorType, kGPU_Backend, GrContextFactory::kNative_GLContextType, 16, kRW_ConfigFlag, "msaa16", false},
- { kN32_SkColorType, kGPU_Backend, GrContextFactory::kNative_GLContextType, 4, kRW_ConfigFlag, "msaa4", false},
- { kN32_SkColorType, kGPU_Backend, GrContextFactory::kNVPR_GLContextType, 4, kRW_ConfigFlag, "nvprmsaa4", true },
- { kN32_SkColorType, kGPU_Backend, GrContextFactory::kNVPR_GLContextType, 16, kRW_ConfigFlag, "nvprmsaa16", false},
- /* Not quite ready to turn on distance field text baselines */
- { kN32_SkColorType, kGPU_Backend, GrContextFactory::kNative_GLContextType, 0, kRWDFT_ConfigFlag, "gpudft", false },
- /* The gpudebug context does not generate meaningful images, so don't record
- * the images it generates! We only run it to look for asserts. */
- { kN32_SkColorType, kGPU_Backend, GrContextFactory::kDebug_GLContextType, 0, kNone_ConfigFlag, "gpudebug", kDebugOnly},
- /* The gpunull context does the least amount of work possible and doesn't
- generate meaninful images, so don't record them!. It can be run to
- isolate the CPU-side processing expense from the GPU-side.
- */
- { kN32_SkColorType, kGPU_Backend, GrContextFactory::kNull_GLContextType, 0, kNone_ConfigFlag, "gpunull", kDebugOnly},
-#if SK_ANGLE
- { kN32_SkColorType, kGPU_Backend, GrContextFactory::kANGLE_GLContextType, 0, kRW_ConfigFlag, "angle", true },
- { kN32_SkColorType, kGPU_Backend, GrContextFactory::kANGLE_GLContextType, 16, kRW_ConfigFlag, "anglemsaa16", true },
-#endif // SK_ANGLE
-#ifdef SK_MESA
- { kN32_SkColorType, kGPU_Backend, GrContextFactory::kMESA_GLContextType, 0, kRW_ConfigFlag, "mesa", true },
-#endif // SK_MESA
-#endif // SK_SUPPORT_GPU
-#ifdef SK_SUPPORT_XPS
- /* At present we have no way of comparing XPS files (either natively or by converting to PNG). */
- { kN32_SkColorType, kXPS_Backend, kDontCare_GLContextType, 0, kWrite_ConfigFlag, "xps", true },
-#endif // SK_SUPPORT_XPS
-#ifdef SK_SUPPORT_PDF
- { kN32_SkColorType, kPDF_Backend, kDontCare_GLContextType, 0, kRW_ConfigFlag, "pdf", true },
-#endif // SK_SUPPORT_PDF
-};
-
-static bool SkNoRasterizePDF(SkStream*, SkBitmap*) { return false; }
-
-static const PDFRasterizerData kPDFRasterizers[] = {
-#ifdef SK_BUILD_FOR_MAC
- { &SkPDFDocumentToBitmap, "mac", true },
-#endif
-#ifdef SK_BUILD_POPPLER
- { &SkPopplerRasterizePDF, "poppler", true },
-#endif
-#ifdef SK_BUILD_NATIVE_PDF_RENDERER
- { &SkNativeRasterizePDF, "native", true },
-#endif // SK_BUILD_NATIVE_PDF_RENDERER
- // The following exists so that this array is never zero length.
- { &SkNoRasterizePDF, "none", false},
-};
-
-static const char kDefaultsConfigStr[] = "defaults";
-static const char kExcludeConfigChar = '~';
-#if SK_SUPPORT_GPU
-static const char kGpuAPINameGL[] = "gl";
-static const char kGpuAPINameGLES[] = "gles";
-#endif
-
-static SkString configUsage() {
- SkString result;
- result.appendf("Space delimited list of which configs to run. Possible options: [");
- for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
- SkASSERT(gRec[i].fName != kDefaultsConfigStr);
- if (i > 0) {
- result.append("|");
- }
- result.appendf("%s", gRec[i].fName);
- }
- result.append("]\n");
- result.appendf("The default value is: \"");
- SkString firstDefault;
- SkString allButFirstDefaults;
- SkString nonDefault;
- for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
- if (gRec[i].fRunByDefault) {
- if (i > 0) {
- result.append(" ");
- }
- result.append(gRec[i].fName);
- if (firstDefault.isEmpty()) {
- firstDefault = gRec[i].fName;
- } else {
- if (!allButFirstDefaults.isEmpty()) {
- allButFirstDefaults.append(" ");
- }
- allButFirstDefaults.append(gRec[i].fName);
- }
- } else {
- nonDefault = gRec[i].fName;
- }
- }
- result.append("\"\n");
- result.appendf("\"%s\" evaluates to the default set of configs.\n", kDefaultsConfigStr);
- result.appendf("Prepending \"%c\" on a config name excludes it from the set of configs to run.\n"
- "Exclusions always override inclusions regardless of order.\n",
- kExcludeConfigChar);
- result.appendf("E.g. \"--config %s %c%s %s\" will run these configs:\n\t%s %s",
- kDefaultsConfigStr,
- kExcludeConfigChar,
- firstDefault.c_str(),
- nonDefault.c_str(),
- allButFirstDefaults.c_str(),
- nonDefault.c_str());
- return result;
-}
-
-static SkString pdfRasterizerUsage() {
- SkString result;
- result.appendf("Space delimited list of which PDF rasterizers to run. Possible options: [");
- // For this (and further) loops through kPDFRasterizers, there is a typecast to int to avoid
- // the compiler giving an "comparison of unsigned expression < 0 is always false" warning
- // and turning it into a build-breaking error.
- for (int i = 0; i < (int)SK_ARRAY_COUNT(kPDFRasterizers); ++i) {
- if (i > 0) {
- result.append(" ");
- }
- result.append(kPDFRasterizers[i].fName);
- }
- result.append("]\n");
- result.append("The default value is: \"");
- for (int i = 0; i < (int)SK_ARRAY_COUNT(kPDFRasterizers); ++i) {
- if (kPDFRasterizers[i].fRunByDefault) {
- if (i > 0) {
- result.append(" ");
- }
- result.append(kPDFRasterizers[i].fName);
- }
- }
- result.append("\"");
- return result;
-}
-
-// Macro magic to convert a numeric preprocessor token into a string.
-// Adapted from http://stackoverflow.com/questions/240353/convert-a-preprocessor-token-to-a-string
-// This should probably be moved into one of our common headers...
-#define TOSTRING_INTERNAL(x) #x
-#define TOSTRING(x) TOSTRING_INTERNAL(x)
-
-// Alphabetized ignoring "no" prefix ("readPath", "noreplay", "resourcePath").
-DEFINE_string(config, "", configUsage().c_str());
-DEFINE_bool(cpu, true, "Allows non-GPU configs to be run. Applied after --config.");
-DEFINE_string(pdfRasterizers, "default", pdfRasterizerUsage().c_str());
-DEFINE_bool(deferred, false, "Exercise the deferred rendering test pass.");
-DEFINE_bool(mpd, false, "Exercise MultiPictureDraw.");
-
-DEFINE_bool(dryRun, false, "Don't actually run the tests, just print what would have been done.");
-DEFINE_string(excludeConfig, "", "Space delimited list of configs to skip.");
-DEFINE_bool(forceBWtext, false, "Disable text anti-aliasing.");
-#if SK_SUPPORT_GPU
-DEFINE_string(gpuAPI, "", "Force use of specific gpu API. Using \"gl\" "
- "forces OpenGL API. Using \"gles\" forces OpenGL ES API. "
- "Defaults to empty string, which selects the API native to the "
- "system.");
-DEFINE_string(gpuCacheSize, "", "<bytes> <count>: Limit the gpu cache to byte size or "
- "object count. " TOSTRING(DEFAULT_CACHE_VALUE) " for either value means "
- "use the default. 0 for either disables the cache.");
-DEFINE_bool(gpu, true, "Allows GPU configs to be run. Applied after --config.");
-DEFINE_bool(gpuCompressAlphaMasks, false, "Compress masks generated from falling back to "
- "software path rendering.");
-#endif
-DEFINE_bool(hierarchy, false, "Whether to use multilevel directory structure "
- "when reading/writing files.");
-DEFINE_string(ignoreErrorTypes, kDefaultIgnorableErrorTypes.asString(" ").c_str(),
- "Space-separated list of ErrorTypes that should be ignored. If any *other* error "
- "types are encountered, the tool will exit with a nonzero return value.");
-DEFINE_string(ignoreFailuresFile, "", "Path to file containing a list of tests for which we "
- "should ignore failures.\n"
- "The file should list one test per line, except for comment lines starting with #");
-DEFINE_bool2(leaks, l, false, "show leaked ref cnt'd objects.");
-DEFINE_string(match, "", "[~][^]substring[$] [...] of test name to run.\n"
- "Multiple matches may be separated by spaces.\n"
- "~ causes a matching test to always be skipped\n"
- "^ requires the start of the test to match\n"
- "$ requires the end of the test to match\n"
- "^ and $ requires an exact match\n"
- "If a test does not match any list entry,\n"
- "it is skipped unless some list entry starts with ~");
-DEFINE_string(missingExpectationsPath, "", "Write images for tests without expectations "
- "into this directory.");
-DEFINE_string(mismatchPath, "", "Write images for tests that failed due to "
- "pixel mismatches into this directory.");
-DEFINE_string(modulo, "", "[--modulo <remainder> <divisor>]: only run tests for which "
- "testIndex %% divisor == remainder.");
-DEFINE_bool(pipe, false, "Exercise the SkGPipe replay test pass.");
-DEFINE_string2(readPath, r, "", "Read reference images from this dir, and report "
- "any differences between those and the newly generated ones.");
-DEFINE_bool(replay, false, "Exercise the SkPicture replay test pass.");
-
-#ifdef SK_BUILD_FOR_ANDROID
-DEFINE_bool(resetGpuContext, true, "Reset the GrContext prior to running each GM.");
-#else
-DEFINE_bool(resetGpuContext, false, "Reset the GrContext prior to running each GM.");
-#endif
-
-DEFINE_bool(rtree, false, "Exercise the R-Tree variant of SkPicture test pass.");
-DEFINE_bool(serialize, false, "Exercise the SkPicture serialization & deserialization test pass.");
-DEFINE_bool(simulatePipePlaybackFailure, false, "Simulate a rendering failure in pipe mode only.");
-DEFINE_bool(tiledPipe, false, "Exercise tiled SkGPipe replay.");
-DEFINE_bool(tileGrid, false, "Exercise the tile grid variant of SkPicture.");
-DEFINE_string(tileGridReplayScales, "", "Space separated list of floating-point scale "
- "factors to be used for tileGrid playback testing. Default value: 1.0");
-DEFINE_bool2(verbose, v, false, "Give more detail (e.g. list all GMs run, more info about "
- "each test).");
-DEFINE_bool(writeChecksumBasedFilenames, false, "When writing out actual images, use checksum-"
- "based filenames, as rebaseline.py will use when downloading them from Google Storage");
-DEFINE_string(writeJsonSummaryPath, "", "Write a JSON-formatted result summary to this file.");
-DEFINE_string2(writePath, w, "", "Write rendered images into this directory.");
-DEFINE_string2(writePicturePath, p, "", "Write .skp files into this directory.");
-DEFINE_int32(pdfJpegQuality, -1, "Encodes images in JPEG at quality level N, "
- "which can be in range 0-100). N = -1 will disable JPEG compression. "
- "Default is N = 100, maximum quality.");
-// TODO(edisonn): pass a matrix instead of forcePerspectiveMatrix
-// Either the 9 numbers defining the matrix
-// or probably more readable would be to replace it with a set of a few predicates
-// Like --prerotate 100 200 10 --posttranslate 10, 10
-// Probably define spacial names like centerx, centery, top, bottom, left, right
-// then we can write something reabable like --rotate centerx centery 90
-DEFINE_bool(forcePerspectiveMatrix, false, "Force a perspective matrix.");
-DEFINE_bool(useDocumentInsteadOfDevice, false, "Use SkDocument::CreateFoo instead of SkFooDevice.");
-DEFINE_int32(pdfRasterDpi, 72, "Scale at which at which the non suported "
- "features in PDF are rasterized. Must be be in range 0-10000. "
- "Default is 72. N = 0 will disable rasterizing features like "
- "text shadows or perspective bitmaps.");
-static SkData* encode_to_dct_data(size_t*, const SkBitmap& bitmap) {
- // Filter output of warnings that JPEG is not available for the image.
- if (bitmap.width() >= 65500 || bitmap.height() >= 65500) return NULL;
- if (FLAGS_pdfJpegQuality == -1) return NULL;
-
- SkBitmap bm = bitmap;
-#if defined(SK_BUILD_FOR_MAC)
- // Workaround bug #1043 where bitmaps with referenced pixels cause
- // CGImageDestinationFinalize to crash
- SkBitmap copy;
- bitmap.deepCopyTo(&copy);
- bm = copy;
-#endif
-
- SkPixelRef* pr = bm.pixelRef();
- if (pr != NULL) {
- SkData* data = pr->refEncodedData();
- if (data != NULL) {
- return data;
- }
- }
-
- return SkImageEncoder::EncodeData(bm,
- SkImageEncoder::kJPEG_Type,
- FLAGS_pdfJpegQuality);
-}
-
-static int findConfig(const char config[]) {
- for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
- if (!strcmp(config, gRec[i].fName)) {
- return (int) i;
- }
- }
- return -1;
-}
-
-static const PDFRasterizerData* findPDFRasterizer(const char rasterizer[]) {
- for (int i = 0; i < (int)SK_ARRAY_COUNT(kPDFRasterizers); i++) {
- if (!strcmp(rasterizer, kPDFRasterizers[i].fName)) {
- return &kPDFRasterizers[i];
- }
- }
- return NULL;
-}
-
-template <typename T> void appendUnique(SkTDArray<T>* array, const T& value) {
- int index = array->find(value);
- if (index < 0) {
- *array->append() = value;
- }
-}
-
-/**
- * Run this test in a number of different drawing modes (pipe,
- * deferred, tiled, etc.), confirming that the resulting bitmaps all
- * *exactly* match comparisonBitmap.
- *
- * Returns all errors encountered while doing so.
- */
-ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm,
- const ConfigData &compareConfig, GrSurface* gpuTarget,
- const SkBitmap &comparisonBitmap,
- const SkTDArray<SkScalar> &tileGridReplayScales);
-ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm,
- const ConfigData &compareConfig, GrSurface* gpuTarget,
- const SkBitmap &comparisonBitmap,
- const SkTDArray<SkScalar> &tileGridReplayScales) {
- ErrorCombination errorsForAllModes;
- uint32_t gmFlags = gm->getFlags();
- const SkString shortNamePlusConfig = gmmain.make_shortname_plus_config(gm->getName(),
- compareConfig.fName);
-
- SkPicture* pict = gmmain.generate_new_picture(gm, kNone_BbhType, 0);
- SkAutoTUnref<SkPicture> aur(pict);
- if (FLAGS_replay) {
- const char renderModeDescriptor[] = "-replay";
- if (gmFlags & GM::kSkipPicture_Flag) {
- gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
- renderModeDescriptor);
- errorsForAllModes.add(kIntentionallySkipped_ErrorType);
- } else {
- SkBitmap bitmap;
- gmmain.generate_image_from_picture(gm, compareConfig, gpuTarget, pict, &bitmap);
-
- errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
- gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap,
- &comparisonBitmap));
- }
- }
-
- if (FLAGS_serialize) {
- const char renderModeDescriptor[] = "-serialize";
- if (gmFlags & GM::kSkipPicture_Flag) {
- gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
- renderModeDescriptor);
- errorsForAllModes.add(kIntentionallySkipped_ErrorType);
- } else {
- SkPicture* repict = gmmain.stream_to_new_picture(*pict);
- SkAutoTUnref<SkPicture> aurr(repict);
- SkBitmap bitmap;
- gmmain.generate_image_from_picture(gm, compareConfig, gpuTarget, repict, &bitmap);
- errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
- gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap,
- &comparisonBitmap));
- }
- }
-
- if ((1 == FLAGS_writePicturePath.count()) &&
- !(gmFlags & GM::kSkipPicture_Flag)) {
- const char* pictureSuffix = "skp";
- // TODO(epoger): Make sure this still works even though the
- // filename now contains the config name (it used to contain
- // just the shortName). I think this is actually an
- // *improvement*, because now runs with different configs will
- // write out their SkPictures to separate files rather than
- // overwriting each other. But we should make sure it doesn't
- // break anybody.
- SkString path = gmmain.make_filename(FLAGS_writePicturePath[0], gm->getName(),
- compareConfig.fName, "", pictureSuffix);
- SkFILEWStream stream(path.c_str());
- pict->serialize(&stream);
- }
-
- if (FLAGS_rtree) {
- const char renderModeDescriptor[] = "-rtree";
- if ((gmFlags & GM::kSkipPicture_Flag) || (gmFlags & GM::kSkipTiled_Flag)) {
- gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
- renderModeDescriptor);
- errorsForAllModes.add(kIntentionallySkipped_ErrorType);
- } else {
- SkPicture* pict = gmmain.generate_new_picture(gm, kRTree_BbhType, 0);
- SkAutoTUnref<SkPicture> aur(pict);
- SkBitmap bitmap;
- gmmain.generate_image_from_picture(gm, compareConfig, gpuTarget, pict, &bitmap);
- errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
- gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap,
- &comparisonBitmap));
- }
- }
-
- // run the pipe centric GM steps
- if (FLAGS_pipe) {
- errorsForAllModes.add(gmmain.test_pipe_playback(gm, compareConfig, comparisonBitmap,
- FLAGS_simulatePipePlaybackFailure));
- if (FLAGS_tiledPipe) {
- errorsForAllModes.add(gmmain.test_tiled_pipe_playback(gm, compareConfig,
- comparisonBitmap));
- }
- }
- return errorsForAllModes;
-}
-
-
-/**
- * Run this test in a number of different configs (8888, 565, PDF,
- * etc.), confirming that the resulting bitmaps match expectations
- * (which may be different for each config).
- *
- * Returns all errors encountered while doing so.
- */
-ErrorCombination run_multiple_configs(GMMain &gmmain, GM *gm,
- const SkTDArray<size_t> &configs,
- const SkTDArray<const PDFRasterizerData*> &pdfRasterizers,
- const SkTDArray<SkScalar> &tileGridReplayScales,
- GrContextFactory *grFactory,
- GrGLStandard gpuAPI);
-ErrorCombination run_multiple_configs(GMMain &gmmain, GM *gm,
- const SkTDArray<size_t> &configs,
- const SkTDArray<const PDFRasterizerData*> &pdfRasterizers,
- const SkTDArray<SkScalar> &tileGridReplayScales,
- GrContextFactory *grFactory,
- GrGLStandard gpuAPI) {
- const char renderModeDescriptor[] = "";
- ErrorCombination errorsForAllConfigs;
- uint32_t gmFlags = gm->getFlags();
-
- for (int i = 0; i < configs.count(); i++) {
- ConfigData config = gRec[configs[i]];
- const SkString shortNamePlusConfig = gmmain.make_shortname_plus_config(gm->getName(),
- config.fName);
-
- // Skip any tests that we don't even need to try.
- // If any of these were skipped on a per-GM basis, record them as
- // kIntentionallySkipped.
- if (kPDF_Backend == config.fBackend) {
- if (gmFlags & GM::kSkipPDF_Flag) {
- gmmain.RecordSkippedTest(shortNamePlusConfig,
- renderModeDescriptor,
- config.fBackend);
- errorsForAllConfigs.add(kIntentionallySkipped_ErrorType);
- continue;
- }
- }
- if ((gmFlags & GM::kSkip565_Flag) &&
- (kRaster_Backend == config.fBackend) &&
- (kRGB_565_SkColorType == config.fColorType)) {
- gmmain.RecordSkippedTest(shortNamePlusConfig,
- renderModeDescriptor,
- config.fBackend);
- errorsForAllConfigs.add(kIntentionallySkipped_ErrorType);
- continue;
- }
- if (((gmFlags & GM::kSkipGPU_Flag) && kGPU_Backend == config.fBackend) ||
- ((gmFlags & GM::kGPUOnly_Flag) && kGPU_Backend != config.fBackend)) {
- gmmain.RecordSkippedTest(shortNamePlusConfig,
- renderModeDescriptor,
- config.fBackend);
- errorsForAllConfigs.add(kIntentionallySkipped_ErrorType);
- continue;
- }
-
- // Now we know that we want to run this test and record its
- // success or failure.
- ErrorCombination errorsForThisConfig;
- GrSurface* gpuTarget = NULL;
-#if SK_SUPPORT_GPU
- SkAutoTUnref<GrSurface> auGpuTarget;
- if ((errorsForThisConfig.isEmpty()) && (kGPU_Backend == config.fBackend)) {
- if (FLAGS_resetGpuContext) {
- grFactory->destroyContexts();
- }
- GrContext* gr = grFactory->get(config.fGLContextType, gpuAPI);
- bool grSuccess = false;
- if (gr) {
- // create a render target to back the device
- GrSurfaceDesc desc;
- desc.fConfig = kSkia8888_GrPixelConfig;
- desc.fFlags = kRenderTarget_GrSurfaceFlag;
- desc.fWidth = gm->getISize().width();
- desc.fHeight = gm->getISize().height();
- desc.fSampleCnt = config.fSampleCnt;
- auGpuTarget.reset(gr->createUncachedTexture(desc, NULL, 0));
- if (auGpuTarget) {
- gpuTarget = auGpuTarget;
- grSuccess = true;
- // Set the user specified cache limits if non-default.
- size_t bytes;
- int count;
- gr->getResourceCacheLimits(&count, &bytes);
- if (DEFAULT_CACHE_VALUE != gGpuCacheSizeBytes) {
- bytes = static_cast<size_t>(gGpuCacheSizeBytes);
- }
- if (DEFAULT_CACHE_VALUE != gGpuCacheSizeCount) {
- count = gGpuCacheSizeCount;
- }
- gr->setResourceCacheLimits(count, bytes);
- }
- }
- if (!grSuccess) {
- errorsForThisConfig.add(kNoGpuContext_ErrorType);
- }
- }
-#endif
-
- SkBitmap comparisonBitmap;
-
- const char* writePath;
- if (FLAGS_writePath.count() == 1) {
- writePath = FLAGS_writePath[0];
- } else {
- writePath = NULL;
- }
-
- if (errorsForThisConfig.isEmpty()) {
- errorsForThisConfig.add(gmmain.test_drawing(gm, config, pdfRasterizers,
- writePath, gpuTarget,
- &comparisonBitmap));
- gmmain.RecordTestResults(errorsForThisConfig, shortNamePlusConfig, "");
- }
-
- // TODO: run only if gmmain.test_drawing succeeded.
- if (kRaster_Backend == config.fBackend) {
- run_multiple_modes(gmmain, gm, config, gpuTarget, comparisonBitmap, tileGridReplayScales);
- }
-
- if (FLAGS_deferred && errorsForThisConfig.isEmpty() &&
- (kGPU_Backend == config.fBackend || kRaster_Backend == config.fBackend)) {
- errorsForThisConfig.add(gmmain.test_deferred_drawing(gm, config, comparisonBitmap,
- gpuTarget));
- }
-
- if (FLAGS_mpd && (kGPU_Backend == config.fBackend || kRaster_Backend == config.fBackend)) {
-
- if (gmFlags & GM::kSkipPicture_Flag) {
- gmmain.RecordSkippedTest(shortNamePlusConfig,
- renderModeDescriptor,
- config.fBackend);
- errorsForThisConfig.add(kIntentionallySkipped_ErrorType);
- } else if (!(gmFlags & GM::kGPUOnly_Flag)) {
- errorsForThisConfig.add(gmmain.testMPDDrawing(gm, config,
- writePath, gpuTarget,
- comparisonBitmap));
- }
- }
-
- errorsForAllConfigs.add(errorsForThisConfig);
- }
- return errorsForAllConfigs;
-}
-
-
-/**
- * Read individual lines from a file, pushing them into the given array.
- *
- * @param filename path to the file to read
- * @param lines array of strings to add the lines to
- * @returns true if able to read lines from the file
- */
-static bool read_lines_from_file(const char* filename, SkTArray<SkString> &lines) {
- SkAutoTUnref<SkStream> streamWrapper(SkStream::NewFromFile(filename));
- SkStream *stream = streamWrapper.get();
- if (!stream) {
- SkDebugf("unable to read file '%s'\n", filename);
- return false;
- }
-
- char c;
- SkString line;
- while (1 == stream->read(&c, 1)) {
- // If we hit either CR or LF, we've completed a line.
- //
- // TODO: If the file uses both CR and LF, this will return an extra blank
- // line for each line of the file. Which is OK for current purposes...
- //
- // TODO: Does this properly handle unicode? It doesn't matter for
- // current purposes...
- if ((c == 0x0d) || (c == 0x0a)) {
- lines.push_back(line);
- line.reset();
- } else {
- line.append(&c, 1);
- }
- }
- lines.push_back(line);
- return true;
-}
-
-/**
- * Return a list of all entries in an array of strings as a single string
- * of this form:
- * "item1", "item2", "item3"
- */
-SkString list_all(const SkTArray<SkString> &stringArray);
-SkString list_all(const SkTArray<SkString> &stringArray) {
- SkString total;
- for (int i = 0; i < stringArray.count(); i++) {
- if (i > 0) {
- total.append(", ");
- }
- total.append("\"");
- total.append(stringArray[i]);
- total.append("\"");
- }
- return total;
-}
-
-/**
- * Return a list of configuration names, as a single string of this form:
- * "item1", "item2", "item3"
- *
- * @param configs configurations, as a list of indices into gRec
- */
-SkString list_all_config_names(const SkTDArray<size_t> &configs);
-SkString list_all_config_names(const SkTDArray<size_t> &configs) {
- SkString total;
- for (int i = 0; i < configs.count(); i++) {
- if (i > 0) {
- total.append(", ");
- }
- total.append("\"");
- total.append(gRec[configs[i]].fName);
- total.append("\"");
- }
- return total;
-}
-
-static bool prepare_subdirectories(const char *root, bool useFileHierarchy,
- const SkTDArray<size_t> &configs,
- const SkTDArray<const PDFRasterizerData*>& pdfRasterizers) {
- if (!sk_mkdir(root)) {
- return false;
- }
- if (useFileHierarchy) {
- for (int i = 0; i < configs.count(); i++) {
- ConfigData config = gRec[configs[i]];
- SkString subdir;
- subdir.appendf("%s%c%s", root, SkPATH_SEPARATOR, config.fName);
- if (!sk_mkdir(subdir.c_str())) {
- return false;
- }
-
- if (config.fBackend == kPDF_Backend) {
- for (int j = 0; j < pdfRasterizers.count(); j++) {
- SkString pdfSubdir = subdir;
- pdfSubdir.appendf("-%s", pdfRasterizers[j]->fName);
- if (!sk_mkdir(pdfSubdir.c_str())) {
- return false;
- }
- }
- }
- }
- }
- return true;
-}
-
-static bool parse_flags_configs(SkTDArray<size_t>* outConfigs,
- GrContextFactory* grFactory, GrGLStandard gpuAPI) {
- SkTDArray<size_t> excludeConfigs;
-
- for (int i = 0; i < FLAGS_config.count(); i++) {
- const char* config = FLAGS_config[i];
- bool exclude = false;
- if (*config == kExcludeConfigChar) {
- exclude = true;
- config += 1;
- }
- int index = findConfig(config);
- if (index >= 0) {
- if (exclude) {
- *excludeConfigs.append() = index;
- } else {
- appendUnique<size_t>(outConfigs, index);
- }
- } else if (0 == strcmp(kDefaultsConfigStr, config)) {
- if (exclude) {
- SkDebugf("%c%s is not allowed.\n",
- kExcludeConfigChar, kDefaultsConfigStr);
- return false;
- }
- for (size_t c = 0; c < SK_ARRAY_COUNT(gRec); ++c) {
- if (gRec[c].fRunByDefault) {
- appendUnique<size_t>(outConfigs, c);
- }
- }
- } else {
- SkDebugf("unrecognized config %s\n", config);
- return false;
- }
- }
-
- for (int i = 0; i < FLAGS_excludeConfig.count(); i++) {
- int index = findConfig(FLAGS_excludeConfig[i]);
- if (index >= 0) {
- *excludeConfigs.append() = index;
- } else {
- SkDebugf("unrecognized excludeConfig %s\n", FLAGS_excludeConfig[i]);
- return false;
- }
- }
-
- if (outConfigs->count() == 0) {
- // if no config is specified by user, add the defaults
- for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
- if (gRec[i].fRunByDefault) {
- *outConfigs->append() = i;
- }
- }
- }
- // now remove any explicitly excluded configs
- for (int i = 0; i < excludeConfigs.count(); ++i) {
- int index = outConfigs->find(excludeConfigs[i]);
- if (index >= 0) {
- outConfigs->remove(index);
- // now assert that there was only one copy in configs[]
- SkASSERT(outConfigs->find(excludeConfigs[i]) < 0);
- }
- }
-
- for (int i = 0; i < outConfigs->count(); ++i) {
- size_t index = (*outConfigs)[i];
- if (kGPU_Backend == gRec[index].fBackend) {
-#if SK_SUPPORT_GPU
- if (!FLAGS_gpu) {
- outConfigs->remove(i);
- --i;
- continue;
- }
-#endif
- } else if (!FLAGS_cpu) {
- outConfigs->remove(i);
- --i;
- continue;
- }
-#if SK_SUPPORT_GPU
- SkASSERT(grFactory != NULL);
- if (kGPU_Backend == gRec[index].fBackend) {
- GrContext* ctx = grFactory->get(gRec[index].fGLContextType, gpuAPI);
- if (NULL == ctx) {
- SkDebugf("GrContext could not be created for config %s. Config will be skipped.\n",
- gRec[index].fName);
- outConfigs->remove(i);
- --i;
- continue;
- }
- if (gRec[index].fSampleCnt > ctx->getMaxSampleCount()) {
- SkDebugf("Sample count (%d) of config %s is not supported."
- " Config will be skipped.\n",
- gRec[index].fSampleCnt, gRec[index].fName);
- outConfigs->remove(i);
- --i;
- }
- }
-#endif
- }
-
- if (outConfigs->isEmpty()) {
- SkDebugf("No configs to run.");
- return false;
- }
-
- // now show the user the set of configs that will be run.
- SkString configStr("These configs will be run:");
- // show the user the config that will run.
- for (int i = 0; i < outConfigs->count(); ++i) {
- configStr.appendf(" %s", gRec[(*outConfigs)[i]].fName);
- }
- SkDebugf("%s\n", configStr.c_str());
-
- return true;
-}
-
-static bool parse_flags_pdf_rasterizers(const SkTDArray<size_t>& configs,
- SkTDArray<const PDFRasterizerData*>* outRasterizers) {
- // No need to run this check (and display the PDF rasterizers message)
- // if no PDF backends are in the configs.
- bool configHasPDF = false;
- for (int i = 0; i < configs.count(); i++) {
- if (gRec[configs[i]].fBackend == kPDF_Backend) {
- configHasPDF = true;
- break;
- }
- }
- if (!configHasPDF) {
- return true;
- }
-
- if (FLAGS_pdfRasterizers.count() == 1 &&
- !strcmp(FLAGS_pdfRasterizers[0], "default")) {
- for (int i = 0; i < (int)SK_ARRAY_COUNT(kPDFRasterizers); ++i) {
- if (kPDFRasterizers[i].fRunByDefault) {
- *outRasterizers->append() = &kPDFRasterizers[i];
- }
- }
- } else {
- for (int i = 0; i < FLAGS_pdfRasterizers.count(); i++) {
- const char* rasterizer = FLAGS_pdfRasterizers[i];
- const PDFRasterizerData* rasterizerPtr =
- findPDFRasterizer(rasterizer);
- if (rasterizerPtr == NULL) {
- SkDebugf("unrecognized rasterizer %s\n", rasterizer);
- return false;
- }
- appendUnique<const PDFRasterizerData*>(outRasterizers,
- rasterizerPtr);
- }
- }
-
- // now show the user the set of configs that will be run.
- SkString configStr("These PDF rasterizers will be run:");
- // show the user the config that will run.
- for (int i = 0; i < outRasterizers->count(); ++i) {
- configStr.appendf(" %s", (*outRasterizers)[i]->fName);
- }
- SkDebugf("%s\n", configStr.c_str());
-
- return true;
-}
-
-static bool parse_flags_ignore_error_types(ErrorCombination* outErrorTypes) {
- if (FLAGS_ignoreErrorTypes.count() > 0) {
- *outErrorTypes = ErrorCombination();
- for (int i = 0; i < FLAGS_ignoreErrorTypes.count(); i++) {
- ErrorType type;
- const char *name = FLAGS_ignoreErrorTypes[i];
- if (!getErrorTypeByName(name, &type)) {
- SkDebugf("cannot find ErrorType with name '%s'\n", name);
- return false;
- } else {
- outErrorTypes->add(type);
- }
- }
- }
- return true;
-}
-
-/**
- * Replace contents of ignoreTestNames with a list of test names, indicating
- * which tests' failures should be ignored.
- */
-static bool parse_flags_ignore_tests(SkTArray<SkString> &ignoreTestNames) {
- ignoreTestNames.reset();
-
- // Parse --ignoreFailuresFile
- for (int i = 0; i < FLAGS_ignoreFailuresFile.count(); i++) {
- SkTArray<SkString> linesFromFile;
- if (!read_lines_from_file(FLAGS_ignoreFailuresFile[i], linesFromFile)) {
- return false;
- } else {
- for (int j = 0; j < linesFromFile.count(); j++) {
- SkString thisLine = linesFromFile[j];
- if (thisLine.isEmpty() || thisLine.startsWith('#')) {
- // skip this line
- } else {
- ignoreTestNames.push_back(thisLine);
- }
- }
- }
- }
-
- return true;
-}
-
-static bool parse_flags_modulo(int* moduloRemainder, int* moduloDivisor) {
- if (FLAGS_modulo.count() == 2) {
- *moduloRemainder = atoi(FLAGS_modulo[0]);
- *moduloDivisor = atoi(FLAGS_modulo[1]);
- if (*moduloRemainder < 0 || *moduloDivisor <= 0 ||
- *moduloRemainder >= *moduloDivisor) {
- SkDebugf("invalid modulo values.");
- return false;
- }
- }
- return true;
-}
-
-#if SK_SUPPORT_GPU
-static bool parse_flags_gpu_cache(int* sizeBytes, int* sizeCount) {
- if (FLAGS_gpuCacheSize.count() > 0) {
- if (FLAGS_gpuCacheSize.count() != 2) {
- SkDebugf("--gpuCacheSize requires two arguments\n");
- return false;
- }
- *sizeBytes = atoi(FLAGS_gpuCacheSize[0]);
- *sizeCount = atoi(FLAGS_gpuCacheSize[1]);
- } else {
- *sizeBytes = DEFAULT_CACHE_VALUE;
- *sizeCount = DEFAULT_CACHE_VALUE;
- }
- return true;
-}
-
-static bool parse_flags_gl_standard(GrGLStandard* gpuAPI) {
- if (0 == FLAGS_gpuAPI.count()) {
- *gpuAPI = kNone_GrGLStandard;
- return true;
- }
- if (1 == FLAGS_gpuAPI.count()) {
- if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) {
- *gpuAPI = kGL_GrGLStandard;
- return true;
- }
- if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) {
- *gpuAPI = kGLES_GrGLStandard;
- return true;
- }
- }
- SkDebugf("--gpuAPI invalid api value");
- return false;
-}
-#endif
-
-static bool parse_flags_tile_grid_replay_scales(SkTDArray<SkScalar>* outScales) {
- *outScales->append() = SK_Scalar1; // By default only test at scale 1.0
- if (FLAGS_tileGridReplayScales.count() > 0) {
- outScales->reset();
- for (int i = 0; i < FLAGS_tileGridReplayScales.count(); i++) {
- double val = atof(FLAGS_tileGridReplayScales[i]);
- if (0 < val) {
- *outScales->append() = SkDoubleToScalar(val);
- }
- }
- if (0 == outScales->count()) {
- // Should have at least one scale
- SkDebugf("--tileGridReplayScales requires at least one scale.\n");
- return false;
- }
- }
- return true;
-}
-
-static bool parse_flags_gmmain_paths(GMMain* gmmain) {
- gmmain->fUseFileHierarchy = FLAGS_hierarchy;
- gmmain->fWriteChecksumBasedFilenames = FLAGS_writeChecksumBasedFilenames;
-
- if (FLAGS_mismatchPath.count() == 1) {
- gmmain->fMismatchPath = FLAGS_mismatchPath[0];
- }
-
- if (FLAGS_missingExpectationsPath.count() == 1) {
- gmmain->fMissingExpectationsPath = FLAGS_missingExpectationsPath[0];
- }
-
- if (FLAGS_readPath.count() == 1) {
- const char* readPath = FLAGS_readPath[0];
- if (!sk_exists(readPath)) {
- SkDebugf("readPath %s does not exist!\n", readPath);
- return false;
- }
- if (sk_isdir(readPath)) {
- if (FLAGS_verbose) {
- SkDebugf("reading from %s\n", readPath);
- }
- gmmain->fExpectationsSource.reset(SkNEW_ARGS(
- IndividualImageExpectationsSource, (readPath)));
- } else {
- if (FLAGS_verbose) {
- SkDebugf("reading expectations from JSON summary file %s\n", readPath);
- }
- gmmain->fExpectationsSource.reset(SkNEW_ARGS(JsonExpectationsSource, (readPath)));
- }
- }
- return true;
-}
-
-static bool parse_flags_jpeg_quality() {
- if (FLAGS_pdfJpegQuality < -1 || FLAGS_pdfJpegQuality > 100) {
- SkDebugf("%s\n", "pdfJpegQuality must be in [-1 .. 100] range.");
- return false;
- }
- return true;
-}
-
-int tool_main(int argc, char** argv);
-int tool_main(int argc, char** argv) {
- SetupCrashHandler();
-
- SkString usage;
- usage.printf("Run the golden master tests.\n");
- SkCommandLineFlags::SetUsage(usage.c_str());
- SkCommandLineFlags::Parse(argc, argv);
-
-#if SK_ENABLE_INST_COUNT
- if (FLAGS_leaks) {
- gPrintInstCount = true;
- }
-#endif
-
- SkAutoGraphics ag;
-
- setSystemPreferences();
- GMMain gmmain;
-
- SkTDArray<size_t> configs;
-
- int moduloRemainder = -1;
- int moduloDivisor = -1;
- SkTDArray<const PDFRasterizerData*> pdfRasterizers;
- SkTDArray<SkScalar> tileGridReplayScales;
-#if SK_SUPPORT_GPU
- GrGLStandard gpuAPI = kNone_GrGLStandard;
- GrContext::Options grContextOpts;
- grContextOpts.fDrawPathToCompressedTexture = FLAGS_gpuCompressAlphaMasks;
- GrContextFactory* grFactory = new GrContextFactory(grContextOpts);
-#else
- GrGLStandard gpuAPI = 0;
- GrContextFactory* grFactory = NULL;
-#endif
-
- if (FLAGS_dryRun) {
- SkDebugf( "Doing a dry run; no tests will actually be executed.\n");
- }
-
- if (!parse_flags_modulo(&moduloRemainder, &moduloDivisor) ||
- !parse_flags_ignore_error_types(&gmmain.fIgnorableErrorTypes) ||
- !parse_flags_ignore_tests(gmmain.fIgnorableTestNames) ||
-#if SK_SUPPORT_GPU
- !parse_flags_gpu_cache(&gGpuCacheSizeBytes, &gGpuCacheSizeCount) ||
- !parse_flags_gl_standard(&gpuAPI) ||
-#endif
- !parse_flags_tile_grid_replay_scales(&tileGridReplayScales) ||
- !parse_flags_jpeg_quality() ||
- !parse_flags_configs(&configs, grFactory, gpuAPI) ||
- !parse_flags_pdf_rasterizers(configs, &pdfRasterizers) ||
- !parse_flags_gmmain_paths(&gmmain)) {
- return -1;
- }
-
- if (FLAGS_verbose) {
- if (FLAGS_writePath.count() == 1) {
- SkDebugf("writing to %s\n", FLAGS_writePath[0]);
- }
- if (gmmain.fMismatchPath) {
- SkDebugf("writing mismatches to %s\n", gmmain.fMismatchPath);
- }
- if (gmmain.fMissingExpectationsPath) {
- SkDebugf("writing images without expectations to %s\n",
- gmmain.fMissingExpectationsPath);
- }
- if (FLAGS_writePicturePath.count() == 1) {
- SkDebugf("writing pictures to %s\n", FLAGS_writePicturePath[0]);
- }
- if (!GetResourcePath().isEmpty()) {
- SkDebugf("reading resources from %s\n", GetResourcePath().c_str());
- }
- }
-
- int gmsRun = 0;
- int gmIndex = -1;
- SkString moduloStr;
-
- if (!FLAGS_dryRun) {
- // If we will be writing out files, prepare subdirectories.
- if (FLAGS_writePath.count() == 1) {
- if (!prepare_subdirectories(FLAGS_writePath[0], gmmain.fUseFileHierarchy,
- configs, pdfRasterizers)) {
- return -1;
- }
- }
- if (gmmain.fMismatchPath) {
- if (!prepare_subdirectories(gmmain.fMismatchPath, gmmain.fUseFileHierarchy,
- configs, pdfRasterizers)) {
- return -1;
- }
- }
- if (gmmain.fMissingExpectationsPath) {
- if (!prepare_subdirectories(gmmain.fMissingExpectationsPath, gmmain.fUseFileHierarchy,
- configs, pdfRasterizers)) {
- return -1;
- }
- }
- }
- Iter iter;
- GM* gm;
- while ((gm = iter.next()) != NULL) {
- if (FLAGS_forcePerspectiveMatrix) {
- SkMatrix perspective;
- perspective.setIdentity();
- perspective.setPerspY(SkScalarDiv(SK_Scalar1, SkIntToScalar(1000)));
- perspective.setSkewX(SkScalarDiv(SkIntToScalar(8),
- SkIntToScalar(25)));
-
- gm->setStarterMatrix(perspective);
- }
- SkAutoTDelete<GM> adgm(gm);
- ++gmIndex;
- if (moduloRemainder >= 0) {
- if ((gmIndex % moduloDivisor) != moduloRemainder) {
- continue;
- }
- moduloStr.printf("[%d.%d] ", gmIndex, moduloDivisor);
- }
-
- const char* shortName = gm->getName();
-
- if (SkCommandLineFlags::ShouldSkip(FLAGS_match, shortName)) {
- continue;
- }
-
- gmsRun++;
- SkISize size = gm->getISize();
- SkDebugf("%4dM %sdrawing... %s [%d %d]\n",
- sk_tools::getMaxResidentSetSizeMB(), moduloStr.c_str(), shortName,
- size.width(), size.height());
- if (!FLAGS_dryRun)
- run_multiple_configs(gmmain, gm, configs, pdfRasterizers, tileGridReplayScales,
- grFactory, gpuAPI);
- }
-
- if (FLAGS_dryRun)
- return 0;
-
- SkTArray<SkString> modes;
- gmmain.GetRenderModesEncountered(modes);
- int modeCount = modes.count();
-
- // Now that we have run all the tests and thus know the full set of renderModes that we
- // tried to run, we can call RecordTestResults() to record the cases in which we skipped
- // ALL renderModes.
- // See http://skbug.com/1994 and https://codereview.chromium.org/129203002/
- int testCount = gmmain.fTestsSkippedOnAllRenderModes.count();
- for (int testNum = 0; testNum < testCount; ++testNum) {
- const SkString &shortNamePlusConfig = gmmain.fTestsSkippedOnAllRenderModes[testNum];
- for (int modeNum = 0; modeNum < modeCount; ++modeNum) {
- gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
- modes[modeNum].c_str());
- }
- }
-
- bool reportError = false;
- if (gmmain.NumSignificantErrors() > 0) {
- reportError = true;
- }
-
- // We test every GM against every config, and for every raster config also test every mode.
- int rasterConfigs = 0;
- for (int i = 0; i < configs.count(); i++) {
- if (gRec[configs[i]].fBackend == kRaster_Backend) {
- rasterConfigs++;
- }
- }
- // For raster configs, we run all renderModes; for non-raster configs, just default renderMode
- const int expectedNumberOfTests = rasterConfigs * gmsRun * modeCount
- + (configs.count() - rasterConfigs) * gmsRun;
-
- // Output summary to stdout.
- if (FLAGS_verbose) {
- SkDebugf("Ran %d GMs\n", gmsRun);
- SkDebugf("... over %2d configs [%s]\n", configs.count(),
- list_all_config_names(configs).c_str());
- SkDebugf("... and %2d modes [%s]\n", modeCount, list_all(modes).c_str());
- SkDebugf("... so there should be a total of %d tests.\n", expectedNumberOfTests);
- }
- gmmain.ListErrors(FLAGS_verbose);
-
- // TODO(epoger): Enable this check for Android, too, once we resolve
- // https://code.google.com/p/skia/issues/detail?id=1222
- // ('GM is unexpectedly skipping tests on Android')
-#ifndef SK_BUILD_FOR_ANDROID
- if (expectedNumberOfTests != gmmain.fTestsRun) {
- SkDebugf("expected %d tests, but ran or skipped %d tests\n",
- expectedNumberOfTests, gmmain.fTestsRun);
- reportError = true;
- }
-#endif
-
- if (FLAGS_writeJsonSummaryPath.count() == 1) {
- Json::Value root = CreateJsonTree(
- gmmain.fJsonExpectedResults,
- gmmain.fJsonActualResults_Failed, gmmain.fJsonActualResults_FailureIgnored,
- gmmain.fJsonActualResults_NoComparison, gmmain.fJsonActualResults_Succeeded);
- std::string jsonStdString = root.toStyledString();
- SkFILEWStream stream(FLAGS_writeJsonSummaryPath[0]);
- stream.write(jsonStdString.c_str(), jsonStdString.length());
- }
-
-#if SK_SUPPORT_GPU
-
-#if GR_CACHE_STATS
- for (int i = 0; i < configs.count(); i++) {
- ConfigData config = gRec[configs[i]];
-
- if (FLAGS_verbose && (kGPU_Backend == config.fBackend)) {
- GrContext* gr = grFactory->get(config.fGLContextType, gpuAPI);
-
- SkDebugf("config: %s %x\n", config.fName, gr);
- gr->printCacheStats();
- }
- }
-#endif
-
-#if GR_DUMP_FONT_CACHE
- for (int i = 0; i < configs.count(); i++) {
- ConfigData config = gRec[configs[i]];
-
- if (kGPU_Backend == config.fBackend) {
- GrContext* gr = grFactory->get(config.fGLContextType, gpuAPI);
-
- gr->dumpFontCache();
- }
- }
-#endif
-
- delete grFactory;
-#endif
-
- return (reportError) ? -1 : 0;
-}
-
-void GMMain::InstallFilter(SkCanvas* canvas) {
- if (FLAGS_forceBWtext) {
- canvas->setDrawFilter(SkNEW(BWTextDrawFilter))->unref();
- }
-}
-
-#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
-int main(int argc, char * const argv[]) {
- return tool_main(argc, (char**) argv);
-}
-#endif
diff --git a/gm/rebaseline_server/__init__.py b/gm/rebaseline_server/__init__.py
deleted file mode 100644
index 02d71e90af..0000000000
--- a/gm/rebaseline_server/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Needed so that test_all.py will recurse into this directory.
diff --git a/gm/rebaseline_server/base_unittest.py b/gm/rebaseline_server/base_unittest.py
deleted file mode 100755
index b8a653866b..0000000000
--- a/gm/rebaseline_server/base_unittest.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-A wrapper around the standard Python unittest library, adding features we need
-for various unittests within this directory.
-"""
-
-# System-level imports.
-import os
-import sys
-
-PARENT_DIR = os.path.abspath(os.path.dirname(__file__))
-TRUNK_DIR = os.path.abspath(os.path.join(PARENT_DIR, os.pardir, os.pardir))
-
-# Import the superclass base_unittest module from the tools dir.
-#
-# TODO(epoger): If I don't put this at the beginning of sys.path, the import of
-# tests.base_unittest fails. That's bad. I need to come up with a cleaner way
-# of doing this... I think this will involve changing how we import the "boto"
-# library in gs_utils.py, within the common repo.
-TOOLS_DIR = os.path.join(TRUNK_DIR, 'tools')
-if TOOLS_DIR != sys.path[0]:
- sys.path.insert(0, TOOLS_DIR)
-import tests.base_unittest as superclass_module
-
-
-class TestCase(superclass_module.TestCase):
-
- def __init__(self, *args, **kwargs):
- super(TestCase, self).__init__(*args, **kwargs)
- # Some of the tests within this package want their output validated,
- # so we declare where the expected and actual output will be.
- self._testdata_dir = os.path.join(PARENT_DIR, 'testdata')
-
-def main(*args, **kwargs):
- superclass_module.main(*args, **kwargs)
diff --git a/gm/rebaseline_server/column.py b/gm/rebaseline_server/column.py
deleted file mode 100644
index 1b9d0bf1c5..0000000000
--- a/gm/rebaseline_server/column.py
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-ColumnHeaderFactory class (see class docstring for details)
-"""
-
-# Keys used within dictionary representation of each column header.
-# NOTE: Keep these in sync with static/constants.js
-KEY__EXTRACOLUMNHEADERS__HEADER_TEXT = 'headerText'
-KEY__EXTRACOLUMNHEADERS__HEADER_URL = 'headerUrl'
-KEY__EXTRACOLUMNHEADERS__IS_FILTERABLE = 'isFilterable'
-KEY__EXTRACOLUMNHEADERS__IS_SORTABLE = 'isSortable'
-KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER = 'useFreeformFilter'
-KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS = 'valuesAndCounts'
-
-
-class ColumnHeaderFactory(object):
- """Factory which assembles the header for a single column of data."""
-
- def __init__(self, header_text, header_url=None,
- is_filterable=True, is_sortable=True,
- use_freeform_filter=False):
- """
- Args:
- header_text: string; text the client should display within column header.
- header_url: string; target URL if user clicks on column header.
- If None, nothing to click on.
- is_filterable: boolean; whether client should allow filtering on this
- column.
- is_sortable: boolean; whether client should allow sorting on this column.
- use_freeform_filter: boolean; *recommendation* to the client indicating
- whether to allow freeform text matching, as opposed to listing all
- values alongside checkboxes. If is_filterable==false, this is
- meaningless.
- """
- self._header_text = header_text
- self._header_url = header_url
- self._is_filterable = is_filterable
- self._is_sortable = is_sortable
- self._use_freeform_filter = use_freeform_filter
-
- def create_as_dict(self, values_and_counts_dict=None):
- """Creates the header for this column, in dictionary form.
-
- Creates the header for this column in dictionary form, as needed when
- constructing the JSON representation. Uses the KEY__EXTRACOLUMNHEADERS__*
- constants as keys.
-
- Args:
- values_and_counts_dict: dictionary mapping each possible column value
- to its count (how many entries in the column have this value), or
- None if this information is not available.
- """
- asdict = {
- KEY__EXTRACOLUMNHEADERS__HEADER_TEXT: self._header_text,
- KEY__EXTRACOLUMNHEADERS__IS_FILTERABLE: self._is_filterable,
- KEY__EXTRACOLUMNHEADERS__IS_SORTABLE: self._is_sortable,
- KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER: self._use_freeform_filter,
- }
- if self._header_url:
- asdict[KEY__EXTRACOLUMNHEADERS__HEADER_URL] = self._header_url
- if values_and_counts_dict:
- asdict[KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS] = sorted(
- values_and_counts_dict.items())
- return asdict
diff --git a/gm/rebaseline_server/compare_configs.py b/gm/rebaseline_server/compare_configs.py
deleted file mode 100755
index 36c7f86530..0000000000
--- a/gm/rebaseline_server/compare_configs.py
+++ /dev/null
@@ -1,209 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Compare GM results for two configs, across all builders.
-"""
-
-# System-level imports
-import argparse
-import logging
-import time
-
-# Must fix up PYTHONPATH before importing from within Skia
-import rs_fixpypath # pylint: disable=W0611
-
-# Imports from within Skia
-from py.utils import url_utils
-import gm_json
-import imagediffdb
-import imagepair
-import imagepairset
-import results
-
-
-class ConfigComparisons(results.BaseComparisons):
- """Loads results from two different configurations into an ImagePairSet.
-
- Loads actual and expected results from all builders, except for those skipped
- by _ignore_builder().
- """
-
- def __init__(self, configs, actuals_root=results.DEFAULT_ACTUALS_DIR,
- generated_images_root=results.DEFAULT_GENERATED_IMAGES_ROOT,
- diff_base_url=None, builder_regex_list=None):
- """
- Args:
- configs: (string, string) tuple; pair of configs to compare
- actuals_root: root directory containing all actual-results.json files
- generated_images_root: directory within which to create all pixel diffs;
- if this directory does not yet exist, it will be created
- diff_base_url: base URL within which the client should look for diff
- images; if not specified, defaults to a "file:///" URL representation
- of generated_images_root
- builder_regex_list: List of regular expressions specifying which builders
- we will process. If None, process all builders.
- """
- super(ConfigComparisons, self).__init__()
- time_start = int(time.time())
- if builder_regex_list != None:
- self.set_match_builders_pattern_list(builder_regex_list)
- self._image_diff_db = imagediffdb.ImageDiffDB(generated_images_root)
- self._diff_base_url = (
- diff_base_url or
- url_utils.create_filepath_url(generated_images_root))
- self._actuals_root = actuals_root
- self._load_config_pairs(configs)
- self._timestamp = int(time.time())
- logging.info('Results complete; took %d seconds.' %
- (self._timestamp - time_start))
-
- def _load_config_pairs(self, configs):
- """Loads the results of all tests, across all builders (based on the
- files within self._actuals_root), compares them across two configs,
- and stores the summary in self._results.
-
- Args:
- configs: tuple of strings; pair of configs to compare
- """
- logging.info('Reading actual-results JSON files from %s...' %
- self._actuals_root)
- actual_builder_dicts = self._read_builder_dicts_from_root(
- self._actuals_root)
- configA, configB = configs
- logging.info('Comparing configs %s and %s...' % (configA, configB))
-
- all_image_pairs = imagepairset.ImagePairSet(
- descriptions=configs,
- diff_base_url=self._diff_base_url)
- failing_image_pairs = imagepairset.ImagePairSet(
- descriptions=configs,
- diff_base_url=self._diff_base_url)
-
- all_image_pairs.ensure_extra_column_values_in_summary(
- column_id=results.KEY__EXTRACOLUMNS__RESULT_TYPE, values=[
- results.KEY__RESULT_TYPE__FAILED,
- results.KEY__RESULT_TYPE__NOCOMPARISON,
- results.KEY__RESULT_TYPE__SUCCEEDED,
- ])
- failing_image_pairs.ensure_extra_column_values_in_summary(
- column_id=results.KEY__EXTRACOLUMNS__RESULT_TYPE, values=[
- results.KEY__RESULT_TYPE__FAILED,
- results.KEY__RESULT_TYPE__NOCOMPARISON,
- ])
-
- builders = sorted(actual_builder_dicts.keys())
- num_builders = len(builders)
- builder_num = 0
- for builder in builders:
- builder_num += 1
- logging.info('Generating pixel diffs for builder #%d of %d, "%s"...' %
- (builder_num, num_builders, builder))
- actual_results_for_this_builder = (
- actual_builder_dicts[builder][gm_json.JSONKEY_ACTUALRESULTS])
- for result_type in sorted(actual_results_for_this_builder.keys()):
- results_of_this_type = actual_results_for_this_builder[result_type]
- if not results_of_this_type:
- continue
-
- tests_found = set()
- for image_name in sorted(results_of_this_type.keys()):
- (test, _) = results.IMAGE_FILENAME_RE.match(image_name).groups()
- tests_found.add(test)
-
- for test in tests_found:
- # Get image_relative_url (or None) for each of configA, configB
- image_name_A = results.IMAGE_FILENAME_FORMATTER % (test, configA)
- configA_image_relative_url = ConfigComparisons._create_relative_url(
- hashtype_and_digest=results_of_this_type.get(image_name_A),
- test_name=test)
- image_name_B = results.IMAGE_FILENAME_FORMATTER % (test, configB)
- configB_image_relative_url = ConfigComparisons._create_relative_url(
- hashtype_and_digest=results_of_this_type.get(image_name_B),
- test_name=test)
-
- # If we have images for at least one of these two configs,
- # add them to our list.
- if configA_image_relative_url or configB_image_relative_url:
- if configA_image_relative_url == configB_image_relative_url:
- result_type = results.KEY__RESULT_TYPE__SUCCEEDED
- elif not configA_image_relative_url:
- result_type = results.KEY__RESULT_TYPE__NOCOMPARISON
- elif not configB_image_relative_url:
- result_type = results.KEY__RESULT_TYPE__NOCOMPARISON
- else:
- result_type = results.KEY__RESULT_TYPE__FAILED
-
- extra_columns_dict = {
- results.KEY__EXTRACOLUMNS__RESULT_TYPE: result_type,
- results.KEY__EXTRACOLUMNS__BUILDER: builder,
- results.KEY__EXTRACOLUMNS__TEST: test,
- # TODO(epoger): Right now, the client UI crashes if it receives
- # results that do not include a 'config' column.
- # Until we fix that, keep the client happy.
- results.KEY__EXTRACOLUMNS__CONFIG: 'TODO',
- }
-
- try:
- image_pair = imagepair.ImagePair(
- image_diff_db=self._image_diff_db,
- imageA_base_url=gm_json.GM_ACTUALS_ROOT_HTTP_URL,
- imageB_base_url=gm_json.GM_ACTUALS_ROOT_HTTP_URL,
- imageA_relative_url=configA_image_relative_url,
- imageB_relative_url=configB_image_relative_url,
- extra_columns=extra_columns_dict)
- all_image_pairs.add_image_pair(image_pair)
- if result_type != results.KEY__RESULT_TYPE__SUCCEEDED:
- failing_image_pairs.add_image_pair(image_pair)
- except (KeyError, TypeError):
- logging.exception(
- 'got exception while creating ImagePair for test '
- '"%s", builder "%s"' % (test, builder))
-
- # pylint: disable=W0201
- self._results = {
- results.KEY__HEADER__RESULTS_ALL: all_image_pairs.as_dict(),
- results.KEY__HEADER__RESULTS_FAILURES: failing_image_pairs.as_dict(),
- }
-
-
-def main():
- logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
- datefmt='%m/%d/%Y %H:%M:%S',
- level=logging.INFO)
- parser = argparse.ArgumentParser()
- parser.add_argument(
- '--actuals', default=results.DEFAULT_ACTUALS_DIR,
- help='Directory containing all actual-result JSON files; defaults to '
- '\'%(default)s\' .')
- parser.add_argument(
- 'config', nargs=2,
- help='Two configurations to compare (8888, gpu, etc.).')
- parser.add_argument(
- '--outfile', required=True,
- help='File to write result summary into, in JSON format.')
- parser.add_argument(
- '--results', default=results.KEY__HEADER__RESULTS_FAILURES,
- help='Which result types to include. Defaults to \'%(default)s\'; '
- 'must be one of ' +
- str([results.KEY__HEADER__RESULTS_FAILURES,
- results.KEY__HEADER__RESULTS_ALL]))
- parser.add_argument(
- '--workdir', default=results.DEFAULT_GENERATED_IMAGES_ROOT,
- help='Directory within which to download images and generate diffs; '
- 'defaults to \'%(default)s\' .')
- args = parser.parse_args()
- results_obj = ConfigComparisons(configs=args.config,
- actuals_root=args.actuals,
- generated_images_root=args.workdir)
- gm_json.WriteToFile(
- results_obj.get_packaged_results_of_type(results_type=args.results),
- args.outfile)
-
-
-if __name__ == '__main__':
- main()
diff --git a/gm/rebaseline_server/compare_configs_test.py b/gm/rebaseline_server/compare_configs_test.py
deleted file mode 100755
index 612be99837..0000000000
--- a/gm/rebaseline_server/compare_configs_test.py
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Test compare_configs.py
-
-TODO(epoger): Create a command to update the expected results (in
-self._output_dir_expected) when appropriate. For now, you should:
-1. examine the results in self.output_dir_actual and make sure they are ok
-2. rm -rf self._output_dir_expected
-3. mv self.output_dir_actual self._output_dir_expected
-Although, if you're using an SVN checkout, this will blow away .svn directories
-within self._output_dir_expected, which wouldn't be good...
-
-"""
-
-# System-level imports
-import os
-
-# Must fix up PYTHONPATH before importing from within Skia
-import rs_fixpypath # pylint: disable=W0611
-
-# Imports from within Skia
-import base_unittest
-import compare_configs
-import gm_json
-import results
-
-
-class CompareConfigsTest(base_unittest.TestCase):
-
- def test_gm(self):
- """Process results of a GM run with the ConfigComparisons object."""
- results_obj = compare_configs.ConfigComparisons(
- configs=('8888', 'gpu'),
- actuals_root=os.path.join(self.input_dir, 'gm-actuals'),
- generated_images_root=self.temp_dir,
- diff_base_url='/static/generated-images')
- results_obj.get_timestamp = mock_get_timestamp
- gm_json.WriteToFile(
- results_obj.get_packaged_results_of_type(
- results.KEY__HEADER__RESULTS_ALL),
- os.path.join(self.output_dir_actual, 'gm.json'))
-
-
-def mock_get_timestamp():
- """Mock version of BaseComparisons.get_timestamp() for testing."""
- return 12345678
-
-
-def main():
- base_unittest.main(CompareConfigsTest)
-
-
-if __name__ == '__main__':
- main()
diff --git a/gm/rebaseline_server/compare_rendered_pictures.py b/gm/rebaseline_server/compare_rendered_pictures.py
deleted file mode 100755
index 73cb36b430..0000000000
--- a/gm/rebaseline_server/compare_rendered_pictures.py
+++ /dev/null
@@ -1,504 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Compare results of two render_pictures runs.
-
-TODO(epoger): Start using this module to compare ALL images (whether they
-were generated from GMs or SKPs), and rename it accordingly.
-"""
-
-# System-level imports
-import logging
-import os
-import shutil
-import subprocess
-import tempfile
-import time
-
-# Must fix up PYTHONPATH before importing from within Skia
-import rs_fixpypath # pylint: disable=W0611
-
-# Imports from within Skia
-from py.utils import git_utils
-from py.utils import gs_utils
-from py.utils import url_utils
-import buildbot_globals
-import column
-import gm_json
-import imagediffdb
-import imagepair
-import imagepairset
-import results
-
-# URL under which all render_pictures images can be found in Google Storage.
-#
-# TODO(epoger): In order to allow live-view of GMs and other images, read this
-# from the input summary files, or allow the caller to set it within the
-# GET_live_results call.
-DEFAULT_IMAGE_BASE_GS_URL = 'gs://' + buildbot_globals.Get('skp_images_bucket')
-
-# Column descriptors, and display preferences for them.
-COLUMN__RESULT_TYPE = results.KEY__EXTRACOLUMNS__RESULT_TYPE
-COLUMN__SOURCE_SKP = 'sourceSkpFile'
-COLUMN__TILED_OR_WHOLE = 'tiledOrWhole'
-COLUMN__TILENUM = 'tilenum'
-COLUMN__BUILDER_A = 'builderA'
-COLUMN__RENDER_MODE_A = 'renderModeA'
-COLUMN__BUILDER_B = 'builderB'
-COLUMN__RENDER_MODE_B = 'renderModeB'
-# Known values for some of those columns.
-COLUMN__TILED_OR_WHOLE__TILED = 'tiled'
-COLUMN__TILED_OR_WHOLE__WHOLE = 'whole'
-
-FREEFORM_COLUMN_IDS = [
- COLUMN__SOURCE_SKP,
- COLUMN__TILENUM,
-]
-ORDERED_COLUMN_IDS = [
- COLUMN__RESULT_TYPE,
- COLUMN__SOURCE_SKP,
- COLUMN__TILED_OR_WHOLE,
- COLUMN__TILENUM,
- COLUMN__BUILDER_A,
- COLUMN__RENDER_MODE_A,
- COLUMN__BUILDER_B,
- COLUMN__RENDER_MODE_B,
-]
-
-# A special "repo:" URL type that we use to refer to Skia repo contents.
-# (Useful for comparing against expectations files we store in our repo.)
-REPO_URL_PREFIX = 'repo:'
-REPO_BASEPATH = os.path.abspath(os.path.join(
- os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir))
-
-# Which sections within a JSON summary file can contain results.
-ALLOWED_SECTION_NAMES = [
- gm_json.JSONKEY_ACTUALRESULTS,
- gm_json.JSONKEY_EXPECTEDRESULTS,
-]
-
-
-class RenderedPicturesComparisons(results.BaseComparisons):
- """Loads results from multiple render_pictures runs into an ImagePairSet.
- """
-
- def __init__(self,
- setA_dir, setB_dir,
- setA_section, setB_section,
- image_diff_db,
- image_base_gs_url=DEFAULT_IMAGE_BASE_GS_URL, diff_base_url=None,
- setA_label=None, setB_label=None,
- gs=None, truncate_results=False, prefetch_only=False,
- download_all_images=False):
- """Constructor: downloads images and generates diffs.
-
- Once the object has been created (which may take a while), you can call its
- get_packaged_results_of_type() method to quickly retrieve the results...
- unless you have set prefetch_only to True, in which case we will
- asynchronously warm up the ImageDiffDB cache but not fill in self._results.
-
- Args:
- setA_dir: root directory to copy all JSON summaries from, and to use as
- setA within the comparisons. This directory may be specified as a
- gs:// URL, special "repo:" URL, or local filepath.
- setB_dir: root directory to copy all JSON summaries from, and to use as
- setB within the comparisons. This directory may be specified as a
- gs:// URL, special "repo:" URL, or local filepath.
- setA_section: which section within setA to examine; must be one of
- ALLOWED_SECTION_NAMES
- setB_section: which section within setB to examine; must be one of
- ALLOWED_SECTION_NAMES
- image_diff_db: ImageDiffDB instance
- image_base_gs_url: "gs://" URL pointing at the Google Storage bucket/dir
- under which all render_pictures result images can
- be found; this will be used to read images for comparison within
- this code, and included in the ImagePairSet (as an HTTP URL) so its
- consumers know where to download the images from
- diff_base_url: base URL within which the client should look for diff
- images; if not specified, defaults to a "file:///" URL representation
- of image_diff_db's storage_root
- setA_label: description to use for results in setA; if None, will be
- set to a reasonable default
- setB_label: description to use for results in setB; if None, will be
- set to a reasonable default
- gs: instance of GSUtils object we can use to download summary files
- truncate_results: FOR MANUAL TESTING: if True, truncate the set of images
- we process, to speed up testing.
- prefetch_only: if True, return the new object as quickly as possible
- with empty self._results (just queue up all the files to process,
- don't wait around for them to be processed and recorded); otherwise,
- block until the results have been assembled and recorded in
- self._results.
- download_all_images: if True, download all images, even if we don't
- need them to generate diffs. This will take much longer to complete,
- but is useful for warming up the bitmap cache on local disk.
- """
- super(RenderedPicturesComparisons, self).__init__()
- self._image_diff_db = image_diff_db
- self._image_base_gs_url = image_base_gs_url
- self._diff_base_url = (
- diff_base_url or
- url_utils.create_filepath_url(image_diff_db.storage_root))
- self._gs = gs
- self.truncate_results = truncate_results
- self._prefetch_only = prefetch_only
- self._download_all_images = download_all_images
-
- # If we are comparing two different section types, we can use those
- # as the default labels for setA and setB.
- if setA_section != setB_section:
- self._setA_label = setA_label or setA_section
- self._setB_label = setB_label or setB_section
- else:
- self._setA_label = setA_label or 'setA'
- self._setB_label = setB_label or 'setB'
-
- tempdir = tempfile.mkdtemp()
- try:
- setA_root = os.path.join(tempdir, 'setA')
- setB_root = os.path.join(tempdir, 'setB')
- # TODO(stephana): There is a potential race condition here... we copy
- # the contents out of the source_dir, and THEN we get the commithash
- # of source_dir. If source_dir points at a git checkout, and that
- # checkout is updated (by a different thread/process) during this
- # operation, then the contents and commithash will be out of sync.
- self._copy_dir_contents(source_dir=setA_dir, dest_dir=setA_root)
- setA_repo_revision = self._get_repo_revision(source_dir=setA_dir)
- self._copy_dir_contents(source_dir=setB_dir, dest_dir=setB_root)
- setB_repo_revision = self._get_repo_revision(source_dir=setB_dir)
-
- self._setA_descriptions = {
- results.KEY__SET_DESCRIPTIONS__DIR: setA_dir,
- results.KEY__SET_DESCRIPTIONS__REPO_REVISION: setA_repo_revision,
- results.KEY__SET_DESCRIPTIONS__SECTION: setA_section,
- }
- self._setB_descriptions = {
- results.KEY__SET_DESCRIPTIONS__DIR: setB_dir,
- results.KEY__SET_DESCRIPTIONS__REPO_REVISION: setB_repo_revision,
- results.KEY__SET_DESCRIPTIONS__SECTION: setB_section,
- }
-
- time_start = int(time.time())
- self._results = self._load_result_pairs(
- setA_root=setA_root, setB_root=setB_root,
- setA_section=setA_section, setB_section=setB_section)
- if self._results:
- self._timestamp = int(time.time())
- logging.info('Number of download file collisions: %s' %
- imagediffdb.global_file_collisions)
- logging.info('Results complete; took %d seconds.' %
- (self._timestamp - time_start))
- finally:
- shutil.rmtree(tempdir)
-
- def _load_result_pairs(self, setA_root, setB_root,
- setA_section, setB_section):
- """Loads all JSON image summaries from 2 directory trees and compares them.
-
- TODO(stephana): This method is only called from within __init__(); it might
- make more sense to just roll the content of this method into __init__().
-
- Args:
- setA_root: root directory containing JSON summaries of rendering results
- setB_root: root directory containing JSON summaries of rendering results
- setA_section: which section (gm_json.JSONKEY_ACTUALRESULTS or
- gm_json.JSONKEY_EXPECTEDRESULTS) to load from the summaries in setA
- setB_section: which section (gm_json.JSONKEY_ACTUALRESULTS or
- gm_json.JSONKEY_EXPECTEDRESULTS) to load from the summaries in setB
-
- Returns the summary of all image diff results (or None, depending on
- self._prefetch_only).
- """
- logging.info('Reading JSON image summaries from dirs %s and %s...' % (
- setA_root, setB_root))
- setA_dicts = self.read_dicts_from_root(setA_root)
- setB_dicts = self.read_dicts_from_root(setB_root)
- logging.info('Comparing summary dicts...')
-
- all_image_pairs = imagepairset.ImagePairSet(
- descriptions=(self._setA_label, self._setB_label),
- diff_base_url=self._diff_base_url)
- failing_image_pairs = imagepairset.ImagePairSet(
- descriptions=(self._setA_label, self._setB_label),
- diff_base_url=self._diff_base_url)
-
- # Override settings for columns that should be filtered using freeform text.
- for column_id in FREEFORM_COLUMN_IDS:
- factory = column.ColumnHeaderFactory(
- header_text=column_id, use_freeform_filter=True)
- all_image_pairs.set_column_header_factory(
- column_id=column_id, column_header_factory=factory)
- failing_image_pairs.set_column_header_factory(
- column_id=column_id, column_header_factory=factory)
-
- all_image_pairs.ensure_extra_column_values_in_summary(
- column_id=COLUMN__RESULT_TYPE, values=[
- results.KEY__RESULT_TYPE__FAILED,
- results.KEY__RESULT_TYPE__NOCOMPARISON,
- results.KEY__RESULT_TYPE__SUCCEEDED,
- ])
- failing_image_pairs.ensure_extra_column_values_in_summary(
- column_id=COLUMN__RESULT_TYPE, values=[
- results.KEY__RESULT_TYPE__FAILED,
- results.KEY__RESULT_TYPE__NOCOMPARISON,
- ])
-
- logging.info('Starting to add imagepairs to queue.')
- self._image_diff_db.log_queue_size_if_changed(limit_verbosity=False)
-
- union_dict_paths = sorted(set(setA_dicts.keys() + setB_dicts.keys()))
- num_union_dict_paths = len(union_dict_paths)
- dict_num = 0
- for dict_path in union_dict_paths:
- dict_num += 1
- logging.info(
- 'Asynchronously requesting pixel diffs for dict #%d of %d, "%s"...' %
- (dict_num, num_union_dict_paths, dict_path))
-
- dictA = self.get_default(setA_dicts, None, dict_path)
- self._validate_dict_version(dictA)
- dictA_results = self.get_default(dictA, {}, setA_section)
-
- dictB = self.get_default(setB_dicts, None, dict_path)
- self._validate_dict_version(dictB)
- dictB_results = self.get_default(dictB, {}, setB_section)
-
- image_A_base_url = self.get_default(
- setA_dicts, self._image_base_gs_url, dict_path,
- gm_json.JSONKEY_IMAGE_BASE_GS_URL)
- image_B_base_url = self.get_default(
- setB_dicts, self._image_base_gs_url, dict_path,
- gm_json.JSONKEY_IMAGE_BASE_GS_URL)
-
- # get the builders and render modes for each set
- builder_A = self.get_default(dictA, None,
- gm_json.JSONKEY_DESCRIPTIONS,
- gm_json.JSONKEY_DESCRIPTIONS_BUILDER)
- render_mode_A = self.get_default(dictA, None,
- gm_json.JSONKEY_DESCRIPTIONS,
- gm_json.JSONKEY_DESCRIPTIONS_RENDER_MODE)
- builder_B = self.get_default(dictB, None,
- gm_json.JSONKEY_DESCRIPTIONS,
- gm_json.JSONKEY_DESCRIPTIONS_BUILDER)
- render_mode_B = self.get_default(dictB, None,
- gm_json.JSONKEY_DESCRIPTIONS,
- gm_json.JSONKEY_DESCRIPTIONS_RENDER_MODE)
-
- skp_names = sorted(set(dictA_results.keys() + dictB_results.keys()))
- # Just for manual testing... truncate to an arbitrary subset.
- if self.truncate_results:
- skp_names = skp_names[1:3]
- for skp_name in skp_names:
- imagepairs_for_this_skp = []
-
- whole_image_A = self.get_default(
- dictA_results, None,
- skp_name, gm_json.JSONKEY_SOURCE_WHOLEIMAGE)
- whole_image_B = self.get_default(
- dictB_results, None,
- skp_name, gm_json.JSONKEY_SOURCE_WHOLEIMAGE)
-
- imagepairs_for_this_skp.append(self._create_image_pair(
- image_dict_A=whole_image_A, image_dict_B=whole_image_B,
- image_A_base_url=image_A_base_url,
- image_B_base_url=image_B_base_url,
- builder_A=builder_A, render_mode_A=render_mode_A,
- builder_B=builder_B, render_mode_B=render_mode_B,
- source_json_file=dict_path,
- source_skp_name=skp_name, tilenum=None))
-
- tiled_images_A = self.get_default(
- dictA_results, [],
- skp_name, gm_json.JSONKEY_SOURCE_TILEDIMAGES)
- tiled_images_B = self.get_default(
- dictB_results, [],
- skp_name, gm_json.JSONKEY_SOURCE_TILEDIMAGES)
- if tiled_images_A or tiled_images_B:
- num_tiles_A = len(tiled_images_A)
- num_tiles_B = len(tiled_images_B)
- num_tiles = max(num_tiles_A, num_tiles_B)
- for tile_num in range(num_tiles):
- imagepairs_for_this_skp.append(self._create_image_pair(
- image_dict_A=(tiled_images_A[tile_num]
- if tile_num < num_tiles_A else None),
- image_dict_B=(tiled_images_B[tile_num]
- if tile_num < num_tiles_B else None),
- image_A_base_url=image_A_base_url,
- image_B_base_url=image_B_base_url,
- builder_A=builder_A, render_mode_A=render_mode_A,
- builder_B=builder_B, render_mode_B=render_mode_B,
- source_json_file=dict_path,
- source_skp_name=skp_name, tilenum=tile_num))
-
- for one_imagepair in imagepairs_for_this_skp:
- if one_imagepair:
- all_image_pairs.add_image_pair(one_imagepair)
- result_type = one_imagepair.extra_columns_dict\
- [COLUMN__RESULT_TYPE]
- if result_type != results.KEY__RESULT_TYPE__SUCCEEDED:
- failing_image_pairs.add_image_pair(one_imagepair)
-
- logging.info('Finished adding imagepairs to queue.')
- self._image_diff_db.log_queue_size_if_changed(limit_verbosity=False)
-
- if self._prefetch_only:
- return None
- else:
- return {
- results.KEY__HEADER__RESULTS_ALL: all_image_pairs.as_dict(
- column_ids_in_order=ORDERED_COLUMN_IDS),
- results.KEY__HEADER__RESULTS_FAILURES: failing_image_pairs.as_dict(
- column_ids_in_order=ORDERED_COLUMN_IDS),
- }
-
- def _validate_dict_version(self, result_dict):
- """Raises Exception if the dict is not the type/version we know how to read.
-
- Args:
- result_dict: dictionary holding output of render_pictures; if None,
- this method will return without raising an Exception
- """
- # TODO(stephana): These values should be defined as constants somewhere,
- # to be kept in sync between this file and writable_expectations.py
- expected_header_type = 'ChecksummedImages'
- expected_header_revision = 1
-
- if result_dict == None:
- return
- header = result_dict[gm_json.JSONKEY_HEADER]
- header_type = header[gm_json.JSONKEY_HEADER_TYPE]
- if header_type != expected_header_type:
- raise Exception('expected header_type "%s", but got "%s"' % (
- expected_header_type, header_type))
- header_revision = header[gm_json.JSONKEY_HEADER_REVISION]
- if header_revision != expected_header_revision:
- raise Exception('expected header_revision %d, but got %d' % (
- expected_header_revision, header_revision))
-
- def _create_image_pair(self, image_dict_A, image_dict_B,
- image_A_base_url, image_B_base_url,
- builder_A, render_mode_A,
- builder_B, render_mode_B,
- source_json_file,
- source_skp_name, tilenum):
- """Creates an ImagePair object for this pair of images.
-
- Args:
- image_dict_A: dict with JSONKEY_IMAGE_* keys, or None if no image
- image_dict_B: dict with JSONKEY_IMAGE_* keys, or None if no image
- image_A_base_url: base URL for image A
- image_B_base_url: base URL for image B
- builder_A: builder that created image set A or None if unknow
- render_mode_A: render mode used to generate image set A or None if
- unknown.
- builder_B: builder that created image set A or None if unknow
- render_mode_B: render mode used to generate image set A or None if
- unknown.
- source_json_file: string; relative path of the JSON file where this
- result came from, within setA and setB.
- source_skp_name: string; name of the source SKP file
- tilenum: which tile, or None if a wholeimage
-
- Returns:
- An ImagePair object, or None if both image_dict_A and image_dict_B are
- None.
- """
- if (not image_dict_A) and (not image_dict_B):
- return None
-
- def _checksum_and_relative_url(dic):
- if dic:
- return ((dic[gm_json.JSONKEY_IMAGE_CHECKSUMALGORITHM],
- int(dic[gm_json.JSONKEY_IMAGE_CHECKSUMVALUE])),
- dic[gm_json.JSONKEY_IMAGE_FILEPATH])
- else:
- return None, None
-
- imageA_checksum, imageA_relative_url = _checksum_and_relative_url(
- image_dict_A)
- imageB_checksum, imageB_relative_url = _checksum_and_relative_url(
- image_dict_B)
-
- if not imageA_checksum:
- result_type = results.KEY__RESULT_TYPE__NOCOMPARISON
- elif not imageB_checksum:
- result_type = results.KEY__RESULT_TYPE__NOCOMPARISON
- elif imageA_checksum == imageB_checksum:
- result_type = results.KEY__RESULT_TYPE__SUCCEEDED
- else:
- result_type = results.KEY__RESULT_TYPE__FAILED
-
- extra_columns_dict = {
- COLUMN__RESULT_TYPE: result_type,
- COLUMN__SOURCE_SKP: source_skp_name,
- COLUMN__BUILDER_A: builder_A,
- COLUMN__RENDER_MODE_A: render_mode_A,
- COLUMN__BUILDER_B: builder_B,
- COLUMN__RENDER_MODE_B: render_mode_B,
- }
- if tilenum == None:
- extra_columns_dict[COLUMN__TILED_OR_WHOLE] = COLUMN__TILED_OR_WHOLE__WHOLE
- extra_columns_dict[COLUMN__TILENUM] = 'N/A'
- else:
- extra_columns_dict[COLUMN__TILED_OR_WHOLE] = COLUMN__TILED_OR_WHOLE__TILED
- extra_columns_dict[COLUMN__TILENUM] = str(tilenum)
-
- try:
- return imagepair.ImagePair(
- image_diff_db=self._image_diff_db,
- imageA_base_url=image_A_base_url,
- imageB_base_url=image_B_base_url,
- imageA_relative_url=imageA_relative_url,
- imageB_relative_url=imageB_relative_url,
- extra_columns=extra_columns_dict,
- source_json_file=source_json_file,
- download_all_images=self._download_all_images)
- except (KeyError, TypeError):
- logging.exception(
- 'got exception while creating ImagePair for'
- ' urlPair=("%s","%s"), source_skp_name="%s", tilenum="%s"' % (
- imageA_relative_url, imageB_relative_url, source_skp_name,
- tilenum))
- return None
-
- def _copy_dir_contents(self, source_dir, dest_dir):
- """Copy all contents of source_dir into dest_dir, recursing into subdirs.
-
- Args:
- source_dir: path to source dir (GS URL, local filepath, or a special
- "repo:" URL type that points at a file within our Skia checkout)
- dest_dir: path to destination dir (local filepath)
-
- The copy operates as a "merge with overwrite": any files in source_dir will
- be "overlaid" on top of the existing content in dest_dir. Existing files
- with the same names will be overwritten.
- """
- if gs_utils.GSUtils.is_gs_url(source_dir):
- (bucket, path) = gs_utils.GSUtils.split_gs_url(source_dir)
- self._gs.download_dir_contents(source_bucket=bucket, source_dir=path,
- dest_dir=dest_dir)
- elif source_dir.lower().startswith(REPO_URL_PREFIX):
- repo_dir = os.path.join(REPO_BASEPATH, source_dir[len(REPO_URL_PREFIX):])
- shutil.copytree(repo_dir, dest_dir)
- else:
- shutil.copytree(source_dir, dest_dir)
-
- def _get_repo_revision(self, source_dir):
- """Get the commit hash of source_dir, IF it refers to a git checkout.
-
- Args:
- source_dir: path to source dir (GS URL, local filepath, or a special
- "repo:" URL type that points at a file within our Skia checkout;
- only the "repo:" URL type will have a commit hash.
- """
- if source_dir.lower().startswith(REPO_URL_PREFIX):
- repo_dir = os.path.join(REPO_BASEPATH, source_dir[len(REPO_URL_PREFIX):])
- return subprocess.check_output(
- args=[git_utils.GIT, 'rev-parse', 'HEAD'], cwd=repo_dir).strip()
- else:
- return None
diff --git a/gm/rebaseline_server/compare_rendered_pictures_test.py b/gm/rebaseline_server/compare_rendered_pictures_test.py
deleted file mode 100755
index 2b15462111..0000000000
--- a/gm/rebaseline_server/compare_rendered_pictures_test.py
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Test compare_rendered_pictures.py
-
-TODO(epoger): Create a command to update the expected results (in
-self._output_dir_expected) when appropriate. For now, you should:
-1. examine the results in self.output_dir_actual and make sure they are ok
-2. rm -rf self._output_dir_expected
-3. mv self.output_dir_actual self._output_dir_expected
-Although, if you're using an SVN checkout, this will blow away .svn directories
-within self._output_dir_expected, which wouldn't be good...
-
-"""
-
-# System-level imports
-import os
-import posixpath
-import subprocess
-
-# Must fix up PYTHONPATH before importing from within Skia
-import rs_fixpypath # pylint: disable=W0611
-
-# Imports from within Skia
-import base_unittest
-import compare_rendered_pictures
-import find_run_binary
-import gm_json
-import imagediffdb
-import imagepairset
-import results
-
-
-class CompareRenderedPicturesTest(base_unittest.TestCase):
-
- def test_endToEnd(self):
- """Generate two sets of SKPs, run render_pictures over both, and compare
- the results."""
- setA_subdir = 'before_patch'
- setB_subdir = 'after_patch'
- self._generate_skps_and_run_render_pictures(
- subdir=setA_subdir, skpdict={
- 'changed.skp': 200,
- 'unchanged.skp': 100,
- 'only-in-before.skp': 128,
- })
- self._generate_skps_and_run_render_pictures(
- subdir=setB_subdir, skpdict={
- 'changed.skp': 201,
- 'unchanged.skp': 100,
- 'only-in-after.skp': 128,
- })
-
- results_obj = compare_rendered_pictures.RenderedPicturesComparisons(
- setA_dir=os.path.join(self.temp_dir, setA_subdir),
- setB_dir=os.path.join(self.temp_dir, setB_subdir),
- setA_section=gm_json.JSONKEY_ACTUALRESULTS,
- setB_section=gm_json.JSONKEY_ACTUALRESULTS,
- image_diff_db=imagediffdb.ImageDiffDB(self.temp_dir),
- image_base_gs_url='gs://fakebucket/fake/path',
- diff_base_url='/static/generated-images')
- results_obj.get_timestamp = mock_get_timestamp
-
- # Overwrite elements within the results that change from one test run
- # to the next.
- # pylint: disable=W0212
- results_obj._setA_descriptions[results.KEY__SET_DESCRIPTIONS__DIR] = [
- 'before-patch-fake-dir']
- results_obj._setB_descriptions[results.KEY__SET_DESCRIPTIONS__DIR] = [
- 'after-patch-fake-dir']
-
- gm_json.WriteToFile(
- results_obj.get_packaged_results_of_type(
- results.KEY__HEADER__RESULTS_ALL),
- os.path.join(self.output_dir_actual, 'compare_rendered_pictures.json'))
-
- def test_endToEnd_withImageBaseGSUrl(self):
- """Generate two sets of SKPs, run render_pictures over both, and compare
- the results."""
- setA_subdir = 'before_patch'
- setB_subdir = 'after_patch'
- imageA_gs_base = 'superman/kent-camera/pictures'
- imageB_gs_base = 'batman/batarang/pictures'
- self._generate_skps_and_run_render_pictures(
- subdir=setA_subdir, skpdict={
- 'changed.skp': 200,
- 'unchanged.skp': 100,
- 'only-in-before.skp': 128,
- },
- image_base_gs_url='gs://%s' % imageA_gs_base)
- self._generate_skps_and_run_render_pictures(
- subdir=setB_subdir, skpdict={
- 'changed.skp': 201,
- 'unchanged.skp': 100,
- 'only-in-after.skp': 128,
- },
- image_base_gs_url='gs://%s' % imageB_gs_base)
-
- results_obj = compare_rendered_pictures.RenderedPicturesComparisons(
- setA_dir=os.path.join(self.temp_dir, setA_subdir),
- setB_dir=os.path.join(self.temp_dir, setB_subdir),
- setA_section=gm_json.JSONKEY_ACTUALRESULTS,
- setB_section=gm_json.JSONKEY_ACTUALRESULTS,
- image_diff_db=imagediffdb.ImageDiffDB(self.temp_dir),
- image_base_gs_url='gs://fakebucket/fake/path',
- diff_base_url='/static/generated-images')
- results_obj.get_timestamp = mock_get_timestamp
-
- output_dict = results_obj.get_packaged_results_of_type(
- results.KEY__HEADER__RESULTS_ALL)
- # Assert that the baseURLs are as expected.
- self.assertEquals(
- output_dict[imagepairset.KEY__ROOT__IMAGESETS]
- [imagepairset.KEY__IMAGESETS__SET__IMAGE_A]
- [imagepairset.KEY__IMAGESETS__FIELD__BASE_URL],
- 'http://storage.cloud.google.com/%s' % imageA_gs_base)
- self.assertEquals(
- output_dict[imagepairset.KEY__ROOT__IMAGESETS]
- [imagepairset.KEY__IMAGESETS__SET__IMAGE_B]
- [imagepairset.KEY__IMAGESETS__FIELD__BASE_URL],
- 'http://storage.cloud.google.com/%s' % imageB_gs_base)
- # Overwrite elements within the results that change from one test run
- # to the next.
- # pylint: disable=W0212
- results_obj._setA_descriptions[results.KEY__SET_DESCRIPTIONS__DIR] = [
- 'before-patch-fake-dir']
- results_obj._setB_descriptions[results.KEY__SET_DESCRIPTIONS__DIR] = [
- 'after-patch-fake-dir']
-
- gm_json.WriteToFile(
- output_dict,
- os.path.join(self.output_dir_actual,
- 'compare_rendered_pictures.json'))
-
- def test_repo_url(self):
- """Use repo: URL to specify summary files."""
- base_repo_url = 'repo:gm/rebaseline_server/testdata/inputs/skp-summaries'
- results_obj = compare_rendered_pictures.RenderedPicturesComparisons(
- setA_dir=posixpath.join(base_repo_url, 'expectations'),
- setB_dir=posixpath.join(base_repo_url, 'actuals'),
- setA_section=gm_json.JSONKEY_EXPECTEDRESULTS,
- setB_section=gm_json.JSONKEY_ACTUALRESULTS,
- image_diff_db=imagediffdb.ImageDiffDB(self.temp_dir),
- image_base_gs_url='gs://fakebucket/fake/path',
- diff_base_url='/static/generated-images')
- results_obj.get_timestamp = mock_get_timestamp
-
- # Overwrite elements within the results that change from one test run
- # to the next.
- # pylint: disable=W0212
- results_obj._setA_descriptions\
- [results.KEY__SET_DESCRIPTIONS__REPO_REVISION] = 'fake-repo-revision'
- results_obj._setB_descriptions\
- [results.KEY__SET_DESCRIPTIONS__REPO_REVISION] = 'fake-repo-revision'
-
- gm_json.WriteToFile(
- results_obj.get_packaged_results_of_type(
- results.KEY__HEADER__RESULTS_ALL),
- os.path.join(self.output_dir_actual, 'compare_rendered_pictures.json'))
-
- def _generate_skps_and_run_render_pictures(self, subdir, skpdict,
- image_base_gs_url=None):
- """Generate SKPs and run render_pictures on them.
-
- Args:
- subdir: subdirectory (within self.temp_dir) to write all files into
- skpdict: {skpname: redvalue} dictionary describing the SKP files to render
- """
- out_path = os.path.join(self.temp_dir, subdir)
- os.makedirs(out_path)
- for skpname, redvalue in skpdict.iteritems():
- self._run_skpmaker(
- output_path=os.path.join(out_path, skpname), red=redvalue)
-
- # TODO(epoger): Add --mode tile 256 256 --writeWholeImage to the unittest,
- # and fix its result! (imageURLs within whole-image entries are wrong when
- # I tried adding that)
- binary = find_run_binary.find_path_to_program('render_pictures')
- render_pictures_cmd = [
- binary,
- '--config', '8888',
- '-r', out_path,
- '--writeChecksumBasedFilenames',
- '--writeJsonSummaryPath', os.path.join(out_path, 'summary.json'),
- '--writePath', out_path]
- if image_base_gs_url:
- render_pictures_cmd.extend(['--imageBaseGSUrl', image_base_gs_url])
- return subprocess.check_output(render_pictures_cmd)
-
- def _run_skpmaker(self, output_path, red=0, green=0, blue=0,
- width=640, height=400):
- """Runs the skpmaker binary to generate SKP with known characteristics.
-
- Args:
- output_path: Filepath to write the SKP into.
- red: Value of red color channel in image, 0-255.
- green: Value of green color channel in image, 0-255.
- blue: Value of blue color channel in image, 0-255.
- width: Width of canvas to create.
- height: Height of canvas to create.
- """
- binary = find_run_binary.find_path_to_program('skpmaker')
- return subprocess.check_output([
- binary,
- '--red', str(red),
- '--green', str(green),
- '--blue', str(blue),
- '--width', str(width),
- '--height', str(height),
- '--writePath', str(output_path)])
-
-def mock_get_timestamp():
- """Mock version of BaseComparisons.get_timestamp() for testing."""
- return 12345678
-
-
-def main():
- base_unittest.main(CompareRenderedPicturesTest)
-
-
-if __name__ == '__main__':
- main()
diff --git a/gm/rebaseline_server/compare_to_expectations.py b/gm/rebaseline_server/compare_to_expectations.py
deleted file mode 100755
index 303294c0ae..0000000000
--- a/gm/rebaseline_server/compare_to_expectations.py
+++ /dev/null
@@ -1,415 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2013 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Repackage expected/actual GM results as needed by our HTML rebaseline viewer.
-"""
-
-# System-level imports
-import argparse
-import fnmatch
-import logging
-import os
-import time
-
-# Must fix up PYTHONPATH before importing from within Skia
-import rs_fixpypath # pylint: disable=W0611
-
-# Imports from within Skia
-from py.utils import url_utils
-import column
-import gm_json
-import imagediffdb
-import imagepair
-import imagepairset
-import results
-
-EXPECTATION_FIELDS_PASSED_THRU_VERBATIM = [
- results.KEY__EXPECTATIONS__BUGS,
- results.KEY__EXPECTATIONS__IGNOREFAILURE,
- results.KEY__EXPECTATIONS__REVIEWED,
-]
-FREEFORM_COLUMN_IDS = [
- results.KEY__EXTRACOLUMNS__BUILDER,
- results.KEY__EXTRACOLUMNS__TEST,
-]
-ORDERED_COLUMN_IDS = [
- results.KEY__EXTRACOLUMNS__RESULT_TYPE,
- results.KEY__EXTRACOLUMNS__BUILDER,
- results.KEY__EXTRACOLUMNS__TEST,
- results.KEY__EXTRACOLUMNS__CONFIG,
-]
-
-TRUNK_DIRECTORY = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
-DEFAULT_EXPECTATIONS_DIR = os.path.join(TRUNK_DIRECTORY, 'expectations', 'gm')
-DEFAULT_IGNORE_FAILURES_FILE = 'ignored-tests.txt'
-
-IMAGEPAIR_SET_DESCRIPTIONS = ('expected image', 'actual image')
-
-
-class ExpectationComparisons(results.BaseComparisons):
- """Loads actual and expected GM results into an ImagePairSet.
-
- Loads actual and expected results from all builders, except for those skipped
- by _ignore_builder().
-
- Once this object has been constructed, the results (in self._results[])
- are immutable. If you want to update the results based on updated JSON
- file contents, you will need to create a new ExpectationComparisons object."""
-
- def __init__(self, image_diff_db, actuals_root=results.DEFAULT_ACTUALS_DIR,
- expected_root=DEFAULT_EXPECTATIONS_DIR,
- ignore_failures_file=DEFAULT_IGNORE_FAILURES_FILE,
- diff_base_url=None, builder_regex_list=None):
- """
- Args:
- image_diff_db: instance of ImageDiffDB we use to cache the image diffs
- actuals_root: root directory containing all actual-results.json files
- expected_root: root directory containing all expected-results.json files
- ignore_failures_file: if a file with this name is found within
- expected_root, ignore failures for any tests listed in the file
- diff_base_url: base URL within which the client should look for diff
- images; if not specified, defaults to a "file:///" URL representation
- of image_diff_db's storage_root
- builder_regex_list: List of regular expressions specifying which builders
- we will process. If None, process all builders.
- """
- super(ExpectationComparisons, self).__init__()
- time_start = int(time.time())
- if builder_regex_list != None:
- self.set_match_builders_pattern_list(builder_regex_list)
- self._image_diff_db = image_diff_db
- self._diff_base_url = (
- diff_base_url or
- url_utils.create_filepath_url(image_diff_db.storage_root))
- self._actuals_root = actuals_root
- self._expected_root = expected_root
- self._ignore_failures_on_these_tests = []
- if ignore_failures_file:
- self._ignore_failures_on_these_tests = (
- ExpectationComparisons._read_noncomment_lines(
- os.path.join(expected_root, ignore_failures_file)))
- self._load_actual_and_expected()
- self._timestamp = int(time.time())
- logging.info('Results complete; took %d seconds.' %
- (self._timestamp - time_start))
-
- def edit_expectations(self, modifications):
- """Edit the expectations stored within this object and write them back
- to disk.
-
- Note that this will NOT update the results stored in self._results[] ;
- in order to see those updates, you must instantiate a new
- ExpectationComparisons object based on the (now updated) files on disk.
-
- Args:
- modifications: a list of dictionaries, one for each expectation to update:
-
- [
- {
- imagepair.KEY__IMAGEPAIRS__EXPECTATIONS: {
- results.KEY__EXPECTATIONS__BUGS: [123, 456],
- results.KEY__EXPECTATIONS__IGNOREFAILURE: false,
- results.KEY__EXPECTATIONS__REVIEWED: true,
- },
- imagepair.KEY__IMAGEPAIRS__EXTRACOLUMNS: {
- results.KEY__EXTRACOLUMNS__BUILDER: 'Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug',
- results.KEY__EXTRACOLUMNS__CONFIG: '8888',
- results.KEY__EXTRACOLUMNS__TEST: 'bigmatrix',
- },
- results.KEY__IMAGEPAIRS__IMAGE_B_URL: 'bitmap-64bitMD5/bigmatrix/10894408024079689926.png',
- },
- ...
- ]
-
- """
- expected_builder_dicts = self._read_builder_dicts_from_root(
- self._expected_root)
- for mod in modifications:
- image_name = results.IMAGE_FILENAME_FORMATTER % (
- mod[imagepair.KEY__IMAGEPAIRS__EXTRACOLUMNS]
- [results.KEY__EXTRACOLUMNS__TEST],
- mod[imagepair.KEY__IMAGEPAIRS__EXTRACOLUMNS]
- [results.KEY__EXTRACOLUMNS__CONFIG])
- _, hash_type, hash_digest = gm_json.SplitGmRelativeUrl(
- mod[imagepair.KEY__IMAGEPAIRS__IMAGE_B_URL])
- allowed_digests = [[hash_type, int(hash_digest)]]
- new_expectations = {
- gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS: allowed_digests,
- }
- for field in EXPECTATION_FIELDS_PASSED_THRU_VERBATIM:
- value = mod[imagepair.KEY__IMAGEPAIRS__EXPECTATIONS].get(field)
- if value is not None:
- new_expectations[field] = value
- builder_dict = expected_builder_dicts[
- mod[imagepair.KEY__IMAGEPAIRS__EXTRACOLUMNS]
- [results.KEY__EXTRACOLUMNS__BUILDER]]
- builder_expectations = builder_dict.get(gm_json.JSONKEY_EXPECTEDRESULTS)
- if not builder_expectations:
- builder_expectations = {}
- builder_dict[gm_json.JSONKEY_EXPECTEDRESULTS] = builder_expectations
- builder_expectations[image_name] = new_expectations
- ExpectationComparisons._write_dicts_to_root(
- expected_builder_dicts, self._expected_root)
-
- @staticmethod
- def _write_dicts_to_root(meta_dict, root, pattern='*.json'):
- """Write all per-builder dictionaries within meta_dict to files under
- the root path.
-
- Security note: this will only write to files that already exist within
- the root path (as found by os.walk() within root), so we don't need to
- worry about malformed content writing to disk outside of root.
- However, the data written to those files is not double-checked, so it
- could contain poisonous data.
-
- Args:
- meta_dict: a builder-keyed meta-dictionary containing all the JSON
- dictionaries we want to write out
- root: path to root of directory tree within which to write files
- pattern: which files to write within root (fnmatch-style pattern)
-
- Raises:
- IOError if root does not refer to an existing directory
- KeyError if the set of per-builder dictionaries written out was
- different than expected
- """
- if not os.path.isdir(root):
- raise IOError('no directory found at path %s' % root)
- actual_builders_written = []
- for dirpath, _, filenames in os.walk(root):
- for matching_filename in fnmatch.filter(filenames, pattern):
- builder = os.path.basename(dirpath)
- per_builder_dict = meta_dict.get(builder)
- if per_builder_dict is not None:
- fullpath = os.path.join(dirpath, matching_filename)
- gm_json.WriteToFile(per_builder_dict, fullpath)
- actual_builders_written.append(builder)
-
- # Check: did we write out the set of per-builder dictionaries we
- # expected to?
- expected_builders_written = sorted(meta_dict.keys())
- actual_builders_written.sort()
- if expected_builders_written != actual_builders_written:
- raise KeyError(
- 'expected to write dicts for builders %s, but actually wrote them '
- 'for builders %s' % (
- expected_builders_written, actual_builders_written))
-
- def _load_actual_and_expected(self):
- """Loads the results of all tests, across all builders (based on the
- files within self._actuals_root and self._expected_root),
- and stores them in self._results.
- """
- logging.info('Reading actual-results JSON files from %s...' %
- self._actuals_root)
- actual_builder_dicts = self._read_builder_dicts_from_root(
- self._actuals_root)
- logging.info('Reading expected-results JSON files from %s...' %
- self._expected_root)
- expected_builder_dicts = self._read_builder_dicts_from_root(
- self._expected_root)
-
- all_image_pairs = imagepairset.ImagePairSet(
- descriptions=IMAGEPAIR_SET_DESCRIPTIONS,
- diff_base_url=self._diff_base_url)
- failing_image_pairs = imagepairset.ImagePairSet(
- descriptions=IMAGEPAIR_SET_DESCRIPTIONS,
- diff_base_url=self._diff_base_url)
-
- # Override settings for columns that should be filtered using freeform text.
- for column_id in FREEFORM_COLUMN_IDS:
- factory = column.ColumnHeaderFactory(
- header_text=column_id, use_freeform_filter=True)
- all_image_pairs.set_column_header_factory(
- column_id=column_id, column_header_factory=factory)
- failing_image_pairs.set_column_header_factory(
- column_id=column_id, column_header_factory=factory)
-
- all_image_pairs.ensure_extra_column_values_in_summary(
- column_id=results.KEY__EXTRACOLUMNS__RESULT_TYPE, values=[
- results.KEY__RESULT_TYPE__FAILED,
- results.KEY__RESULT_TYPE__FAILUREIGNORED,
- results.KEY__RESULT_TYPE__NOCOMPARISON,
- results.KEY__RESULT_TYPE__SUCCEEDED,
- ])
- failing_image_pairs.ensure_extra_column_values_in_summary(
- column_id=results.KEY__EXTRACOLUMNS__RESULT_TYPE, values=[
- results.KEY__RESULT_TYPE__FAILED,
- results.KEY__RESULT_TYPE__FAILUREIGNORED,
- results.KEY__RESULT_TYPE__NOCOMPARISON,
- ])
-
- # Only consider builders we have both expected and actual results for.
- # Fixes http://skbug.com/2486 ('rebaseline_server shows actual results
- # (but not expectations) for Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug
- # builder')
- actual_builder_set = set(actual_builder_dicts.keys())
- expected_builder_set = set(expected_builder_dicts.keys())
- builders = sorted(actual_builder_set.intersection(expected_builder_set))
-
- num_builders = len(builders)
- builder_num = 0
- for builder in builders:
- builder_num += 1
- logging.info('Generating pixel diffs for builder #%d of %d, "%s"...' %
- (builder_num, num_builders, builder))
- actual_results_for_this_builder = (
- actual_builder_dicts[builder][gm_json.JSONKEY_ACTUALRESULTS])
- for result_type in sorted(actual_results_for_this_builder.keys()):
- results_of_this_type = actual_results_for_this_builder[result_type]
- if not results_of_this_type:
- continue
- for image_name in sorted(results_of_this_type.keys()):
- (test, config) = results.IMAGE_FILENAME_RE.match(image_name).groups()
- actual_image_relative_url = (
- ExpectationComparisons._create_relative_url(
- hashtype_and_digest=results_of_this_type[image_name],
- test_name=test))
-
- # Default empty expectations; overwrite these if we find any real ones
- expectations_per_test = None
- expected_image_relative_url = None
- expectations_dict = None
- try:
- expectations_per_test = (
- expected_builder_dicts
- [builder][gm_json.JSONKEY_EXPECTEDRESULTS][image_name])
- # TODO(epoger): assumes a single allowed digest per test, which is
- # fine; see https://code.google.com/p/skia/issues/detail?id=1787
- expected_image_hashtype_and_digest = (
- expectations_per_test
- [gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS][0])
- expected_image_relative_url = (
- ExpectationComparisons._create_relative_url(
- hashtype_and_digest=expected_image_hashtype_and_digest,
- test_name=test))
- expectations_dict = {}
- for field in EXPECTATION_FIELDS_PASSED_THRU_VERBATIM:
- expectations_dict[field] = expectations_per_test.get(field)
- except (KeyError, TypeError):
- # There are several cases in which we would expect to find
- # no expectations for a given test:
- #
- # 1. result_type == NOCOMPARISON
- # There are no expectations for this test yet!
- #
- # 2. alternate rendering mode failures (e.g. serialized)
- # In cases like
- # https://code.google.com/p/skia/issues/detail?id=1684
- # ('tileimagefilter GM test failing in serialized render mode'),
- # the gm-actuals will list a failure for the alternate
- # rendering mode even though we don't have explicit expectations
- # for the test (the implicit expectation is that it must
- # render the same in all rendering modes).
- #
- # Don't log type 1, because it is common.
- # Log other types, because they are rare and we should know about
- # them, but don't throw an exception, because we need to keep our
- # tools working in the meanwhile!
- if result_type != results.KEY__RESULT_TYPE__NOCOMPARISON:
- logging.warning('No expectations found for test: %s' % {
- results.KEY__EXTRACOLUMNS__BUILDER: builder,
- results.KEY__EXTRACOLUMNS__RESULT_TYPE: result_type,
- 'image_name': image_name,
- })
-
- # If this test was recently rebaselined, it will remain in
- # the 'failed' set of actuals until all the bots have
- # cycled (although the expectations have indeed been set
- # from the most recent actuals). Treat these as successes
- # instead of failures.
- #
- # TODO(epoger): Do we need to do something similar in
- # other cases, such as when we have recently marked a test
- # as ignoreFailure but it still shows up in the 'failed'
- # category? Maybe we should not rely on the result_type
- # categories recorded within the gm_actuals AT ALL, and
- # instead evaluate the result_type ourselves based on what
- # we see in expectations vs actual checksum?
- if expected_image_relative_url == actual_image_relative_url:
- updated_result_type = results.KEY__RESULT_TYPE__SUCCEEDED
- elif ((result_type == results.KEY__RESULT_TYPE__FAILED) and
- (test in self._ignore_failures_on_these_tests)):
- updated_result_type = results.KEY__RESULT_TYPE__FAILUREIGNORED
- else:
- updated_result_type = result_type
- extra_columns_dict = {
- results.KEY__EXTRACOLUMNS__RESULT_TYPE: updated_result_type,
- results.KEY__EXTRACOLUMNS__BUILDER: builder,
- results.KEY__EXTRACOLUMNS__TEST: test,
- results.KEY__EXTRACOLUMNS__CONFIG: config,
- }
- try:
- image_pair = imagepair.ImagePair(
- image_diff_db=self._image_diff_db,
- imageA_base_url=gm_json.GM_ACTUALS_ROOT_HTTP_URL,
- imageB_base_url=gm_json.GM_ACTUALS_ROOT_HTTP_URL,
- imageA_relative_url=expected_image_relative_url,
- imageB_relative_url=actual_image_relative_url,
- expectations=expectations_dict,
- extra_columns=extra_columns_dict)
- all_image_pairs.add_image_pair(image_pair)
- if updated_result_type != results.KEY__RESULT_TYPE__SUCCEEDED:
- failing_image_pairs.add_image_pair(image_pair)
- except Exception:
- logging.exception('got exception while creating new ImagePair')
-
- # pylint: disable=W0201
- self._results = {
- results.KEY__HEADER__RESULTS_ALL: all_image_pairs.as_dict(
- column_ids_in_order=ORDERED_COLUMN_IDS),
- results.KEY__HEADER__RESULTS_FAILURES: failing_image_pairs.as_dict(
- column_ids_in_order=ORDERED_COLUMN_IDS),
- }
-
-
-def main():
- logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
- datefmt='%m/%d/%Y %H:%M:%S',
- level=logging.INFO)
- parser = argparse.ArgumentParser()
- parser.add_argument(
- '--actuals', default=results.DEFAULT_ACTUALS_DIR,
- help='Directory containing all actual-result JSON files; defaults to '
- '\'%(default)s\' .')
- parser.add_argument(
- '--expectations', default=DEFAULT_EXPECTATIONS_DIR,
- help='Directory containing all expected-result JSON files; defaults to '
- '\'%(default)s\' .')
- parser.add_argument(
- '--ignore-failures-file', default=DEFAULT_IGNORE_FAILURES_FILE,
- help='If a file with this name is found within the EXPECTATIONS dir, '
- 'ignore failures for any tests listed in the file; defaults to '
- '\'%(default)s\' .')
- parser.add_argument(
- '--outfile', required=True,
- help='File to write result summary into, in JSON format.')
- parser.add_argument(
- '--results', default=results.KEY__HEADER__RESULTS_FAILURES,
- help='Which result types to include. Defaults to \'%(default)s\'; '
- 'must be one of ' +
- str([results.KEY__HEADER__RESULTS_FAILURES,
- results.KEY__HEADER__RESULTS_ALL]))
- parser.add_argument(
- '--workdir', default=results.DEFAULT_GENERATED_IMAGES_ROOT,
- help='Directory within which to download images and generate diffs; '
- 'defaults to \'%(default)s\' .')
- args = parser.parse_args()
- image_diff_db = imagediffdb.ImageDiffDB(storage_root=args.workdir)
- results_obj = ExpectationComparisons(
- image_diff_db=image_diff_db,
- actuals_root=args.actuals,
- expected_root=args.expectations,
- ignore_failures_file=args.ignore_failures_file)
- gm_json.WriteToFile(
- results_obj.get_packaged_results_of_type(results_type=args.results),
- args.outfile)
-
-
-if __name__ == '__main__':
- main()
diff --git a/gm/rebaseline_server/compare_to_expectations_test.py b/gm/rebaseline_server/compare_to_expectations_test.py
deleted file mode 100755
index 2997cde67f..0000000000
--- a/gm/rebaseline_server/compare_to_expectations_test.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2013 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Test compare_to_expectations.py
-
-TODO(epoger): Create a command to update the expected results (in
-self._output_dir_expected) when appropriate. For now, you should:
-1. examine the results in self.output_dir_actual and make sure they are ok
-2. rm -rf self._output_dir_expected
-3. mv self.output_dir_actual self._output_dir_expected
-Although, if you're using an SVN checkout, this will blow away .svn directories
-within self._output_dir_expected, which wouldn't be good...
-
-"""
-
-import os
-
-# Imports from within Skia
-import base_unittest
-import compare_to_expectations
-import imagediffdb
-import results
-import gm_json # must import results first, so that gm_json will be in sys.path
-
-
-class CompareToExpectationsTest(base_unittest.TestCase):
-
- def test_gm(self):
- """Process results of a GM run with the ExpectationComparisons object."""
- image_diff_db = imagediffdb.ImageDiffDB(storage_root=self.temp_dir)
- results_obj = compare_to_expectations.ExpectationComparisons(
- image_diff_db=image_diff_db,
- actuals_root=os.path.join(self.input_dir, 'gm-actuals'),
- expected_root=os.path.join(self.input_dir, 'gm-expectations'),
- diff_base_url='/static/generated-images')
- results_obj.get_timestamp = mock_get_timestamp
- gm_json.WriteToFile(
- results_obj.get_packaged_results_of_type(
- results.KEY__HEADER__RESULTS_ALL),
- os.path.join(self.output_dir_actual, 'gm.json'))
-
-
-def mock_get_timestamp():
- """Mock version of BaseComparisons.get_timestamp() for testing."""
- return 12345678
-
-
-def main():
- base_unittest.main(CompareToExpectationsTest)
-
-
-if __name__ == '__main__':
- main()
diff --git a/gm/rebaseline_server/download_actuals.py b/gm/rebaseline_server/download_actuals.py
deleted file mode 100755
index 0e60289573..0000000000
--- a/gm/rebaseline_server/download_actuals.py
+++ /dev/null
@@ -1,289 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Download actual GM results for a particular builder.
-"""
-
-# System-level imports
-import httplib
-import logging
-import optparse
-import os
-import posixpath
-import re
-import urllib2
-
-# Must fix up PYTHONPATH before importing from within Skia
-import rs_fixpypath # pylint: disable=W0611
-
-# Imports from within Skia
-from py.utils import gs_utils
-from py.utils import url_utils
-import buildbot_globals
-import gm_json
-
-
-GM_SUMMARIES_BUCKET = buildbot_globals.Get('gm_summaries_bucket')
-DEFAULT_ACTUALS_BASE_URL = (
- 'http://storage.googleapis.com/%s' % GM_SUMMARIES_BUCKET)
-DEFAULT_JSON_FILENAME = 'actual-results.json'
-
-
-class Download(object):
-
- def __init__(self, actuals_base_url=DEFAULT_ACTUALS_BASE_URL,
- json_filename=DEFAULT_JSON_FILENAME,
- gm_actuals_root_url=gm_json.GM_ACTUALS_ROOT_HTTP_URL):
- """
- Args:
- actuals_base_url: URL pointing at the root directory
- containing all actual-results.json files, e.g.,
- http://domain.name/path/to/dir OR
- file:///absolute/path/to/localdir
- json_filename: The JSON filename to read from within each directory.
- gm_actuals_root_url: Base URL under which the actually-generated-by-bots
- GM images are stored.
- """
- self._actuals_base_url = actuals_base_url
- self._json_filename = json_filename
- self._gm_actuals_root_url = gm_actuals_root_url
- self._image_filename_re = re.compile(gm_json.IMAGE_FILENAME_PATTERN)
-
- def fetch(self, builder_name, dest_dir):
- """ Downloads actual GM results for a particular builder.
-
- Args:
- builder_name: which builder to download results of
- dest_dir: path to directory where the image files will be written;
- if the directory does not exist yet, it will be created
-
- TODO(epoger): Display progress info. Right now, it can take a long time
- to download all of the results, and there is no indication of progress.
-
- TODO(epoger): Download multiple images in parallel to speed things up.
- """
- json_url = posixpath.join(self._actuals_base_url, builder_name,
- self._json_filename)
- json_contents = urllib2.urlopen(json_url).read()
- results_dict = gm_json.LoadFromString(json_contents)
-
- actual_results_dict = results_dict[gm_json.JSONKEY_ACTUALRESULTS]
- for result_type in sorted(actual_results_dict.keys()):
- results_of_this_type = actual_results_dict[result_type]
- if not results_of_this_type:
- continue
- for image_name in sorted(results_of_this_type.keys()):
- (test, config) = self._image_filename_re.match(image_name).groups()
- (hash_type, hash_digest) = results_of_this_type[image_name]
- source_url = gm_json.CreateGmActualUrl(
- test_name=test, hash_type=hash_type, hash_digest=hash_digest,
- gm_actuals_root_url=self._gm_actuals_root_url)
- dest_path = os.path.join(dest_dir, config, test + '.png')
- url_utils.copy_contents(source_url=source_url, dest_path=dest_path,
- create_subdirs_if_needed=True)
-
-
-def get_builders_list(summaries_bucket=GM_SUMMARIES_BUCKET):
- """ Returns the list of builders we have actual results for.
-
- Args:
- summaries_bucket: Google Cloud Storage bucket containing the summary
- JSON files
- """
- dirs, _ = gs_utils.GSUtils().list_bucket_contents(bucket=GM_SUMMARIES_BUCKET)
- return dirs
-
-
-class ActualLocation(object):
- def __init__(self, bucket, path, generation):
- self.bucket = bucket
- self.path = path
- self.generation = generation
-
-
-class TipOfTreeActuals(object):
- def __init__(self, summaries_bucket=GM_SUMMARIES_BUCKET,
- json_filename=DEFAULT_JSON_FILENAME):
- """
- Args:
- summaries_bucket: URL pointing at the root directory
- containing all actual-results.json files, e.g.,
- http://domain.name/path/to/dir OR
- file:///absolute/path/to/localdir
- json_filename: The JSON filename to read from within each directory.
- """
- self._json_filename = json_filename
- self._summaries_bucket = summaries_bucket
-
- def description(self):
- return 'gm_summaries_bucket %s' % (self._summaries_bucket,)
-
- def get_builders(self):
- """ Returns the list of builders we have actual results for.
- {builder:string -> ActualLocation}
- """
- dirs = get_builders_list(self._summaries_bucket)
- result = dict()
- for builder in dirs:
- result[builder] = ActualLocation(
- self._summaries_bucket,
- "%s/%s" % (builder, self._json_filename),
- None)
- return result
-
-
-class RietveldIssueActuals(object):
- def __init__(self, issue, json_filename=DEFAULT_JSON_FILENAME):
- """
- Args:
- issue: The rietveld issue from which to obtain actuals.
- json_filename: The JSON filename to read from within each directory.
- """
- self._issue = issue
- self._json_filename = json_filename
-
- def description(self):
- return 'rietveld issue %s' % (self._issue,)
-
- def get_builders(self):
- """ Returns the actuals for the given rietveld issue's tryjobs.
- {builder:string -> ActualLocation}
-
- e.g.
- {'Test-Android-Xoom-Tegra2-Arm7-Release': (
- 'chromium-skia-gm-summaries',
- 'Test-Android-Xoom-Tegra2-Arm7-Release-Trybot/actual-results.json',
- '1415041165535000')}
- """
- result = dict()
- json_filename_re = re.compile(
- 'Created: gs://([^/]+)/((?:[^/]+/)+%s)#(\d+)'
- % re.escape(self._json_filename))
- codereview_api_url = 'https://codereview.chromium.org/api'
- upload_gm_step_url = '/steps/Upload GM Results/logs/stdio'
-
- logging.info('Fetching issue %s ...' % (self._issue,))
- json_issue_url = '%s/%s' % (codereview_api_url, self._issue)
- json_issue_data = urllib2.urlopen(json_issue_url).read()
- issue_dict = gm_json.LoadFromString(json_issue_data)
-
- patchsets = issue_dict.get("patchsets", [])
- patchset = patchsets[-1]
- if not patchset:
- logging.warning('No patchsets for rietveld issue %s.' % (self._issue,))
- return result
-
- logging.info('Fetching issue %s patch %s...' % (self._issue, patchset))
- json_patchset_url = '%s/%s/%s' % (codereview_api_url, self._issue, patchset)
- json_patchset_data = urllib2.urlopen(json_patchset_url).read()
- patchset_dict = gm_json.LoadFromString(json_patchset_data)
-
- # try_job_results is ordered reverse chronologically
- try_job_results = patchset_dict.get('try_job_results', [])
- for try_job_result in try_job_results:
- try_builder = try_job_result.get('builder', '<bad builder>')
- if not try_builder.endswith('-Trybot'):
- logging.warning('Builder %s is not a trybot?' % (try_builder,))
- continue
- builder = try_builder[:-len('-Trybot')]
- if builder in result:
- continue
-
- logging.info('Fetching issue %s patch %s try %s...' %
- (self._issue, patchset, try_builder))
- build_url = try_job_result.get('url', '<bad url>')
- if build_url is None:
- logging.warning('Builder %s has not started.' % (try_builder,))
- continue
- gm_upload_output_url = build_url + urllib2.quote(upload_gm_step_url)
- logging.info('Fetching %s ...' % (gm_upload_output_url,))
-
- # Tryjobs might not produce the step, but don't let that fail everything.
- gm_upload_output = None
- try:
- gm_upload_output = urllib2.urlopen(gm_upload_output_url).read()
- except (urllib2.HTTPError, urllib2.URLError, httplib.HTTPException) as e:
- logging.warning(e)
- except Exception:
- logging.exception('Error opening %s .' % (gm_upload_output_url,))
- if not gm_upload_output:
- logging.warning('Could not fetch %s .' % (gm_upload_output_url,))
- continue
-
- json_filename_match = json_filename_re.search(gm_upload_output)
- if json_filename_match:
- logging.info('Found issue %s patch %s try %s result gs://%s/%s#%s .' %
- (self._issue, patchset, builder,
- json_filename_match.group(1),
- json_filename_match.group(2),
- json_filename_match.group(3)))
- result[builder] = ActualLocation(json_filename_match.group(1),
- json_filename_match.group(2),
- json_filename_match.group(3))
- else:
- logging.warning('Did not find %s for issue %s patch %s try %s.' %
- (self._json_filename, self._issue, patchset, try_builder))
-
- return result
-
-
-def main():
- parser = optparse.OptionParser()
- required_params = []
- parser.add_option('--actuals-base-url',
- action='store', type='string',
- default=DEFAULT_ACTUALS_BASE_URL,
- help=('Base URL from which to read files containing JSON '
- 'summaries of actual GM results; defaults to '
- '"%default".'))
- required_params.append('builder')
- # TODO(epoger): Before https://codereview.chromium.org/309653005 , when this
- # tool downloaded the JSON summaries from skia-autogen, it had the ability
- # to get results as of a specific revision number. We should add similar
- # functionality when retrieving the summaries from Google Storage.
- parser.add_option('--builder',
- action='store', type='string',
- help=('REQUIRED: Which builder to download results for. '
- 'To see a list of builders, run with the '
- '--list-builders option set.'))
- required_params.append('dest_dir')
- parser.add_option('--dest-dir',
- action='store', type='string',
- help=('REQUIRED: Directory where all images should be '
- 'written. If this directory does not exist yet, it '
- 'will be created.'))
- parser.add_option('--json-filename',
- action='store', type='string',
- default=DEFAULT_JSON_FILENAME,
- help=('JSON summary filename to read for each builder; '
- 'defaults to "%default".'))
- parser.add_option('--list-builders', action='store_true',
- help=('List all available builders.'))
- (params, remaining_args) = parser.parse_args()
-
- if params.list_builders:
- print '\n'.join(get_builders_list())
- return
-
- # Make sure all required options were set,
- # and that there were no items left over in the command line.
- for required_param in required_params:
- if not getattr(params, required_param):
- raise Exception('required option \'%s\' was not set' % required_param)
- if len(remaining_args) is not 0:
- raise Exception('extra items specified in the command line: %s' %
- remaining_args)
-
- downloader = Download(actuals_base_url=params.actuals_base_url)
- downloader.fetch(builder_name=params.builder,
- dest_dir=params.dest_dir)
-
-
-
-if __name__ == '__main__':
- main()
diff --git a/gm/rebaseline_server/download_actuals_test.py b/gm/rebaseline_server/download_actuals_test.py
deleted file mode 100755
index b9822245a3..0000000000
--- a/gm/rebaseline_server/download_actuals_test.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Test download.py
-
-TODO(epoger): Create a command to update the expected results (in
-self._output_dir_expected) when appropriate. For now, you should:
-1. examine the results in self.output_dir_actual and make sure they are ok
-2. rm -rf self._output_dir_expected
-3. mv self.output_dir_actual self._output_dir_expected
-Although, if you're using an SVN checkout, this will blow away .svn directories
-within self._output_dir_expected, which wouldn't be good...
-
-"""
-
-# System-level imports
-import os
-
-# Must fix up PYTHONPATH before importing from within Skia
-import rs_fixpypath # pylint: disable=W0611
-
-# Imports from within Skia
-from py.utils import url_utils
-import base_unittest
-import download_actuals
-
-
-class DownloadTest(base_unittest.TestCase):
-
- def test_fetch(self):
- """Tests fetch() of GM results from actual-results.json ."""
- downloader = download_actuals.Download(
- actuals_base_url=url_utils.create_filepath_url(
- os.path.join(self.input_dir, 'gm-actuals')),
- gm_actuals_root_url=url_utils.create_filepath_url(
- os.path.join(self.input_dir, 'fake-gm-imagefiles')))
- downloader.fetch(
- builder_name='Test-Android-GalaxyNexus-SGX540-Arm7-Release',
- dest_dir=self.output_dir_actual)
-
-
-def main():
- base_unittest.main(DownloadTest)
-
-
-if __name__ == '__main__':
- main()
diff --git a/gm/rebaseline_server/imagediffdb.py b/gm/rebaseline_server/imagediffdb.py
deleted file mode 100644
index 0bc75cfca4..0000000000
--- a/gm/rebaseline_server/imagediffdb.py
+++ /dev/null
@@ -1,477 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2013 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Calulate differences between image pairs, and store them in a database.
-"""
-
-# System-level imports
-import contextlib
-import errno
-import json
-import logging
-import os
-import Queue
-import re
-import shutil
-import tempfile
-import threading
-import time
-import urllib
-
-# Must fix up PYTHONPATH before importing from within Skia
-import rs_fixpypath # pylint: disable=W0611
-
-# Imports from within Skia
-import find_run_binary
-from py.utils import gs_utils
-
-
-SKPDIFF_BINARY = find_run_binary.find_path_to_program('skpdiff')
-
-DEFAULT_IMAGE_SUFFIX = '.png'
-DEFAULT_IMAGES_SUBDIR = 'images'
-# TODO(epoger): Figure out a better default number of threads; for now,
-# using a conservative default value.
-DEFAULT_NUM_WORKER_THREADS = 1
-
-DISALLOWED_FILEPATH_CHAR_REGEX = re.compile('[^\w\-]')
-
-RGBDIFFS_SUBDIR = 'diffs'
-WHITEDIFFS_SUBDIR = 'whitediffs'
-
-# Keys used within DiffRecord dictionary representations.
-# NOTE: Keep these in sync with static/constants.js
-KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL = 'maxDiffPerChannel'
-KEY__DIFFERENCES__NUM_DIFF_PIXELS = 'numDifferingPixels'
-KEY__DIFFERENCES__PERCENT_DIFF_PIXELS = 'percentDifferingPixels'
-KEY__DIFFERENCES__PERCEPTUAL_DIFF = 'perceptualDifference'
-KEY__DIFFERENCES__DIFF_URL = 'diffUrl'
-KEY__DIFFERENCES__WHITE_DIFF_URL = 'whiteDiffUrl'
-
-# Special values within ImageDiffDB._diff_dict
-_DIFFRECORD_FAILED = 'failed'
-_DIFFRECORD_PENDING = 'pending'
-
-# How often to report tasks_queue size
-QUEUE_LOGGING_GRANULARITY = 1000
-
-# Temporary variable to keep track of how many times we download
-# the same file in multiple threads.
-# TODO(epoger): Delete this, once we see that the number stays close to 0.
-global_file_collisions = 0
-
-
-class DiffRecord(object):
- """ Record of differences between two images. """
-
- def __init__(self, gs, storage_root,
- expected_image_url, expected_image_locator,
- actual_image_url, actual_image_locator,
- expected_images_subdir=DEFAULT_IMAGES_SUBDIR,
- actual_images_subdir=DEFAULT_IMAGES_SUBDIR,
- image_suffix=DEFAULT_IMAGE_SUFFIX):
- """Download this pair of images (unless we already have them on local disk),
- and prepare a DiffRecord for them.
-
- Args:
- gs: instance of GSUtils object we can use to download images
- storage_root: root directory on local disk within which we store all
- images
- expected_image_url: file, GS, or HTTP url from which we will download the
- expected image
- expected_image_locator: a unique ID string under which we will store the
- expected image within storage_root (probably including a checksum to
- guarantee uniqueness)
- actual_image_url: file, GS, or HTTP url from which we will download the
- actual image
- actual_image_locator: a unique ID string under which we will store the
- actual image within storage_root (probably including a checksum to
- guarantee uniqueness)
- expected_images_subdir: the subdirectory expected images are stored in.
- actual_images_subdir: the subdirectory actual images are stored in.
- image_suffix: the suffix of images.
- """
- expected_image_locator = _sanitize_locator(expected_image_locator)
- actual_image_locator = _sanitize_locator(actual_image_locator)
-
- # Download the expected/actual images, if we don't have them already.
- expected_image_file = os.path.join(
- storage_root, expected_images_subdir,
- str(expected_image_locator) + image_suffix)
- actual_image_file = os.path.join(
- storage_root, actual_images_subdir,
- str(actual_image_locator) + image_suffix)
- for image_file, image_url in [
- (expected_image_file, expected_image_url),
- (actual_image_file, actual_image_url)]:
- if image_file and image_url:
- try:
- _download_file(gs, image_file, image_url)
- except Exception:
- logging.exception('unable to download image_url %s to file %s' %
- (image_url, image_file))
- raise
-
- # Return early if we do not need to generate diffs.
- if (expected_image_url == actual_image_url or
- not expected_image_url or not actual_image_url):
- return
-
- # Get all diff images and values using the skpdiff binary.
- skpdiff_output_dir = tempfile.mkdtemp()
- try:
- skpdiff_summary_file = os.path.join(skpdiff_output_dir,
- 'skpdiff-output.json')
- skpdiff_rgbdiff_dir = os.path.join(storage_root, RGBDIFFS_SUBDIR)
- skpdiff_whitediff_dir = os.path.join(storage_root, WHITEDIFFS_SUBDIR)
- _mkdir_unless_exists(skpdiff_rgbdiff_dir)
- _mkdir_unless_exists(skpdiff_rgbdiff_dir)
-
- # TODO(epoger): Consider calling skpdiff ONCE for all image pairs,
- # instead of calling it separately for each image pair.
- # Pro: we'll incur less overhead from making repeated system calls,
- # spinning up the skpdiff binary, etc.
- # Con: we would have to wait until all image pairs were loaded before
- # generating any of the diffs?
- # Note(stephana): '--longnames' was added to allow for this
- # case (multiple files at once) versus specifying output diffs
- # directly.
- find_run_binary.run_command(
- [SKPDIFF_BINARY, '-p', expected_image_file, actual_image_file,
- '--jsonp', 'false',
- '--longnames', 'true',
- '--output', skpdiff_summary_file,
- '--differs', 'perceptual', 'different_pixels',
- '--rgbDiffDir', skpdiff_rgbdiff_dir,
- '--whiteDiffDir', skpdiff_whitediff_dir,
- ])
-
- # Get information out of the skpdiff_summary_file.
- with contextlib.closing(open(skpdiff_summary_file)) as fp:
- data = json.load(fp)
-
- # For now, we can assume there is only one record in the output summary,
- # since we passed skpdiff only one pair of images.
- record = data['records'][0]
- self._width = record['width']
- self._height = record['height']
- self._diffUrl = os.path.split(record['rgbDiffPath'])[1]
- self._whiteDiffUrl = os.path.split(record['whiteDiffPath'])[1]
-
- # TODO: make max_diff_per_channel a tuple instead of a list, because the
- # structure is meaningful (first element is red, second is green, etc.)
- # See http://stackoverflow.com/a/626871
- self._max_diff_per_channel = [
- record['maxRedDiff'], record['maxGreenDiff'], record['maxBlueDiff']]
- per_differ_stats = record['diffs']
- for stats in per_differ_stats:
- differ_name = stats['differName']
- if differ_name == 'different_pixels':
- self._num_pixels_differing = stats['pointsOfInterest']
- elif differ_name == 'perceptual':
- perceptual_similarity = stats['result']
-
- # skpdiff returns the perceptual similarity; convert it to get the
- # perceptual difference percentage.
- # skpdiff outputs -1 if the images are different sizes. Treat any
- # output that does not lie in [0, 1] as having 0% perceptual
- # similarity.
- if not 0 <= perceptual_similarity <= 1:
- perceptual_similarity = 0
- self._perceptual_difference = 100 - (perceptual_similarity * 100)
- finally:
- shutil.rmtree(skpdiff_output_dir)
-
- # TODO(epoger): Use properties instead of getters throughout.
- # See http://stackoverflow.com/a/6618176
- def get_num_pixels_differing(self):
- """Returns the absolute number of pixels that differ."""
- return self._num_pixels_differing
-
- def get_percent_pixels_differing(self):
- """Returns the percentage of pixels that differ, as a float between
- 0 and 100 (inclusive)."""
- return ((float(self._num_pixels_differing) * 100) /
- (self._width * self._height))
-
- def get_perceptual_difference(self):
- """Returns the perceptual difference percentage."""
- return self._perceptual_difference
-
- def get_max_diff_per_channel(self):
- """Returns the maximum difference between the expected and actual images
- for each R/G/B channel, as a list."""
- return self._max_diff_per_channel
-
- def as_dict(self):
- """Returns a dictionary representation of this DiffRecord, as needed when
- constructing the JSON representation."""
- return {
- KEY__DIFFERENCES__NUM_DIFF_PIXELS: self._num_pixels_differing,
- KEY__DIFFERENCES__PERCENT_DIFF_PIXELS:
- self.get_percent_pixels_differing(),
- KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL: self._max_diff_per_channel,
- KEY__DIFFERENCES__PERCEPTUAL_DIFF: self._perceptual_difference,
- KEY__DIFFERENCES__DIFF_URL: self._diffUrl,
- KEY__DIFFERENCES__WHITE_DIFF_URL: self._whiteDiffUrl,
- }
-
-
-
-class ImageDiffDB(object):
- """ Calculates differences between image pairs, maintaining a database of
- them for download."""
-
- def __init__(self, storage_root, gs=None,
- num_worker_threads=DEFAULT_NUM_WORKER_THREADS):
- """
- Args:
- storage_root: string; root path within the DB will store all of its stuff
- gs: instance of GSUtils object we can use to download images
- num_worker_threads: how many threads that download images and
- generate diffs simultaneously
- """
- self._storage_root = storage_root
- self._gs = gs
-
- # Mechanism for reporting queue size periodically.
- self._last_queue_size_reported = None
- self._queue_size_report_lock = threading.RLock()
-
- # Dictionary of DiffRecords, keyed by (expected_image_locator,
- # actual_image_locator) tuples.
- # Values can also be _DIFFRECORD_PENDING, _DIFFRECORD_FAILED.
- #
- # Any thread that modifies _diff_dict must first acquire
- # _diff_dict_writelock!
- #
- # TODO(epoger): Disk is limitless, but RAM is not... so, we should probably
- # remove items from self._diff_dict if they haven't been accessed for a
- # long time. We can always regenerate them by diffing the images we
- # previously downloaded to local disk.
- # I guess we should figure out how expensive it is to download vs diff the
- # image pairs... if diffing them is expensive too, we can write these
- # _diff_dict objects out to disk if there's too many to hold in RAM.
- # Or we could use virtual memory to handle that automatically.
- self._diff_dict = {}
- self._diff_dict_writelock = threading.RLock()
-
- # Set up the queue for asynchronously loading DiffRecords, and start the
- # worker threads reading from it.
- # The queue maxsize must be 0 (infinite size queue), so that asynchronous
- # calls can return as soon as possible.
- self._tasks_queue = Queue.Queue(maxsize=0)
- self._workers = []
- for i in range(num_worker_threads):
- worker = threading.Thread(target=self.worker, args=(i,))
- worker.daemon = True
- worker.start()
- self._workers.append(worker)
-
- def log_queue_size_if_changed(self, limit_verbosity=True):
- """Log the size of self._tasks_queue, if it has changed since the last call.
-
- Reports the current queue size, using log.info(), unless the queue is the
- same size as the last time we reported it.
-
- Args:
- limit_verbosity: if True, only log if the queue size is a multiple of
- QUEUE_LOGGING_GRANULARITY
- """
- # Acquire the lock, to synchronize access to self._last_queue_size_reported
- self._queue_size_report_lock.acquire()
- try:
- size = self._tasks_queue.qsize()
- if size == self._last_queue_size_reported:
- return
- if limit_verbosity and (size % QUEUE_LOGGING_GRANULARITY != 0):
- return
- logging.info('tasks_queue size is %d' % size)
- self._last_queue_size_reported = size
- finally:
- self._queue_size_report_lock.release()
-
- def worker(self, worker_num):
- """Launch a worker thread that pulls tasks off self._tasks_queue.
-
- Args:
- worker_num: (integer) which worker this is
- """
- while True:
- self.log_queue_size_if_changed()
- params = self._tasks_queue.get()
- key, expected_image_url, actual_image_url = params
- try:
- diff_record = DiffRecord(
- self._gs, self._storage_root,
- expected_image_url=expected_image_url,
- expected_image_locator=key[0],
- actual_image_url=actual_image_url,
- actual_image_locator=key[1])
- except Exception:
- logging.exception(
- 'exception while creating DiffRecord for key %s' % str(key))
- diff_record = _DIFFRECORD_FAILED
- self._diff_dict_writelock.acquire()
- try:
- self._diff_dict[key] = diff_record
- finally:
- self._diff_dict_writelock.release()
-
- @property
- def storage_root(self):
- return self._storage_root
-
- def add_image_pair(self,
- expected_image_url, expected_image_locator,
- actual_image_url, actual_image_locator):
- """Asynchronously prepare a DiffRecord for a pair of images.
-
- This method will return quickly; calls to get_diff_record() will block
- until the DiffRecord is available (or we have given up on creating it).
-
- If we already have a DiffRecord for this particular image pair, no work
- will be done.
-
- If expected_image_url (or its locator) is None, just download actual_image.
- If actual_image_url (or its locator) is None, just download expected_image.
-
- Args:
- expected_image_url: file, GS, or HTTP url from which we will download the
- expected image
- expected_image_locator: a unique ID string under which we will store the
- expected image within storage_root (probably including a checksum to
- guarantee uniqueness)
- actual_image_url: file, GS, or HTTP url from which we will download the
- actual image
- actual_image_locator: a unique ID string under which we will store the
- actual image within storage_root (probably including a checksum to
- guarantee uniqueness)
- """
- expected_image_locator = _sanitize_locator(expected_image_locator)
- actual_image_locator = _sanitize_locator(actual_image_locator)
- key = (expected_image_locator, actual_image_locator)
- must_add_to_queue = False
-
- self._diff_dict_writelock.acquire()
- try:
- if not key in self._diff_dict:
- # If we have already requested a diff between these two images,
- # we don't need to request it again.
- must_add_to_queue = True
- self._diff_dict[key] = _DIFFRECORD_PENDING
- finally:
- self._diff_dict_writelock.release()
-
- if must_add_to_queue:
- self._tasks_queue.put((key, expected_image_url, actual_image_url))
- self.log_queue_size_if_changed()
-
- def get_diff_record(self, expected_image_locator, actual_image_locator):
- """Returns the DiffRecord for this image pair.
-
- This call will block until the diff record is available, or we were unable
- to generate it.
-
- Args:
- expected_image_locator: a unique ID string under which we will store the
- expected image within storage_root (probably including a checksum to
- guarantee uniqueness)
- actual_image_locator: a unique ID string under which we will store the
- actual image within storage_root (probably including a checksum to
- guarantee uniqueness)
-
- Returns the DiffRecord for this image pair, or None if we were unable to
- generate one.
- """
- key = (_sanitize_locator(expected_image_locator),
- _sanitize_locator(actual_image_locator))
- diff_record = self._diff_dict[key]
-
- # If we have no results yet, block until we do.
- while diff_record == _DIFFRECORD_PENDING:
- time.sleep(1)
- diff_record = self._diff_dict[key]
-
- # Once we have the result...
- if diff_record == _DIFFRECORD_FAILED:
- logging.error(
- 'failed to create a DiffRecord for expected_image_locator=%s , '
- 'actual_image_locator=%s' % (
- expected_image_locator, actual_image_locator))
- return None
- else:
- return diff_record
-
-
-# Utility functions
-
-def _download_file(gs, local_filepath, url):
- """Download a file from url to local_filepath, unless it is already there.
-
- Args:
- gs: instance of GSUtils object, in case the url points at Google Storage
- local_filepath: path on local disk where the image should be stored
- url: HTTP or GS URL from which we can download the image if we don't have
- it yet
- """
- global global_file_collisions
- if not os.path.exists(local_filepath):
- _mkdir_unless_exists(os.path.dirname(local_filepath))
-
- # First download the file contents into a unique filename, and
- # then rename that file. That way, if multiple threads are downloading
- # the same filename at the same time, they won't interfere with each
- # other (they will both download the file, and one will "win" in the end)
- temp_filename = '%s-%d' % (local_filepath,
- threading.current_thread().ident)
- if gs_utils.GSUtils.is_gs_url(url):
- (bucket, path) = gs_utils.GSUtils.split_gs_url(url)
- gs.download_file(source_bucket=bucket, source_path=path,
- dest_path=temp_filename)
- else:
- with contextlib.closing(urllib.urlopen(url)) as url_handle:
- with open(temp_filename, 'wb') as file_handle:
- shutil.copyfileobj(fsrc=url_handle, fdst=file_handle)
-
- # Rename the file to its real filename.
- # Keep count of how many colliding downloads we encounter;
- # if it's a large number, we may want to change our download strategy
- # to minimize repeated downloads.
- if os.path.exists(local_filepath):
- global_file_collisions += 1
- else:
- os.rename(temp_filename, local_filepath)
-
-
-def _mkdir_unless_exists(path):
- """Unless path refers to an already-existing directory, create it.
-
- Args:
- path: path on local disk
- """
- try:
- os.makedirs(path)
- except OSError as e:
- if e.errno == errno.EEXIST:
- pass
-
-
-def _sanitize_locator(locator):
- """Returns a sanitized version of a locator (one in which we know none of the
- characters will have special meaning in filenames).
-
- Args:
- locator: string, or something that can be represented as a string.
- If None or '', it is returned without modification, because empty
- locators have a particular meaning ("there is no image for this")
- """
- if locator:
- return DISALLOWED_FILEPATH_CHAR_REGEX.sub('_', str(locator))
- else:
- return locator
diff --git a/gm/rebaseline_server/imagediffdb_test.py b/gm/rebaseline_server/imagediffdb_test.py
deleted file mode 100755
index 186b2f1324..0000000000
--- a/gm/rebaseline_server/imagediffdb_test.py
+++ /dev/null
@@ -1,101 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2013 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Test imagediffdb.py
-"""
-
-# System-level imports
-import shutil
-import tempfile
-import unittest
-
-# Local imports
-import imagediffdb
-
-
-IMG_URL_BASE = ('http://chromium-skia-gm.commondatastorage.googleapis.com/gm/'
- 'bitmap-64bitMD5/')
-
-
-class ImageDiffDbTest(unittest.TestCase):
-
- def setUp(self):
- self.temp_dir = tempfile.mkdtemp()
- self.maxDiff = None
-
- def tearDown(self):
- shutil.rmtree(self.temp_dir)
-
- def shortDescription(self):
- """Tell unittest framework to not print docstrings for test cases."""
- return None
-
- def test_sanitize_locator(self):
- """Test _sanitize_locator()."""
- # pylint: disable=W0212
- self.assertEqual(imagediffdb._sanitize_locator('simple'), 'simple')
- self.assertEqual(imagediffdb._sanitize_locator(1234), '1234')
- self.assertEqual(imagediffdb._sanitize_locator('one/two'), 'one_two')
- self.assertEqual(imagediffdb._sanitize_locator('one\\two'), 'one_two')
- self.assertEqual(imagediffdb._sanitize_locator('one_two'), 'one_two')
-
- def test_simple(self):
- """Test ImageDiffDB, downloading real known images from Google Storage.
-
- TODO(epoger): Instead of hitting Google Storage, we should read image
- files from local disk using a file:// IMG_URL_BASE.
- """
- # params for each self-test:
- # 0. expected image locator
- # 1. expected image URL
- # 2. actual image locator
- # 3. actual image URL
- # 4. expected percent_pixels_differing (as a string, to 4 decimal places)
- # 5. expected perceptual difference (as a string, to 4 decimal places)
- # 6. expected max_diff_per_channel
- selftests = [
- [
- 'arcofzorro/16206093933823793653',
- IMG_URL_BASE + 'arcofzorro/16206093933823793653.png',
- 'arcofzorro/13786535001616823825',
- IMG_URL_BASE + 'arcofzorro/13786535001616823825.png',
- '0.0662', '0.0662', [255, 255, 247],
- ],
- [
- 'gradients_degenerate_2pt/10552995703607727960',
- IMG_URL_BASE + 'gradients_degenerate_2pt/10552995703607727960.png',
- 'gradients_degenerate_2pt/11198253335583713230',
- IMG_URL_BASE + 'gradients_degenerate_2pt/11198253335583713230.png',
- '100.0000', '100.0000', [255, 0, 255],
- ],
- ]
-
- # Add all image pairs to the database
- db = imagediffdb.ImageDiffDB(self.temp_dir)
- for selftest in selftests:
- db.add_image_pair(
- expected_image_locator=selftest[0], expected_image_url=selftest[1],
- actual_image_locator=selftest[2], actual_image_url=selftest[3])
-
- # Fetch each image pair from the database
- for selftest in selftests:
- record = db.get_diff_record(expected_image_locator=selftest[0],
- actual_image_locator=selftest[2])
- self.assertEqual('%.4f' % record.get_percent_pixels_differing(),
- selftest[4])
- self.assertEqual('%.4f' % record.get_perceptual_difference(), selftest[5])
- self.assertEqual(record.get_max_diff_per_channel(), selftest[6])
-
-
-def main():
- suite = unittest.TestLoader().loadTestsFromTestCase(ImageDiffDbTest)
- unittest.TextTestRunner(verbosity=2).run(suite)
-
-
-if __name__ == '__main__':
- main()
diff --git a/gm/rebaseline_server/imagepair.py b/gm/rebaseline_server/imagepair.py
deleted file mode 100644
index e85c21948b..0000000000
--- a/gm/rebaseline_server/imagepair.py
+++ /dev/null
@@ -1,128 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-ImagePair class (see class docstring for details)
-"""
-
-import posixpath
-
-
-# Keys used within ImagePair dictionary representations.
-# NOTE: Keep these in sync with static/constants.js
-KEY__IMAGEPAIRS__DIFFERENCES = 'differenceData'
-KEY__IMAGEPAIRS__EXPECTATIONS = 'expectations'
-KEY__IMAGEPAIRS__EXTRACOLUMNS = 'extraColumns'
-KEY__IMAGEPAIRS__IMAGE_A_URL = 'imageAUrl'
-KEY__IMAGEPAIRS__IMAGE_B_URL = 'imageBUrl'
-KEY__IMAGEPAIRS__IS_DIFFERENT = 'isDifferent'
-KEY__IMAGEPAIRS__SOURCE_JSON_FILE = 'sourceJsonFile'
-
-# If self._diff_record is set to this, we haven't asked ImageDiffDB for the
-# image diff details yet.
-_DIFF_RECORD_STILL_LOADING = 'still_loading'
-
-
-class ImagePair(object):
- """Describes a pair of images, pixel difference info, and optional metadata.
- """
-
- def __init__(self, image_diff_db,
- imageA_base_url, imageB_base_url,
- imageA_relative_url, imageB_relative_url,
- expectations=None, extra_columns=None, source_json_file=None,
- download_all_images=False):
- """
- Args:
- image_diff_db: ImageDiffDB instance we use to generate/store image diffs
- imageA_base_url: string; base URL for image A
- imageB_base_url: string; base URL for image B
- imageA_relative_url: string; URL pointing at an image, relative to
- imageA_base_url; or None, if this image is missing
- imageB_relative_url: string; URL pointing at an image, relative to
- imageB_base_url; or None, if this image is missing
- expectations: optional dictionary containing expectations-specific
- metadata (ignore-failure, bug numbers, etc.)
- extra_columns: optional dictionary containing more metadata (test name,
- builder name, etc.)
- source_json_file: relative path of the JSON file where each image came
- from; this will be the same for both imageA and imageB, within their
- respective directories
- download_all_images: if True, download any images associated with this
- image pair, even if we don't need them to generate diffs
- (imageA == imageB, or one of them is missing)
- """
- self._image_diff_db = image_diff_db
- self.imageA_base_url = imageA_base_url
- self.imageB_base_url = imageB_base_url
- self.imageA_relative_url = imageA_relative_url
- self.imageB_relative_url = imageB_relative_url
- self.expectations_dict = expectations
- self.extra_columns_dict = extra_columns
- self.source_json_file = source_json_file
- if not imageA_relative_url or not imageB_relative_url:
- self._is_different = True
- self._diff_record = None
- elif imageA_relative_url == imageB_relative_url:
- self._is_different = False
- self._diff_record = None
- else:
- # Tell image_diff_db to add an entry for this diff asynchronously.
- # Later on, we will call image_diff_db.get_diff_record() to find it.
- self._is_different = True
- self._diff_record = _DIFF_RECORD_STILL_LOADING
-
- if self._diff_record != None or download_all_images:
- image_diff_db.add_image_pair(
- expected_image_locator=imageA_relative_url,
- expected_image_url=self.posixpath_join(imageA_base_url,
- imageA_relative_url),
- actual_image_locator=imageB_relative_url,
- actual_image_url=self.posixpath_join(imageB_base_url,
- imageB_relative_url))
-
- def as_dict(self):
- """Returns a dictionary describing this ImagePair.
-
- Uses the KEY__IMAGEPAIRS__* constants as keys.
- """
- asdict = {
- KEY__IMAGEPAIRS__IMAGE_A_URL: self.imageA_relative_url,
- KEY__IMAGEPAIRS__IMAGE_B_URL: self.imageB_relative_url,
- }
- asdict[KEY__IMAGEPAIRS__IS_DIFFERENT] = self._is_different
- if self.expectations_dict:
- asdict[KEY__IMAGEPAIRS__EXPECTATIONS] = self.expectations_dict
- if self.extra_columns_dict:
- asdict[KEY__IMAGEPAIRS__EXTRACOLUMNS] = self.extra_columns_dict
- if self.source_json_file:
- asdict[KEY__IMAGEPAIRS__SOURCE_JSON_FILE] = self.source_json_file
- if self._diff_record is _DIFF_RECORD_STILL_LOADING:
- # We have waited as long as we can to ask ImageDiffDB for details of
- # this image diff. Now we must block until ImageDiffDB can provide
- # those details.
- #
- # TODO(epoger): Is it wasteful for every imagepair to have its own
- # reference to image_diff_db? If so, we could pass an image_diff_db
- # reference into this method call instead...
- self._diff_record = self._image_diff_db.get_diff_record(
- expected_image_locator=self.imageA_relative_url,
- actual_image_locator=self.imageB_relative_url)
- if self._diff_record != None:
- asdict[KEY__IMAGEPAIRS__DIFFERENCES] = self._diff_record.as_dict()
- return asdict
-
- @staticmethod
- def posixpath_join(*args):
- """Wrapper around posixpath.join().
-
- Returns posixpath.join(*args), or None if any arg is None.
- """
- for arg in args:
- if arg == None:
- return None
- return posixpath.join(*args)
diff --git a/gm/rebaseline_server/imagepair_test.py b/gm/rebaseline_server/imagepair_test.py
deleted file mode 100755
index 773f6a376c..0000000000
--- a/gm/rebaseline_server/imagepair_test.py
+++ /dev/null
@@ -1,214 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Test imagepair.py
-"""
-
-# System-level imports
-import shutil
-import tempfile
-import unittest
-
-# Local imports
-import imagediffdb
-import imagepair
-
-
-IMG_URL_BASE = ('http://chromium-skia-gm.commondatastorage.googleapis.com/'
- 'gm/bitmap-64bitMD5/')
-
-
-class ImagePairTest(unittest.TestCase):
-
- def setUp(self):
- self.temp_dir = tempfile.mkdtemp()
- self.maxDiff = None
-
- def tearDown(self):
- shutil.rmtree(self.temp_dir)
-
- def shortDescription(self):
- """Tells unittest framework to not print docstrings for test cases."""
- return None
-
- def test_endToEnd(self):
- """Tests ImagePair, using a real ImageDiffDB to download real images.
-
- TODO(epoger): Either in addition to or instead of this end-to-end test,
- we should perform some tests using either:
- 1. a mock ImageDiffDB, or
- 2. a real ImageDiffDB that doesn't hit Google Storage looking for input
- image files (maybe a file:// IMG_URL_BASE)
- """
- # params for each self-test:
- #
- # inputs:
- # 0. imageA_relative_URL
- # 1. imageB_relative_URL
- # 2. expectations dict
- # 3. extra_columns dict
- # expected output:
- # 4. expected result of ImagePair.as_dict()
- selftests = [
- [
- # inputs:
- 'arcofzorro/16206093933823793653.png',
- 'arcofzorro/16206093933823793653.png',
- None,
- {
- 'builder': 'MyBuilder',
- 'test': 'MyTest',
- },
- # expected output:
- {
- 'extraColumns': {
- 'builder': 'MyBuilder',
- 'test': 'MyTest',
- },
- 'imageAUrl': 'arcofzorro/16206093933823793653.png',
- 'imageBUrl': 'arcofzorro/16206093933823793653.png',
- 'isDifferent': False,
- },
- ],
-
- [
- # inputs:
- 'arcofzorro/16206093933823793653.png',
- 'arcofzorro/13786535001616823825.png',
- None,
- None,
- # expected output:
- {
- 'differenceData': {
- 'maxDiffPerChannel': [255, 255, 247],
- 'numDifferingPixels': 662,
- 'percentDifferingPixels': 0.0662,
- 'perceptualDifference': 0.06620300000000157,
- 'diffUrl': 'arcofzorro_16206093933823793653_png_png-vs-' +
- 'arcofzorro_13786535001616823825_png_png.png',
- 'whiteDiffUrl': 'arcofzorro_16206093933823793653_png_png' +
- '-vs-arcofzorro_13786535001616823825_png_png.png',
- },
- 'imageAUrl': 'arcofzorro/16206093933823793653.png',
- 'imageBUrl': 'arcofzorro/13786535001616823825.png',
- 'isDifferent': True,
- },
- ],
-
- [
- # inputs:
- 'gradients_degenerate_2pt/10552995703607727960.png',
- 'gradients_degenerate_2pt/11198253335583713230.png',
- {
- 'ignoreFailure': True,
- 'bugs': [1001, 1002],
- },
- {
- 'builder': 'MyBuilder',
- 'test': 'MyTest',
- },
- # expected output:
- {
- 'differenceData': {
- 'maxDiffPerChannel': [255, 0, 255],
- 'numDifferingPixels': 102400,
- 'percentDifferingPixels': 100.00,
- 'perceptualDifference': 100.00,
- 'diffUrl': 'gradients_degenerate_2pt_10552995703607727960' +
- '_png_png-vs-gradients_degenerate_2pt_' +
- '11198253335583713230_png_png.png',
- 'whiteDiffUrl': 'gradients_degenerate_2pt_' +
- '10552995703607727960_png_png-vs-' +
- 'gradients_degenerate_2pt_11198253335583713230' +
- '_png_png.png'
- },
- 'expectations': {
- 'bugs': [1001, 1002],
- 'ignoreFailure': True,
- },
- 'extraColumns': {
- 'builder': 'MyBuilder',
- 'test': 'MyTest',
- },
- 'imageAUrl':
- 'gradients_degenerate_2pt/10552995703607727960.png',
- 'imageBUrl':
- 'gradients_degenerate_2pt/11198253335583713230.png',
- 'isDifferent': True,
- },
- ],
-
- # Test fix for http://skbug.com/2368 -- how do we handle an ImagePair
- # missing one of its images?
- [
- # inputs:
- 'arcofzorro/16206093933823793653.png',
- 'nonexistentDir/111111.png',
- {
- 'ignoreFailure': True,
- 'bugs': [1001, 1002],
- },
- {
- 'builder': 'MyBuilder',
- 'test': 'MyTest',
- },
- # expected output:
- {
- 'expectations': {
- 'bugs': [1001, 1002],
- 'ignoreFailure': True,
- },
- 'extraColumns': {
- 'builder': 'MyBuilder',
- 'test': 'MyTest',
- },
- 'imageAUrl': 'arcofzorro/16206093933823793653.png',
- 'imageBUrl': 'nonexistentDir/111111.png',
- 'isDifferent': True,
- },
- ],
-
- # One of the two images is missing, but download_all_images=True so we
- # should download it anyway.
- [
- # inputs:
- None,
- 'arcofzorro/13786535001616823825.png',
- None,
- None,
- # expected output:
- {
- 'imageAUrl': None,
- 'imageBUrl': 'arcofzorro/13786535001616823825.png',
- 'isDifferent': True,
- },
- ],
-
- ]
-
- db = imagediffdb.ImageDiffDB(self.temp_dir)
- for selftest in selftests:
- image_pair = imagepair.ImagePair(
- image_diff_db=db,
- imageA_base_url=IMG_URL_BASE,
- imageB_base_url=IMG_URL_BASE,
- imageA_relative_url=selftest[0],
- imageB_relative_url=selftest[1],
- expectations=selftest[2],
- extra_columns=selftest[3],
- download_all_images=True)
- self.assertEqual(image_pair.as_dict(), selftest[4])
-
-
-def main():
- suite = unittest.TestLoader().loadTestsFromTestCase(ImagePairTest)
- unittest.TextTestRunner(verbosity=2).run(suite)
-
-
-if __name__ == '__main__':
- main()
diff --git a/gm/rebaseline_server/imagepairset.py b/gm/rebaseline_server/imagepairset.py
deleted file mode 100644
index b492d9f021..0000000000
--- a/gm/rebaseline_server/imagepairset.py
+++ /dev/null
@@ -1,234 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-ImagePairSet class; see its docstring below.
-"""
-
-# System-level imports
-import posixpath
-
-# Must fix up PYTHONPATH before importing from within Skia
-import rs_fixpypath # pylint: disable=W0611
-
-# Imports from within Skia
-import column
-import imagediffdb
-from py.utils import gs_utils
-
-# Keys used within dictionary representation of ImagePairSet.
-# NOTE: Keep these in sync with static/constants.js
-KEY__ROOT__EXTRACOLUMNHEADERS = 'extraColumnHeaders'
-KEY__ROOT__EXTRACOLUMNORDER = 'extraColumnOrder'
-KEY__ROOT__HEADER = 'header'
-KEY__ROOT__IMAGEPAIRS = 'imagePairs'
-KEY__ROOT__IMAGESETS = 'imageSets'
-KEY__IMAGESETS__FIELD__BASE_URL = 'baseUrl'
-KEY__IMAGESETS__FIELD__DESCRIPTION = 'description'
-KEY__IMAGESETS__SET__DIFFS = 'diffs'
-KEY__IMAGESETS__SET__IMAGE_A = 'imageA'
-KEY__IMAGESETS__SET__IMAGE_B = 'imageB'
-KEY__IMAGESETS__SET__WHITEDIFFS = 'whiteDiffs'
-
-DEFAULT_DESCRIPTIONS = ('setA', 'setB')
-
-
-class ImagePairSet(object):
- """A collection of ImagePairs, representing two arbitrary sets of images.
-
- These could be:
- - images generated before and after a code patch
- - expected and actual images for some tests
- - or any other pairwise set of images.
- """
-
- def __init__(self, diff_base_url, descriptions=None):
- """
- Args:
- diff_base_url: base URL indicating where diff images can be loaded from
- descriptions: a (string, string) tuple describing the two image sets.
- If not specified, DEFAULT_DESCRIPTIONS will be used.
- """
- self._column_header_factories = {}
- self._descriptions = descriptions or DEFAULT_DESCRIPTIONS
- self._extra_column_tallies = {} # maps column_id -> values
- # -> instances_per_value
- self._imageA_base_url = None
- self._imageB_base_url = None
- self._diff_base_url = diff_base_url
-
- # We build self._image_pair_objects incrementally as calls come into
- # add_image_pair(); self._image_pair_dicts is filled in lazily (so that
- # we put off asking ImageDiffDB for results as long as possible).
- self._image_pair_objects = []
- self._image_pair_dicts = None
-
- def add_image_pair(self, image_pair):
- """Adds an ImagePair; this may be repeated any number of times."""
- # Special handling when we add the first ImagePair...
- if not self._image_pair_objects:
- self._imageA_base_url = image_pair.imageA_base_url
- self._imageB_base_url = image_pair.imageB_base_url
-
- if(image_pair.imageA_base_url != self._imageA_base_url):
- raise Exception('added ImagePair with base_url "%s" instead of "%s"' % (
- image_pair.imageA_base_url, self._imageA_base_url))
- if(image_pair.imageB_base_url != self._imageB_base_url):
- raise Exception('added ImagePair with base_url "%s" instead of "%s"' % (
- image_pair.imageB_base_url, self._imageB_base_url))
- self._image_pair_objects.append(image_pair)
- extra_columns_dict = image_pair.extra_columns_dict
- if extra_columns_dict:
- for column_id, value in extra_columns_dict.iteritems():
- self._add_extra_column_value_to_summary(column_id, value)
-
- def set_column_header_factory(self, column_id, column_header_factory):
- """Overrides the default settings for one of the extraColumn headers.
-
- Args:
- column_id: string; unique ID of this column (must match a key within
- an ImagePair's extra_columns dictionary)
- column_header_factory: a ColumnHeaderFactory object
- """
- self._column_header_factories[column_id] = column_header_factory
-
- def get_column_header_factory(self, column_id):
- """Returns the ColumnHeaderFactory object for a particular extraColumn.
-
- Args:
- column_id: string; unique ID of this column (must match a key within
- an ImagePair's extra_columns dictionary)
- """
- column_header_factory = self._column_header_factories.get(column_id, None)
- if not column_header_factory:
- column_header_factory = column.ColumnHeaderFactory(header_text=column_id)
- self._column_header_factories[column_id] = column_header_factory
- return column_header_factory
-
- def ensure_extra_column_values_in_summary(self, column_id, values):
- """Ensure this column_id/value pair is part of the extraColumns summary.
-
- Args:
- column_id: string; unique ID of this column
- value: string; a possible value for this column
- """
- for value in values:
- self._add_extra_column_value_to_summary(
- column_id=column_id, value=value, addend=0)
-
- def _add_extra_column_value_to_summary(self, column_id, value, addend=1):
- """Records one column_id/value extraColumns pair found within an ImagePair.
-
- We use this information to generate tallies within the column header
- (how many instances we saw of a particular value, within a particular
- extraColumn).
-
- Args:
- column_id: string; unique ID of this column (must match a key within
- an ImagePair's extra_columns dictionary)
- value: string; a possible value for this column
- addend: integer; how many instances to add to the tally
- """
- known_values_for_column = self._extra_column_tallies.get(column_id, None)
- if not known_values_for_column:
- known_values_for_column = {}
- self._extra_column_tallies[column_id] = known_values_for_column
- instances_of_this_value = known_values_for_column.get(value, 0)
- instances_of_this_value += addend
- known_values_for_column[value] = instances_of_this_value
-
- def _column_headers_as_dict(self):
- """Returns all column headers as a dictionary."""
- asdict = {}
- for column_id, values_for_column in self._extra_column_tallies.iteritems():
- column_header_factory = self.get_column_header_factory(column_id)
- asdict[column_id] = column_header_factory.create_as_dict(
- values_for_column)
- return asdict
-
- def as_dict(self, column_ids_in_order=None):
- """Returns a dictionary describing this package of ImagePairs.
-
- Uses the KEY__* constants as keys.
-
- Args:
- column_ids_in_order: A list of all extracolumn IDs in the desired display
- order. If unspecified, they will be displayed in alphabetical order.
- If specified, this list must contain all the extracolumn IDs!
- (It may contain extra column IDs; they will be ignored.)
- """
- all_column_ids = set(self._extra_column_tallies.keys())
- if column_ids_in_order == None:
- column_ids_in_order = sorted(all_column_ids)
- else:
- # Make sure the caller listed all column IDs, and throw away any extras.
- specified_column_ids = set(column_ids_in_order)
- forgotten_column_ids = all_column_ids - specified_column_ids
- assert not forgotten_column_ids, (
- 'column_ids_in_order %s missing these column_ids: %s' % (
- column_ids_in_order, forgotten_column_ids))
- column_ids_in_order = [c for c in column_ids_in_order
- if c in all_column_ids]
-
- key_description = KEY__IMAGESETS__FIELD__DESCRIPTION
- key_base_url = KEY__IMAGESETS__FIELD__BASE_URL
- if gs_utils.GSUtils.is_gs_url(self._imageA_base_url):
- valueA_base_url = self._convert_gs_url_to_http_url(self._imageA_base_url)
- else:
- valueA_base_url = self._imageA_base_url
- if gs_utils.GSUtils.is_gs_url(self._imageB_base_url):
- valueB_base_url = self._convert_gs_url_to_http_url(self._imageB_base_url)
- else:
- valueB_base_url = self._imageB_base_url
-
- # We've waited as long as we can to ask ImageDiffDB for details of the
- # image diffs, so that it has time to compute them.
- if self._image_pair_dicts == None:
- self._image_pair_dicts = [ip.as_dict() for ip in self._image_pair_objects]
-
- return {
- KEY__ROOT__EXTRACOLUMNHEADERS: self._column_headers_as_dict(),
- KEY__ROOT__EXTRACOLUMNORDER: column_ids_in_order,
- KEY__ROOT__IMAGEPAIRS: self._image_pair_dicts,
- KEY__ROOT__IMAGESETS: {
- KEY__IMAGESETS__SET__IMAGE_A: {
- key_description: self._descriptions[0],
- key_base_url: valueA_base_url,
- },
- KEY__IMAGESETS__SET__IMAGE_B: {
- key_description: self._descriptions[1],
- key_base_url: valueB_base_url,
- },
- KEY__IMAGESETS__SET__DIFFS: {
- key_description: 'color difference per channel',
- key_base_url: posixpath.join(
- self._diff_base_url, imagediffdb.RGBDIFFS_SUBDIR),
- },
- KEY__IMAGESETS__SET__WHITEDIFFS: {
- key_description: 'differing pixels in white',
- key_base_url: posixpath.join(
- self._diff_base_url, imagediffdb.WHITEDIFFS_SUBDIR),
- },
- },
- }
-
- @staticmethod
- def _convert_gs_url_to_http_url(gs_url):
- """Returns HTTP URL that can be used to download this Google Storage file.
-
- TODO(epoger): Create functionality like this within gs_utils.py instead of
- here? See https://codereview.chromium.org/428493005/ ('create
- anyfile_utils.py for copying files between HTTP/GS/local filesystem')
-
- Args:
- gs_url: "gs://bucket/path" format URL
- """
- bucket, path = gs_utils.GSUtils.split_gs_url(gs_url)
- http_url = 'http://storage.cloud.google.com/' + bucket
- if path:
- http_url += '/' + path
- return http_url
diff --git a/gm/rebaseline_server/imagepairset_test.py b/gm/rebaseline_server/imagepairset_test.py
deleted file mode 100755
index a931e047aa..0000000000
--- a/gm/rebaseline_server/imagepairset_test.py
+++ /dev/null
@@ -1,210 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Test imagepairset.py
-"""
-
-# System-level imports
-import unittest
-
-# Local imports
-import column
-import imagepair
-import imagepairset
-
-
-BASE_URL_1 = 'http://base/url/1'
-BASE_URL_2 = 'http://base/url/2'
-DIFF_BASE_URL = 'http://diff/base/url'
-IMAGEPAIR_1_AS_DICT = {
- imagepair.KEY__IMAGEPAIRS__EXTRACOLUMNS: {
- 'builder': 'MyBuilder',
- 'test': 'test1',
- },
- imagepair.KEY__IMAGEPAIRS__IMAGE_A_URL: 'test1/1111.png',
- imagepair.KEY__IMAGEPAIRS__IMAGE_B_URL: 'test1/1111.png',
- imagepair.KEY__IMAGEPAIRS__IS_DIFFERENT: False,
-}
-IMAGEPAIR_2_AS_DICT = {
- imagepair.KEY__IMAGEPAIRS__DIFFERENCES: {
- 'maxDiffPerChannel': [1, 2, 3],
- 'numDifferingPixels': 111,
- 'percentDifferingPixels': 22.222,
- },
- imagepair.KEY__IMAGEPAIRS__EXTRACOLUMNS: {
- 'builder': 'MyBuilder',
- 'test': 'test2',
- },
- imagepair.KEY__IMAGEPAIRS__IMAGE_A_URL: 'test2/2222.png',
- imagepair.KEY__IMAGEPAIRS__IMAGE_B_URL: 'test2/22223.png',
- imagepair.KEY__IMAGEPAIRS__IS_DIFFERENT: True,
-}
-IMAGEPAIR_3_AS_DICT = {
- imagepair.KEY__IMAGEPAIRS__DIFFERENCES: {
- 'maxDiffPerChannel': [4, 5, 6],
- 'numDifferingPixels': 111,
- 'percentDifferingPixels': 44.444,
- },
- imagepair.KEY__IMAGEPAIRS__EXPECTATIONS: {
- 'bugs': [1001, 1002],
- 'ignoreFailure': True,
- },
- imagepair.KEY__IMAGEPAIRS__EXTRACOLUMNS: {
- 'builder': 'MyBuilder',
- 'test': 'test3',
- },
- imagepair.KEY__IMAGEPAIRS__IMAGE_A_URL: 'test3/3333.png',
- imagepair.KEY__IMAGEPAIRS__IMAGE_B_URL: 'test3/33334.png',
- imagepair.KEY__IMAGEPAIRS__IS_DIFFERENT: True,
-}
-SET_A_DESCRIPTION = 'expectations'
-SET_B_DESCRIPTION = 'actuals'
-
-
-class ImagePairSetTest(unittest.TestCase):
-
- def setUp(self):
- self.maxDiff = None # do not truncate diffs when tests fail
-
- def shortDescription(self):
- """Tells unittest framework to not print docstrings for test cases."""
- return None
-
- def test_success(self):
- """Assembles some ImagePairs into an ImagePairSet, and validates results.
- """
- image_pairs = [
- MockImagePair(imageA_base_url=BASE_URL_1, imageB_base_url=BASE_URL_1,
- dict_to_return=IMAGEPAIR_1_AS_DICT),
- MockImagePair(imageA_base_url=BASE_URL_1, imageB_base_url=BASE_URL_1,
- dict_to_return=IMAGEPAIR_2_AS_DICT),
- MockImagePair(imageA_base_url=BASE_URL_1, imageB_base_url=BASE_URL_1,
- dict_to_return=IMAGEPAIR_3_AS_DICT),
- ]
- expected_imageset_dict = {
- 'extraColumnHeaders': {
- 'builder': {
- 'headerText': 'builder',
- 'isFilterable': True,
- 'isSortable': True,
- 'useFreeformFilter': False,
- 'valuesAndCounts': [('MyBuilder', 3)],
- },
- 'test': {
- 'headerText': 'which GM test',
- 'headerUrl': 'http://learn/about/gm/tests',
- 'isFilterable': True,
- 'isSortable': False,
- 'useFreeformFilter': False,
- 'valuesAndCounts': [('test1', 1),
- ('test2', 1),
- ('test3', 1)],
- },
- },
- 'extraColumnOrder': ['builder', 'test'],
- 'imagePairs': [
- IMAGEPAIR_1_AS_DICT,
- IMAGEPAIR_2_AS_DICT,
- IMAGEPAIR_3_AS_DICT,
- ],
- 'imageSets': {
- 'imageA': {
- 'baseUrl': BASE_URL_1,
- 'description': SET_A_DESCRIPTION,
- },
- 'imageB': {
- 'baseUrl': BASE_URL_1,
- 'description': SET_B_DESCRIPTION,
- },
- 'diffs': {
- 'baseUrl': DIFF_BASE_URL + '/diffs',
- 'description': 'color difference per channel',
- },
- 'whiteDiffs': {
- 'baseUrl': DIFF_BASE_URL + '/whitediffs',
- 'description': 'differing pixels in white',
- },
- },
- }
-
- image_pair_set = imagepairset.ImagePairSet(
- descriptions=(SET_A_DESCRIPTION, SET_B_DESCRIPTION),
- diff_base_url=DIFF_BASE_URL)
- for image_pair in image_pairs:
- image_pair_set.add_image_pair(image_pair)
- # The 'builder' column header uses the default settings,
- # but the 'test' column header has manual adjustments.
- image_pair_set.set_column_header_factory(
- 'test',
- column.ColumnHeaderFactory(
- header_text='which GM test',
- header_url='http://learn/about/gm/tests',
- is_filterable=True,
- is_sortable=False))
- self.assertEqual(image_pair_set.as_dict(), expected_imageset_dict)
-
- def test_mismatched_base_url(self):
- """Confirms that mismatched base_urls will cause an exception."""
- image_pair_set = imagepairset.ImagePairSet(
- diff_base_url=DIFF_BASE_URL)
- image_pair_set.add_image_pair(
- MockImagePair(imageA_base_url=BASE_URL_1, imageB_base_url=BASE_URL_1,
- dict_to_return=IMAGEPAIR_1_AS_DICT))
- image_pair_set.add_image_pair(
- MockImagePair(imageA_base_url=BASE_URL_1, imageB_base_url=BASE_URL_1,
- dict_to_return=IMAGEPAIR_2_AS_DICT))
- with self.assertRaises(Exception):
- image_pair_set.add_image_pair(
- MockImagePair(imageA_base_url=BASE_URL_2, imageB_base_url=BASE_URL_2,
- dict_to_return=IMAGEPAIR_3_AS_DICT))
-
- def test_missing_column_ids(self):
- """Confirms that passing truncated column_ids_in_order to as_dict()
- will cause an exception."""
- image_pair_set = imagepairset.ImagePairSet(
- diff_base_url=DIFF_BASE_URL)
- image_pair_set.add_image_pair(
- MockImagePair(imageA_base_url=BASE_URL_1, imageB_base_url=BASE_URL_1,
- dict_to_return=IMAGEPAIR_1_AS_DICT))
- image_pair_set.add_image_pair(
- MockImagePair(imageA_base_url=BASE_URL_1, imageB_base_url=BASE_URL_1,
- dict_to_return=IMAGEPAIR_2_AS_DICT))
- # Call as_dict() with default or reasonable column_ids_in_order.
- image_pair_set.as_dict()
- image_pair_set.as_dict(column_ids_in_order=['test', 'builder'])
- image_pair_set.as_dict(column_ids_in_order=['test', 'builder', 'extra'])
- # Call as_dict() with not enough column_ids.
- with self.assertRaises(Exception):
- image_pair_set.as_dict(column_ids_in_order=['builder'])
-
-
-class MockImagePair(object):
- """Mock ImagePair object, which will return canned results."""
- def __init__(self, imageA_base_url, imageB_base_url, dict_to_return):
- """
- Args:
- base_url: base_url attribute for this object
- dict_to_return: dictionary to return from as_dict()
- """
- self.imageA_base_url = imageA_base_url
- self.imageB_base_url = imageB_base_url
- self.extra_columns_dict = dict_to_return.get(
- imagepair.KEY__IMAGEPAIRS__EXTRACOLUMNS, None)
- self._dict_to_return = dict_to_return
-
- def as_dict(self):
- return self._dict_to_return
-
-
-def main():
- suite = unittest.TestLoader().loadTestsFromTestCase(ImagePairSetTest)
- unittest.TextTestRunner(verbosity=2).run(suite)
-
-
-if __name__ == '__main__':
- main()
diff --git a/gm/rebaseline_server/results.py b/gm/rebaseline_server/results.py
deleted file mode 100755
index b0027d22af..0000000000
--- a/gm/rebaseline_server/results.py
+++ /dev/null
@@ -1,343 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2013 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Repackage expected/actual GM results as needed by our HTML rebaseline viewer.
-"""
-
-# System-level imports
-import fnmatch
-import os
-import re
-
-# Must fix up PYTHONPATH before importing from within Skia
-import rs_fixpypath # pylint: disable=W0611
-
-# Imports from within Skia
-import gm_json
-import imagepairset
-
-# Keys used to link an image to a particular GM test.
-# NOTE: Keep these in sync with static/constants.js
-VALUE__HEADER__SCHEMA_VERSION = 5
-KEY__EXPECTATIONS__BUGS = gm_json.JSONKEY_EXPECTEDRESULTS_BUGS
-KEY__EXPECTATIONS__IGNOREFAILURE = gm_json.JSONKEY_EXPECTEDRESULTS_IGNOREFAILURE
-KEY__EXPECTATIONS__REVIEWED = gm_json.JSONKEY_EXPECTEDRESULTS_REVIEWED
-KEY__EXTRACOLUMNS__BUILDER = 'builder'
-KEY__EXTRACOLUMNS__CONFIG = 'config'
-KEY__EXTRACOLUMNS__RESULT_TYPE = 'resultType'
-KEY__EXTRACOLUMNS__TEST = 'test'
-KEY__HEADER__DATAHASH = 'dataHash'
-KEY__HEADER__IS_EDITABLE = 'isEditable'
-KEY__HEADER__IS_EXPORTED = 'isExported'
-KEY__HEADER__IS_STILL_LOADING = 'resultsStillLoading'
-KEY__HEADER__RESULTS_ALL = 'all'
-KEY__HEADER__RESULTS_FAILURES = 'failures'
-KEY__HEADER__SCHEMA_VERSION = 'schemaVersion'
-KEY__HEADER__SET_A_DESCRIPTIONS = 'setA'
-KEY__HEADER__SET_B_DESCRIPTIONS = 'setB'
-KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE = 'timeNextUpdateAvailable'
-KEY__HEADER__TIME_UPDATED = 'timeUpdated'
-KEY__HEADER__TYPE = 'type'
-KEY__RESULT_TYPE__FAILED = gm_json.JSONKEY_ACTUALRESULTS_FAILED
-KEY__RESULT_TYPE__FAILUREIGNORED = gm_json.JSONKEY_ACTUALRESULTS_FAILUREIGNORED
-KEY__RESULT_TYPE__NOCOMPARISON = gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON
-KEY__RESULT_TYPE__SUCCEEDED = gm_json.JSONKEY_ACTUALRESULTS_SUCCEEDED
-KEY__SET_DESCRIPTIONS__DIR = 'dir'
-KEY__SET_DESCRIPTIONS__REPO_REVISION = 'repoRevision'
-KEY__SET_DESCRIPTIONS__SECTION = 'section'
-
-IMAGE_FILENAME_RE = re.compile(gm_json.IMAGE_FILENAME_PATTERN)
-IMAGE_FILENAME_FORMATTER = '%s_%s.png' # pass in (testname, config)
-
-PARENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
-DEFAULT_ACTUALS_DIR = '.gm-actuals'
-DEFAULT_GENERATED_IMAGES_ROOT = os.path.join(
- PARENT_DIRECTORY, '.generated-images')
-
-# Define the default set of builders we will process expectations/actuals for.
-# This allows us to ignore builders for which we don't maintain expectations
-# (trybots, Valgrind, ASAN, TSAN), and avoid problems like
-# https://code.google.com/p/skia/issues/detail?id=2036 ('rebaseline_server
-# produces error when trying to add baselines for ASAN/TSAN builders')
-DEFAULT_MATCH_BUILDERS_PATTERN_LIST = ['.*']
-DEFAULT_SKIP_BUILDERS_PATTERN_LIST = [
- '.*-Trybot', '.*Valgrind.*', '.*TSAN.*', '.*ASAN.*']
-
-
-class BaseComparisons(object):
- """Base class for generating summary of comparisons between two image sets.
- """
-
- def __init__(self):
- """Base constructor; most subclasses will override."""
- self._setA_descriptions = None
- self._setB_descriptions = None
-
- def get_results_of_type(self, results_type):
- """Return results of some/all tests (depending on 'results_type' parameter).
-
- Args:
- results_type: string describing which types of results to include; must
- be one of the RESULTS_* constants
-
- Results are returned in a dictionary as output by ImagePairSet.as_dict().
- """
- return self._results[results_type]
-
- def get_packaged_results_of_type(self, results_type, reload_seconds=None,
- is_editable=False, is_exported=True):
- """Package the results of some/all tests as a complete response_dict.
-
- Args:
- results_type: string indicating which set of results to return;
- must be one of the RESULTS_* constants
- reload_seconds: if specified, note that new results may be available once
- these results are reload_seconds old
- is_editable: whether clients are allowed to submit new baselines
- is_exported: whether these results are being made available to other
- network hosts
- """
- response_dict = self._results[results_type]
- time_updated = self.get_timestamp()
- header_dict = {
- KEY__HEADER__SCHEMA_VERSION: (
- VALUE__HEADER__SCHEMA_VERSION),
-
- # Timestamps:
- # 1. when this data was last updated
- # 2. when the caller should check back for new data (if ever)
- KEY__HEADER__TIME_UPDATED: time_updated,
- KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE: (
- (time_updated+reload_seconds) if reload_seconds else None),
-
- # The type we passed to get_results_of_type()
- KEY__HEADER__TYPE: results_type,
-
- # Hash of dataset, which the client must return with any edits--
- # this ensures that the edits were made to a particular dataset.
- KEY__HEADER__DATAHASH: str(hash(repr(
- response_dict[imagepairset.KEY__ROOT__IMAGEPAIRS]))),
-
- # Whether the server will accept edits back.
- KEY__HEADER__IS_EDITABLE: is_editable,
-
- # Whether the service is accessible from other hosts.
- KEY__HEADER__IS_EXPORTED: is_exported,
- }
- if self._setA_descriptions:
- header_dict[KEY__HEADER__SET_A_DESCRIPTIONS] = self._setA_descriptions
- if self._setB_descriptions:
- header_dict[KEY__HEADER__SET_B_DESCRIPTIONS] = self._setB_descriptions
- response_dict[imagepairset.KEY__ROOT__HEADER] = header_dict
- return response_dict
-
- def get_timestamp(self):
- """Return the time at which this object was created, in seconds past epoch
- (UTC).
- """
- return self._timestamp
-
- _match_builders_pattern_list = [
- re.compile(p) for p in DEFAULT_MATCH_BUILDERS_PATTERN_LIST]
- _skip_builders_pattern_list = [
- re.compile(p) for p in DEFAULT_SKIP_BUILDERS_PATTERN_LIST]
-
- def set_match_builders_pattern_list(self, pattern_list):
- """Override the default set of builders we should process.
-
- The default is DEFAULT_MATCH_BUILDERS_PATTERN_LIST .
-
- Note that skip_builders_pattern_list overrides this; regardless of whether a
- builder is in the "match" list, if it's in the "skip" list, we will skip it.
-
- Args:
- pattern_list: list of regex patterns; process builders that match any
- entry within this list
- """
- if pattern_list == None:
- pattern_list = []
- self._match_builders_pattern_list = [re.compile(p) for p in pattern_list]
-
- def set_skip_builders_pattern_list(self, pattern_list):
- """Override the default set of builders we should skip while processing.
-
- The default is DEFAULT_SKIP_BUILDERS_PATTERN_LIST .
-
- This overrides match_builders_pattern_list; regardless of whether a
- builder is in the "match" list, if it's in the "skip" list, we will skip it.
-
- Args:
- pattern_list: list of regex patterns; skip builders that match any
- entry within this list
- """
- if pattern_list == None:
- pattern_list = []
- self._skip_builders_pattern_list = [re.compile(p) for p in pattern_list]
-
- def _ignore_builder(self, builder):
- """Returns True if we should skip processing this builder.
-
- Args:
- builder: name of this builder, as a string
-
- Returns:
- True if we should ignore expectations and actuals for this builder.
- """
- for pattern in self._skip_builders_pattern_list:
- if pattern.match(builder):
- return True
- for pattern in self._match_builders_pattern_list:
- if pattern.match(builder):
- return False
- return True
-
- def _read_builder_dicts_from_root(self, root, pattern='*.json'):
- """Read all JSON dictionaries within a directory tree.
-
- Skips any dictionaries belonging to a builder we have chosen to ignore.
-
- Args:
- root: path to root of directory tree
- pattern: which files to read within root (fnmatch-style pattern)
-
- Returns:
- A meta-dictionary containing all the JSON dictionaries found within
- the directory tree, keyed by builder name (the basename of the directory
- where each JSON dictionary was found).
-
- Raises:
- IOError if root does not refer to an existing directory
- """
- # I considered making this call read_dicts_from_root(), but I decided
- # it was better to prune out the ignored builders within the os.walk().
- if not os.path.isdir(root):
- raise IOError('no directory found at path %s' % root)
- meta_dict = {}
- for dirpath, _, filenames in os.walk(root):
- for matching_filename in fnmatch.filter(filenames, pattern):
- builder = os.path.basename(dirpath)
- if self._ignore_builder(builder):
- continue
- full_path = os.path.join(dirpath, matching_filename)
- meta_dict[builder] = gm_json.LoadFromFile(full_path)
- return meta_dict
-
- @staticmethod
- def read_dicts_from_root(root, pattern='*.json'):
- """Read all JSON dictionaries within a directory tree.
-
- TODO(stephana): Factor this out into a utility module, as a standalone
- function (not part of a class).
-
- Args:
- root: path to root of directory tree
- pattern: which files to read within root (fnmatch-style pattern)
-
- Returns:
- A meta-dictionary containing all the JSON dictionaries found within
- the directory tree, keyed by the pathname (relative to root) of each JSON
- dictionary.
-
- Raises:
- IOError if root does not refer to an existing directory
- """
- if not os.path.isdir(root):
- raise IOError('no directory found at path %s' % root)
- meta_dict = {}
- for abs_dirpath, _, filenames in os.walk(root):
- rel_dirpath = os.path.relpath(abs_dirpath, root)
- for matching_filename in fnmatch.filter(filenames, pattern):
- abs_path = os.path.join(abs_dirpath, matching_filename)
- rel_path = os.path.join(rel_dirpath, matching_filename)
- meta_dict[rel_path] = gm_json.LoadFromFile(abs_path)
- return meta_dict
-
- @staticmethod
- def _read_noncomment_lines(path):
- """Return a list of all noncomment lines within a file.
-
- (A "noncomment" line is one that does not start with a '#'.)
-
- Args:
- path: path to file
- """
- lines = []
- with open(path, 'r') as fh:
- for line in fh:
- if not line.startswith('#'):
- lines.append(line.strip())
- return lines
-
- @staticmethod
- def _create_relative_url(hashtype_and_digest, test_name):
- """Returns the URL for this image, relative to GM_ACTUALS_ROOT_HTTP_URL.
-
- If we don't have a record of this image, returns None.
-
- Args:
- hashtype_and_digest: (hash_type, hash_digest) tuple, or None if we
- don't have a record of this image
- test_name: string; name of the GM test that created this image
- """
- if not hashtype_and_digest:
- return None
- return gm_json.CreateGmRelativeUrl(
- test_name=test_name,
- hash_type=hashtype_and_digest[0],
- hash_digest=hashtype_and_digest[1])
-
- @staticmethod
- def combine_subdicts(input_dict):
- """ Flatten out a dictionary structure by one level.
-
- Input:
- {
- KEY_A1 : {
- KEY_B1 : VALUE_B1,
- },
- KEY_A2 : {
- KEY_B2 : VALUE_B2,
- }
- }
-
- Output:
- {
- KEY_B1 : VALUE_B1,
- KEY_B2 : VALUE_B2,
- }
-
- If this would result in any repeated keys, it will raise an Exception.
- """
- output_dict = {}
- for subdict in input_dict.values():
- for subdict_key, subdict_value in subdict.iteritems():
- if subdict_key in output_dict:
- raise Exception('duplicate key %s in combine_subdicts' % subdict_key)
- output_dict[subdict_key] = subdict_value
- return output_dict
-
- @staticmethod
- def get_default(input_dict, default_value, *keys):
- """Returns input_dict[key1][key2][...], or default_value.
-
- If input_dict is None, or any key is missing along the way, this returns
- default_value.
-
- Args:
- input_dict: dictionary to look within
- key: key indicating which value to return from input_dict
- default_value: value to return if input_dict is None or any key cannot
- be found along the way
- """
- if input_dict == None:
- return default_value
- for key in keys:
- input_dict = input_dict.get(key, None)
- if input_dict == None:
- return default_value
- return input_dict
diff --git a/gm/rebaseline_server/results_test.py b/gm/rebaseline_server/results_test.py
deleted file mode 100755
index f22e833fe3..0000000000
--- a/gm/rebaseline_server/results_test.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Test results.py
-
-"""
-
-# Imports from within Skia
-import base_unittest
-import results
-
-
-class ResultsTest(base_unittest.TestCase):
-
- def test_ignore_builder(self):
- """Test _ignore_builder()."""
- results_obj = results.BaseComparisons()
- self.assertEqual(results_obj._ignore_builder('SomethingTSAN'), True)
- self.assertEqual(results_obj._ignore_builder('Something-Trybot'), True)
- self.assertEqual(results_obj._ignore_builder(
- 'Test-Ubuntu12-ShuttleA-GTX660-x86-Release'), False)
- results_obj.set_skip_builders_pattern_list(['.*TSAN.*', '.*GTX660.*'])
- self.assertEqual(results_obj._ignore_builder('SomethingTSAN'), True)
- self.assertEqual(results_obj._ignore_builder('Something-Trybot'), False)
- self.assertEqual(results_obj._ignore_builder(
- 'Test-Ubuntu12-ShuttleA-GTX660-x86-Release'), True)
- results_obj.set_skip_builders_pattern_list(None)
- self.assertEqual(results_obj._ignore_builder('SomethingTSAN'), False)
- self.assertEqual(results_obj._ignore_builder('Something-Trybot'), False)
- self.assertEqual(results_obj._ignore_builder(
- 'Test-Ubuntu12-ShuttleA-GTX660-x86-Release'), False)
- results_obj.set_match_builders_pattern_list(['.*TSAN'])
- self.assertEqual(results_obj._ignore_builder('SomethingTSAN'), False)
- self.assertEqual(results_obj._ignore_builder('Something-Trybot'), True)
- self.assertEqual(results_obj._ignore_builder(
- 'Test-Ubuntu12-ShuttleA-GTX660-x86-Release'), True)
-
- def test_combine_subdicts_typical(self):
- """Test combine_subdicts() with no merge conflicts. """
- input_dict = {
- "failed" : {
- "changed.png" : [ "bitmap-64bitMD5", 8891695120562235492 ],
- },
- "no-comparison" : {
- "unchanged.png" : [ "bitmap-64bitMD5", 11092453015575919668 ],
- }
- }
- expected_output_dict = {
- "changed.png" : [ "bitmap-64bitMD5", 8891695120562235492 ],
- "unchanged.png" : [ "bitmap-64bitMD5", 11092453015575919668 ],
- }
- actual_output_dict = results.BaseComparisons.combine_subdicts(
- input_dict=input_dict)
- self.assertEqual(actual_output_dict, expected_output_dict)
-
- def test_combine_subdicts_with_merge_conflict(self):
- """Test combine_subdicts() with a merge conflict. """
- input_dict = {
- "failed" : {
- "changed.png" : [ "bitmap-64bitMD5", 8891695120562235492 ],
- },
- "no-comparison" : {
- "changed.png" : [ "bitmap-64bitMD5", 11092453015575919668 ],
- }
- }
- with self.assertRaises(Exception):
- actual_output_dict = results.BaseComparisons.combine_subdicts(
- input_dict=input_dict)
-
-
-def main():
- base_unittest.main(ResultsTest)
-
-
-if __name__ == '__main__':
- main()
diff --git a/gm/rebaseline_server/rs_fixpypath.py b/gm/rebaseline_server/rs_fixpypath.py
deleted file mode 100755
index cc32f4a6bc..0000000000
--- a/gm/rebaseline_server/rs_fixpypath.py
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Adds possibly-needed directories to PYTHONPATH, if they aren't already there.
-"""
-
-import os
-import sys
-
-TRUNK_DIRECTORY = os.path.abspath(os.path.join(
- os.path.dirname(__file__), os.pardir, os.pardir))
-for subdir in ['common', 'gm', 'tools']:
- fullpath = os.path.join(TRUNK_DIRECTORY, subdir)
- if fullpath not in sys.path:
- sys.path.append(fullpath)
diff --git a/gm/rebaseline_server/server.py b/gm/rebaseline_server/server.py
deleted file mode 100755
index 85874eb666..0000000000
--- a/gm/rebaseline_server/server.py
+++ /dev/null
@@ -1,967 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2013 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-HTTP server for our HTML rebaseline viewer.
-"""
-
-# System-level imports
-import argparse
-import BaseHTTPServer
-import json
-import logging
-import os
-import posixpath
-import re
-import shutil
-import socket
-import subprocess
-import thread
-import threading
-import time
-import urllib
-import urlparse
-
-# Must fix up PYTHONPATH before importing from within Skia
-import rs_fixpypath # pylint: disable=W0611
-
-# Imports from within Skia
-from py.utils import gs_utils
-import buildbot_globals
-import gm_json
-
-# Imports from local dir
-#
-# pylint: disable=C0301
-# Note: we import results under a different name, to avoid confusion with the
-# Server.results() property. See discussion at
-# https://codereview.chromium.org/195943004/diff/1/gm/rebaseline_server/server.py#newcode44
-# pylint: enable=C0301
-import compare_configs
-import compare_rendered_pictures
-import compare_to_expectations
-import download_actuals
-import imagediffdb
-import imagepairset
-import results as results_mod
-import writable_expectations as writable_expectations_mod
-
-
-PATHSPLIT_RE = re.compile('/([^/]+)/(.+)')
-
-# A simple dictionary of file name extensions to MIME types. The empty string
-# entry is used as the default when no extension was given or if the extension
-# has no entry in this dictionary.
-MIME_TYPE_MAP = {'': 'application/octet-stream',
- 'html': 'text/html',
- 'css': 'text/css',
- 'png': 'image/png',
- 'js': 'application/javascript',
- 'json': 'application/json'
- }
-
-# Keys that server.py uses to create the toplevel content header.
-# NOTE: Keep these in sync with static/constants.js
-KEY__EDITS__MODIFICATIONS = 'modifications'
-KEY__EDITS__OLD_RESULTS_HASH = 'oldResultsHash'
-KEY__EDITS__OLD_RESULTS_TYPE = 'oldResultsType'
-KEY__LIVE_EDITS__MODIFICATIONS = 'modifications'
-KEY__LIVE_EDITS__SET_A_DESCRIPTIONS = 'setA'
-KEY__LIVE_EDITS__SET_B_DESCRIPTIONS = 'setB'
-
-DEFAULT_ACTUALS_DIR = results_mod.DEFAULT_ACTUALS_DIR
-DEFAULT_GM_SUMMARIES_BUCKET = download_actuals.GM_SUMMARIES_BUCKET
-DEFAULT_JSON_FILENAME = download_actuals.DEFAULT_JSON_FILENAME
-DEFAULT_PORT = 8888
-
-PARENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
-TRUNK_DIRECTORY = os.path.dirname(os.path.dirname(PARENT_DIRECTORY))
-
-# Directory, relative to PARENT_DIRECTORY, within which the server will serve
-# out static files.
-STATIC_CONTENTS_SUBDIR = 'static'
-# All of the GENERATED_*_SUBDIRS are relative to STATIC_CONTENTS_SUBDIR
-GENERATED_HTML_SUBDIR = 'generated-html'
-GENERATED_IMAGES_SUBDIR = 'generated-images'
-GENERATED_JSON_SUBDIR = 'generated-json'
-
-# Directives associated with various HTTP GET requests.
-GET__LIVE_RESULTS = 'live-results'
-GET__PRECOMPUTED_RESULTS = 'results'
-GET__PREFETCH_RESULTS = 'prefetch'
-GET__STATIC_CONTENTS = 'static'
-
-# Parameters we use within do_GET_live_results() and do_GET_prefetch_results()
-LIVE_PARAM__DOWNLOAD_ONLY_DIFFERING = 'downloadOnlyDifferingImages'
-LIVE_PARAM__SET_A_DIR = 'setADir'
-LIVE_PARAM__SET_A_SECTION = 'setASection'
-LIVE_PARAM__SET_B_DIR = 'setBDir'
-LIVE_PARAM__SET_B_SECTION = 'setBSection'
-
-# How often (in seconds) clients should reload while waiting for initial
-# results to load.
-RELOAD_INTERVAL_UNTIL_READY = 10
-
-_GM_SUMMARY_TYPES = [
- results_mod.KEY__HEADER__RESULTS_FAILURES,
- results_mod.KEY__HEADER__RESULTS_ALL,
-]
-# If --compare-configs is specified, compare these configs.
-CONFIG_PAIRS_TO_COMPARE = [('8888', 'gpu')]
-
-# SKP results that are available to compare.
-#
-# TODO(stephana): We don't actually want to maintain this list of platforms.
-# We are just putting them in here for now, as "convenience" links for testing
-# SKP diffs.
-# Ultimately, we will depend on buildbot steps linking to their own diffs on
-# the shared rebaseline_server instance.
-_SKP_BASE_GS_URL = 'gs://' + buildbot_globals.Get('skp_summaries_bucket')
-_SKP_BASE_REPO_URL = (
- compare_rendered_pictures.REPO_URL_PREFIX + posixpath.join(
- 'expectations', 'skp'))
-_SKP_PLATFORMS = [
- 'Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug',
- 'Test-Ubuntu12-ShuttleA-GTX660-x86-Release',
-]
-
-_HTTP_HEADER_CONTENT_LENGTH = 'Content-Length'
-_HTTP_HEADER_CONTENT_TYPE = 'Content-Type'
-
-_SERVER = None # This gets filled in by main()
-
-
-def _run_command(args, directory):
- """Runs a command and returns stdout as a single string.
-
- Args:
- args: the command to run, as a list of arguments
- directory: directory within which to run the command
-
- Returns: stdout, as a string
-
- Raises an Exception if the command failed (exited with nonzero return code).
- """
- logging.debug('_run_command: %s in directory %s' % (args, directory))
- proc = subprocess.Popen(args, cwd=directory,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- (stdout, stderr) = proc.communicate()
- if proc.returncode is not 0:
- raise Exception('command "%s" failed in dir "%s": %s' %
- (args, directory, stderr))
- return stdout
-
-
-def _get_routable_ip_address():
- """Returns routable IP address of this host (the IP address of its network
- interface that would be used for most traffic, not its localhost
- interface). See http://stackoverflow.com/a/166589 """
- sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- sock.connect(('8.8.8.8', 80))
- host = sock.getsockname()[0]
- sock.close()
- return host
-
-
-def _create_index(file_path, config_pairs):
- """Creates an index file linking to all results available from this server.
-
- Prior to https://codereview.chromium.org/215503002 , we had a static
- index.html within our repo. But now that the results may or may not include
- config comparisons, index.html needs to be generated differently depending
- on which results are included.
-
- TODO(epoger): Instead of including raw HTML within the Python code,
- consider restoring the index.html file as a template and using django (or
- similar) to fill in dynamic content.
-
- Args:
- file_path: path on local disk to write index to; any directory components
- of this path that do not already exist will be created
- config_pairs: what pairs of configs (if any) we compare actual results of
- """
- dir_path = os.path.dirname(file_path)
- if not os.path.isdir(dir_path):
- os.makedirs(dir_path)
- with open(file_path, 'w') as file_handle:
- file_handle.write(
- '<!DOCTYPE html><html>'
- '<head><title>rebaseline_server</title></head>'
- '<body><ul>')
-
- if _GM_SUMMARY_TYPES:
- file_handle.write('<li>GM Expectations vs Actuals</li><ul>')
- for summary_type in _GM_SUMMARY_TYPES:
- file_handle.write(
- '\n<li><a href="/{static_directive}/view.html#/view.html?'
- 'resultsToLoad=/{results_directive}/{summary_type}">'
- '{summary_type}</a></li>'.format(
- results_directive=GET__PRECOMPUTED_RESULTS,
- static_directive=GET__STATIC_CONTENTS,
- summary_type=summary_type))
- file_handle.write('</ul>')
-
- if config_pairs:
- file_handle.write(
- '\n<li>Comparing configs within actual GM results</li><ul>')
- for config_pair in config_pairs:
- file_handle.write('<li>%s vs %s:' % config_pair)
- for summary_type in _GM_SUMMARY_TYPES:
- file_handle.write(
- ' <a href="/%s/view.html#/view.html?'
- 'resultsToLoad=/%s/%s/%s-vs-%s_%s.json">%s</a>' % (
- GET__STATIC_CONTENTS, GET__STATIC_CONTENTS,
- GENERATED_JSON_SUBDIR, config_pair[0], config_pair[1],
- summary_type, summary_type))
- file_handle.write('</li>')
- file_handle.write('</ul>')
-
- if _SKP_PLATFORMS:
- file_handle.write('\n<li>Rendered SKPs:<ul>')
- for builder in _SKP_PLATFORMS:
- file_handle.write(
- '\n<li><a href="../live-view.html#live-view.html?%s">' %
- urllib.urlencode({
- LIVE_PARAM__SET_A_SECTION:
- gm_json.JSONKEY_EXPECTEDRESULTS,
- LIVE_PARAM__SET_A_DIR:
- posixpath.join(_SKP_BASE_REPO_URL, builder),
- LIVE_PARAM__SET_B_SECTION:
- gm_json.JSONKEY_ACTUALRESULTS,
- LIVE_PARAM__SET_B_DIR:
- posixpath.join(_SKP_BASE_GS_URL, builder),
- }))
- file_handle.write('expected vs actuals on %s</a></li>' % builder)
- file_handle.write(
- '\n<li><a href="../live-view.html#live-view.html?%s">' %
- urllib.urlencode({
- LIVE_PARAM__SET_A_SECTION:
- gm_json.JSONKEY_ACTUALRESULTS,
- LIVE_PARAM__SET_A_DIR:
- posixpath.join(_SKP_BASE_GS_URL, _SKP_PLATFORMS[0]),
- LIVE_PARAM__SET_B_SECTION:
- gm_json.JSONKEY_ACTUALRESULTS,
- LIVE_PARAM__SET_B_DIR:
- posixpath.join(_SKP_BASE_GS_URL, _SKP_PLATFORMS[1]),
- }))
- file_handle.write('actuals on %s vs %s</a></li>' % (
- _SKP_PLATFORMS[0], _SKP_PLATFORMS[1]))
- file_handle.write('</li>')
-
- file_handle.write('\n</ul></body></html>')
-
-
-class Server(object):
- """ HTTP server for our HTML rebaseline viewer. """
-
- def __init__(self,
- actuals_source,
- actuals_dir=DEFAULT_ACTUALS_DIR,
- json_filename=DEFAULT_JSON_FILENAME,
- port=DEFAULT_PORT, export=False, editable=True,
- reload_seconds=0, config_pairs=None, builder_regex_list=None,
- boto_file_path=None,
- imagediffdb_threads=imagediffdb.DEFAULT_NUM_WORKER_THREADS):
- """
- Args:
- actuals_source: actuals_source.get_builders() ->
- {builder:string -> [ bucket:string, path:string, generation:string ]}
- If None, don't fetch new actual-results files
- at all, just compare to whatever files are already in actuals_dir
- actuals_dir: directory under which we will check out the latest actual
- GM results
- json_filename: basename of the JSON summary file to load for each builder
- port: which TCP port to listen on for HTTP requests
- export: whether to allow HTTP clients on other hosts to access this server
- editable: whether HTTP clients are allowed to submit new GM baselines
- (SKP baseline modifications are performed using an entirely different
- mechanism, not affected by this parameter)
- reload_seconds: polling interval with which to check for new results;
- if 0, don't check for new results at all
- config_pairs: List of (string, string) tuples; for each tuple, compare
- actual results of these two configs. If None or empty,
- don't compare configs at all.
- builder_regex_list: List of regular expressions specifying which builders
- we will process. If None, process all builders.
- boto_file_path: Path to .boto file giving us credentials to access
- Google Storage buckets; if None, we will only be able to access
- public GS buckets.
- imagediffdb_threads: How many threads to spin up within imagediffdb.
- """
- self._actuals_source = actuals_source
- self._actuals_dir = actuals_dir
- self._json_filename = json_filename
- self._port = port
- self._export = export
- self._editable = editable
- self._reload_seconds = reload_seconds
- self._config_pairs = config_pairs or []
- self._builder_regex_list = builder_regex_list
- self.truncate_results = False
-
- if boto_file_path:
- self._gs = gs_utils.GSUtils(boto_file_path=boto_file_path)
- else:
- self._gs = gs_utils.GSUtils()
-
- _create_index(
- file_path=os.path.join(
- PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_HTML_SUBDIR,
- "index.html"),
- config_pairs=config_pairs)
-
- # Reentrant lock that must be held whenever updating EITHER of:
- # 1. self._results
- # 2. the expected or actual results on local disk
- self.results_rlock = threading.RLock()
-
- # Create a single ImageDiffDB instance that is used by all our differs.
- self._image_diff_db = imagediffdb.ImageDiffDB(
- gs=self._gs,
- storage_root=os.path.join(
- PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR,
- GENERATED_IMAGES_SUBDIR),
- num_worker_threads=imagediffdb_threads)
-
- # This will be filled in by calls to update_results()
- self._results = None
-
- @property
- def results(self):
- """ Returns the most recently generated results, or None if we don't have
- any valid results (update_results() has not completed yet). """
- return self._results
-
- @property
- def image_diff_db(self):
- """ Returns reference to our ImageDiffDB object."""
- return self._image_diff_db
-
- @property
- def gs(self):
- """ Returns reference to our GSUtils object."""
- return self._gs
-
- @property
- def is_exported(self):
- """ Returns true iff HTTP clients on other hosts are allowed to access
- this server. """
- return self._export
-
- @property
- def is_editable(self):
- """ True iff HTTP clients are allowed to submit new GM baselines.
-
- TODO(epoger): This only pertains to GM baselines; SKP baselines are
- editable whenever expectations vs actuals are shown.
- Once we move the GM baselines to use the same code as the SKP baselines,
- we can delete this property.
- """
- return self._editable
-
- @property
- def reload_seconds(self):
- """ Returns the result reload period in seconds, or 0 if we don't reload
- results. """
- return self._reload_seconds
-
- def update_results(self, invalidate=False):
- """ Create or update self._results, based on the latest expectations and
- actuals.
-
- We hold self.results_rlock while we do this, to guarantee that no other
- thread attempts to update either self._results or the underlying files at
- the same time.
-
- Args:
- invalidate: if True, invalidate self._results immediately upon entry;
- otherwise, we will let readers see those results until we
- replace them
- """
- with self.results_rlock:
- if invalidate:
- self._results = None
-
- if self._actuals_source:
- logging.info(
- 'Updating GM result summaries in %s from %s ...'
- % (self._actuals_dir, self._actuals_source.description()))
-
- # Clean out actuals_dir first, in case some builders have gone away
- # since we last ran.
- if os.path.isdir(self._actuals_dir):
- shutil.rmtree(self._actuals_dir)
-
- # Get the list of actuals we care about.
- all_actuals = self._actuals_source.get_builders()
-
- if self._builder_regex_list:
- matching_builders = []
- for builder in all_actuals:
- for regex in self._builder_regex_list:
- if re.match(regex, builder):
- matching_builders.append(builder)
- break # go on to the next builder, no need to try more regexes
- else:
- matching_builders = all_actuals.keys()
-
- # Download the JSON file for each builder we care about.
- #
- # TODO(epoger): When this is a large number of builders, we would be
- # better off downloading them in parallel!
- for builder in matching_builders:
- self._gs.download_file(
- source_bucket=all_actuals[builder].bucket,
- source_path=all_actuals[builder].path,
- source_generation=all_actuals[builder].generation,
- dest_path=os.path.join(self._actuals_dir, builder,
- self._json_filename),
- create_subdirs_if_needed=True)
-
- # We only update the expectations dir if the server was run with a
- # nonzero --reload argument; otherwise, we expect the user to maintain
- # her own expectations as she sees fit.
- #
- # Because the Skia repo is hosted using git, and git does not
- # support updating a single directory tree, we have to update the entire
- # repo checkout.
- #
- # Because Skia uses depot_tools, we have to update using "gclient sync"
- # instead of raw git commands.
- #
- # TODO(epoger): Fetch latest expectations in some other way.
- # Eric points out that our official documentation recommends an
- # unmanaged Skia checkout, so "gclient sync" will not bring down updated
- # expectations from origin/master-- you'd have to do a "git pull" of
- # some sort instead.
- # However, the live rebaseline_server at
- # http://skia-tree-status.appspot.com/redirect/rebaseline-server (which
- # is probably the only user of the --reload flag!) uses a managed
- # checkout, so "gclient sync" works in that case.
- # Probably the best idea is to avoid all of this nonsense by fetching
- # updated expectations into a temp directory, and leaving the rest of
- # the checkout alone. This could be done using "git show", or by
- # downloading individual expectation JSON files from
- # skia.googlesource.com .
- if self._reload_seconds:
- logging.info(
- 'Updating expected GM results in %s by syncing Skia repo ...' %
- compare_to_expectations.DEFAULT_EXPECTATIONS_DIR)
- _run_command(['gclient', 'sync'], TRUNK_DIRECTORY)
-
- self._results = compare_to_expectations.ExpectationComparisons(
- image_diff_db=self._image_diff_db,
- actuals_root=self._actuals_dir,
- diff_base_url=posixpath.join(
- os.pardir, STATIC_CONTENTS_SUBDIR, GENERATED_IMAGES_SUBDIR),
- builder_regex_list=self._builder_regex_list)
-
- json_dir = os.path.join(
- PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_JSON_SUBDIR)
- if not os.path.isdir(json_dir):
- os.makedirs(json_dir)
-
- for config_pair in self._config_pairs:
- config_comparisons = compare_configs.ConfigComparisons(
- configs=config_pair,
- actuals_root=self._actuals_dir,
- generated_images_root=os.path.join(
- PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR,
- GENERATED_IMAGES_SUBDIR),
- diff_base_url=posixpath.join(
- os.pardir, GENERATED_IMAGES_SUBDIR),
- builder_regex_list=self._builder_regex_list)
- for summary_type in _GM_SUMMARY_TYPES:
- gm_json.WriteToFile(
- config_comparisons.get_packaged_results_of_type(
- results_type=summary_type),
- os.path.join(
- json_dir, '%s-vs-%s_%s.json' % (
- config_pair[0], config_pair[1], summary_type)))
-
- def _result_loader(self, reload_seconds=0):
- """ Call self.update_results(), either once or periodically.
-
- Params:
- reload_seconds: integer; if nonzero, reload results at this interval
- (in which case, this method will never return!)
- """
- self.update_results()
- logging.info('Initial results loaded. Ready for requests on %s' % self._url)
- if reload_seconds:
- while True:
- time.sleep(reload_seconds)
- self.update_results()
-
- def run(self):
- arg_tuple = (self._reload_seconds,) # start_new_thread needs a tuple,
- # even though it holds just one param
- thread.start_new_thread(self._result_loader, arg_tuple)
-
- if self._export:
- server_address = ('', self._port)
- host = _get_routable_ip_address()
- if self._editable:
- logging.warning('Running with combination of "export" and "editable" '
- 'flags. Users on other machines will '
- 'be able to modify your GM expectations!')
- else:
- host = '127.0.0.1'
- server_address = (host, self._port)
- # pylint: disable=W0201
- http_server = BaseHTTPServer.HTTPServer(server_address, HTTPRequestHandler)
- self._url = 'http://%s:%d' % (host, http_server.server_port)
- logging.info('Listening for requests on %s' % self._url)
- http_server.serve_forever()
-
-
-class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- """ HTTP request handlers for various types of queries this server knows
- how to handle (static HTML and Javascript, expected/actual results, etc.)
- """
- def do_GET(self):
- """
- Handles all GET requests, forwarding them to the appropriate
- do_GET_* dispatcher.
-
- If we see any Exceptions, return a 404. This fixes http://skbug.com/2147
- """
- try:
- logging.debug('do_GET: path="%s"' % self.path)
- if self.path == '' or self.path == '/' or self.path == '/index.html' :
- self.redirect_to('/%s/%s/index.html' % (
- GET__STATIC_CONTENTS, GENERATED_HTML_SUBDIR))
- return
- if self.path == '/favicon.ico' :
- self.redirect_to('/%s/favicon.ico' % GET__STATIC_CONTENTS)
- return
-
- # All requests must be of this form:
- # /dispatcher/remainder
- # where 'dispatcher' indicates which do_GET_* dispatcher to run
- # and 'remainder' is the remaining path sent to that dispatcher.
- (dispatcher_name, remainder) = PATHSPLIT_RE.match(self.path).groups()
- dispatchers = {
- GET__LIVE_RESULTS: self.do_GET_live_results,
- GET__PRECOMPUTED_RESULTS: self.do_GET_precomputed_results,
- GET__PREFETCH_RESULTS: self.do_GET_prefetch_results,
- GET__STATIC_CONTENTS: self.do_GET_static,
- }
- dispatcher = dispatchers[dispatcher_name]
- dispatcher(remainder)
- except:
- self.send_error(404)
- raise
-
- def do_GET_precomputed_results(self, results_type):
- """ Handle a GET request for part of the precomputed _SERVER.results object.
-
- Args:
- results_type: string indicating which set of results to return;
- must be one of the results_mod.RESULTS_* constants
- """
- logging.debug('do_GET_precomputed_results: sending results of type "%s"' %
- results_type)
- # Since we must make multiple calls to the ExpectationComparisons object,
- # grab a reference to it in case it is updated to point at a new
- # ExpectationComparisons object within another thread.
- #
- # TODO(epoger): Rather than using a global variable for the handler
- # to refer to the Server object, make Server a subclass of
- # HTTPServer, and then it could be available to the handler via
- # the handler's .server instance variable.
- results_obj = _SERVER.results
- if results_obj:
- response_dict = results_obj.get_packaged_results_of_type(
- results_type=results_type, reload_seconds=_SERVER.reload_seconds,
- is_editable=_SERVER.is_editable, is_exported=_SERVER.is_exported)
- else:
- now = int(time.time())
- response_dict = {
- imagepairset.KEY__ROOT__HEADER: {
- results_mod.KEY__HEADER__SCHEMA_VERSION: (
- results_mod.VALUE__HEADER__SCHEMA_VERSION),
- results_mod.KEY__HEADER__IS_STILL_LOADING: True,
- results_mod.KEY__HEADER__TIME_UPDATED: now,
- results_mod.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE: (
- now + RELOAD_INTERVAL_UNTIL_READY),
- },
- }
- self.send_json_dict(response_dict)
-
- def _get_live_results_or_prefetch(self, url_remainder, prefetch_only=False):
- """ Handle a GET request for live-generated image diff data.
-
- Args:
- url_remainder: string indicating which image diffs to generate
- prefetch_only: if True, the user isn't waiting around for results
- """
- param_dict = urlparse.parse_qs(url_remainder)
- download_all_images = (
- param_dict.get(LIVE_PARAM__DOWNLOAD_ONLY_DIFFERING, [''])[0].lower()
- not in ['1', 'true'])
- setA_dir = param_dict[LIVE_PARAM__SET_A_DIR][0]
- setB_dir = param_dict[LIVE_PARAM__SET_B_DIR][0]
- setA_section = self._validate_summary_section(
- param_dict.get(LIVE_PARAM__SET_A_SECTION, [None])[0])
- setB_section = self._validate_summary_section(
- param_dict.get(LIVE_PARAM__SET_B_SECTION, [None])[0])
-
- # If the sets show expectations vs actuals, always show expectations on
- # the left (setA).
- if ((setA_section == gm_json.JSONKEY_ACTUALRESULTS) and
- (setB_section == gm_json.JSONKEY_EXPECTEDRESULTS)):
- setA_dir, setB_dir = setB_dir, setA_dir
- setA_section, setB_section = setB_section, setA_section
-
- # Are we comparing some actuals against expectations stored in the repo?
- # If so, we can allow the user to submit new baselines.
- is_editable = (
- (setA_section == gm_json.JSONKEY_EXPECTEDRESULTS) and
- (setA_dir.startswith(compare_rendered_pictures.REPO_URL_PREFIX)) and
- (setB_section == gm_json.JSONKEY_ACTUALRESULTS))
-
- results_obj = compare_rendered_pictures.RenderedPicturesComparisons(
- setA_dir=setA_dir, setB_dir=setB_dir,
- setA_section=setA_section, setB_section=setB_section,
- image_diff_db=_SERVER.image_diff_db,
- diff_base_url='/static/generated-images',
- gs=_SERVER.gs, truncate_results=_SERVER.truncate_results,
- prefetch_only=prefetch_only, download_all_images=download_all_images)
- if prefetch_only:
- self.send_response(200)
- else:
- self.send_json_dict(results_obj.get_packaged_results_of_type(
- results_type=results_mod.KEY__HEADER__RESULTS_ALL,
- is_editable=is_editable))
-
- def do_GET_live_results(self, url_remainder):
- """ Handle a GET request for live-generated image diff data.
-
- Args:
- url_remainder: string indicating which image diffs to generate
- """
- logging.debug('do_GET_live_results: url_remainder="%s"' % url_remainder)
- self._get_live_results_or_prefetch(
- url_remainder=url_remainder, prefetch_only=False)
-
- def do_GET_prefetch_results(self, url_remainder):
- """ Prefetch image diff data for a future do_GET_live_results() call.
-
- Args:
- url_remainder: string indicating which image diffs to generate
- """
- logging.debug('do_GET_prefetch_results: url_remainder="%s"' % url_remainder)
- self._get_live_results_or_prefetch(
- url_remainder=url_remainder, prefetch_only=True)
-
- def do_GET_static(self, path):
- """ Handle a GET request for a file under STATIC_CONTENTS_SUBDIR .
- Only allow serving of files within STATIC_CONTENTS_SUBDIR that is a
- filesystem sibling of this script.
-
- Args:
- path: path to file (within STATIC_CONTENTS_SUBDIR) to retrieve
- """
- # Strip arguments ('?resultsToLoad=all') from the path
- path = urlparse.urlparse(path).path
-
- logging.debug('do_GET_static: sending file "%s"' % path)
- static_dir = os.path.realpath(os.path.join(
- PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR))
- full_path = os.path.realpath(os.path.join(static_dir, path))
- if full_path.startswith(static_dir):
- self.send_file(full_path)
- else:
- logging.error(
- 'Attempted do_GET_static() of path [%s] outside of static dir [%s]'
- % (full_path, static_dir))
- self.send_error(404)
-
- def do_POST(self):
- """ Handles all POST requests, forwarding them to the appropriate
- do_POST_* dispatcher. """
- # All requests must be of this form:
- # /dispatcher
- # where 'dispatcher' indicates which do_POST_* dispatcher to run.
- logging.debug('do_POST: path="%s"' % self.path)
- normpath = posixpath.normpath(self.path)
- dispatchers = {
- '/edits': self.do_POST_edits,
- '/live-edits': self.do_POST_live_edits,
- }
- try:
- dispatcher = dispatchers[normpath]
- dispatcher()
- except:
- self.send_error(404)
- raise
-
- def do_POST_edits(self):
- """ Handle a POST request with modifications to GM expectations, in this
- format:
-
- {
- KEY__EDITS__OLD_RESULTS_TYPE: 'all', # type of results that the client
- # loaded and then made
- # modifications to
- KEY__EDITS__OLD_RESULTS_HASH: 39850913, # hash of results when the client
- # loaded them (ensures that the
- # client and server apply
- # modifications to the same base)
- KEY__EDITS__MODIFICATIONS: [
- # as needed by compare_to_expectations.edit_expectations()
- ...
- ],
- }
-
- Raises an Exception if there were any problems.
- """
- if not _SERVER.is_editable:
- raise Exception('this server is not running in --editable mode')
-
- content_type = self.headers[_HTTP_HEADER_CONTENT_TYPE]
- if content_type != 'application/json;charset=UTF-8':
- raise Exception('unsupported %s [%s]' % (
- _HTTP_HEADER_CONTENT_TYPE, content_type))
-
- content_length = int(self.headers[_HTTP_HEADER_CONTENT_LENGTH])
- json_data = self.rfile.read(content_length)
- data = json.loads(json_data)
- logging.debug('do_POST_edits: received new GM expectations data [%s]' %
- data)
-
- # Update the results on disk with the information we received from the
- # client.
- # We must hold _SERVER.results_rlock while we do this, to guarantee that
- # no other thread updates expectations (from the Skia repo) while we are
- # updating them (using the info we received from the client).
- with _SERVER.results_rlock:
- oldResultsType = data[KEY__EDITS__OLD_RESULTS_TYPE]
- oldResults = _SERVER.results.get_results_of_type(oldResultsType)
- oldResultsHash = str(hash(repr(
- oldResults[imagepairset.KEY__ROOT__IMAGEPAIRS])))
- if oldResultsHash != data[KEY__EDITS__OLD_RESULTS_HASH]:
- raise Exception('results of type "%s" changed while the client was '
- 'making modifications. The client should reload the '
- 'results and submit the modifications again.' %
- oldResultsType)
- _SERVER.results.edit_expectations(data[KEY__EDITS__MODIFICATIONS])
-
- # Read the updated results back from disk.
- # We can do this in a separate thread; we should return our success message
- # to the UI as soon as possible.
- thread.start_new_thread(_SERVER.update_results, (True,))
- self.send_response(200)
-
- def do_POST_live_edits(self):
- """ Handle a POST request with modifications to SKP expectations, in this
- format:
-
- {
- KEY__LIVE_EDITS__SET_A_DESCRIPTIONS: {
- # setA descriptions from the original data
- },
- KEY__LIVE_EDITS__SET_B_DESCRIPTIONS: {
- # setB descriptions from the original data
- },
- KEY__LIVE_EDITS__MODIFICATIONS: [
- # as needed by writable_expectations.modify()
- ],
- }
-
- Raises an Exception if there were any problems.
- """
- content_type = self.headers[_HTTP_HEADER_CONTENT_TYPE]
- if content_type != 'application/json;charset=UTF-8':
- raise Exception('unsupported %s [%s]' % (
- _HTTP_HEADER_CONTENT_TYPE, content_type))
-
- content_length = int(self.headers[_HTTP_HEADER_CONTENT_LENGTH])
- json_data = self.rfile.read(content_length)
- data = json.loads(json_data)
- logging.debug('do_POST_live_edits: received new GM expectations data [%s]' %
- data)
- with writable_expectations_mod.WritableExpectations(
- data[KEY__LIVE_EDITS__SET_A_DESCRIPTIONS]) as writable_expectations:
- writable_expectations.modify(data[KEY__LIVE_EDITS__MODIFICATIONS])
- diffs = writable_expectations.get_diffs()
- # TODO(stephana): Move to a simpler web framework so we don't have to
- # call these functions. See http://skbug.com/2856 ('rebaseline_server:
- # Refactor server to use a simple web framework')
- self.send_response(200)
- self.send_header('Content-type', 'text/plain')
- self.end_headers()
- self.wfile.write(diffs)
-
- def redirect_to(self, url):
- """ Redirect the HTTP client to a different url.
-
- Args:
- url: URL to redirect the HTTP client to
- """
- self.send_response(301)
- self.send_header('Location', url)
- self.end_headers()
-
- def send_file(self, path):
- """ Send the contents of the file at this path, with a mimetype based
- on the filename extension.
-
- Args:
- path: path of file whose contents to send to the HTTP client
- """
- # Grab the extension if there is one
- extension = os.path.splitext(path)[1]
- if len(extension) >= 1:
- extension = extension[1:]
-
- # Determine the MIME type of the file from its extension
- mime_type = MIME_TYPE_MAP.get(extension, MIME_TYPE_MAP[''])
-
- # Open the file and send it over HTTP
- if os.path.isfile(path):
- with open(path, 'rb') as sending_file:
- self.send_response(200)
- self.send_header('Content-type', mime_type)
- self.end_headers()
- self.wfile.write(sending_file.read())
- else:
- self.send_error(404)
-
- def send_json_dict(self, json_dict):
- """ Send the contents of this dictionary in JSON format, with a JSON
- mimetype.
-
- Args:
- json_dict: dictionary to send
- """
- self.send_response(200)
- self.send_header('Content-type', 'application/json')
- self.end_headers()
- json.dump(json_dict, self.wfile)
-
- def _validate_summary_section(self, section_name):
- """Validates the section we have been requested to read within JSON summary.
-
- Args:
- section_name: which section of the JSON summary file has been requested
-
- Returns: the validated section name
-
- Raises: Exception if an invalid section_name was requested.
- """
- if section_name not in compare_rendered_pictures.ALLOWED_SECTION_NAMES:
- raise Exception('requested section name "%s" not in allowed list %s' % (
- section_name, compare_rendered_pictures.ALLOWED_SECTION_NAMES))
- return section_name
-
-
-def main():
- logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
- datefmt='%m/%d/%Y %H:%M:%S',
- level=logging.INFO)
- parser = argparse.ArgumentParser()
- parser.add_argument('--actuals-dir',
- help=('Directory into which we will check out the latest '
- 'actual GM results. If this directory does not '
- 'exist, it will be created. Defaults to %(default)s'),
- default=DEFAULT_ACTUALS_DIR)
- parser.add_argument('--boto',
- help=('Path to .boto file giving us credentials to access '
- 'Google Storage buckets. If not specified, we will '
- 'only be able to access public GS buckets (and thus '
- 'won\'t be able to download SKP images).'),
- default='')
- # TODO(epoger): Before https://codereview.chromium.org/310093003 ,
- # when this tool downloaded the JSON summaries from skia-autogen,
- # it had an --actuals-revision the caller could specify to download
- # actual results as of a specific point in time. We should add similar
- # functionality when retrieving the summaries from Google Storage.
- parser.add_argument('--builders', metavar='BUILDER_REGEX', nargs='+',
- help=('Only process builders matching these regular '
- 'expressions. If unspecified, process all '
- 'builders.'))
- parser.add_argument('--compare-configs', action='store_true',
- help=('In addition to generating differences between '
- 'expectations and actuals, also generate '
- 'differences between these config pairs: '
- + str(CONFIG_PAIRS_TO_COMPARE)))
- parser.add_argument('--editable', action='store_true',
- help=('Allow HTTP clients to submit new GM baselines; '
- 'SKP baselines can be edited regardless of this '
- 'setting.'))
- parser.add_argument('--export', action='store_true',
- help=('Instead of only allowing access from HTTP clients '
- 'on localhost, allow HTTP clients on other hosts '
- 'to access this server. WARNING: doing so will '
- 'allow users on other hosts to modify your '
- 'GM expectations, if combined with --editable.'))
- parser.add_argument('--rietveld-issue',
- help=('Download json_filename files from latest trybot'
- 'runs on this codereview.chromium.org issue.'
- 'Overrides --gm-summaries-bucket.'))
- parser.add_argument('--gm-summaries-bucket',
- help=('Google Cloud Storage bucket to download '
- 'JSON_FILENAME files from. '
- 'Defaults to %(default)s ; if set to '
- 'empty string, just compare to actual-results '
- 'already found in ACTUALS_DIR.'),
- default=DEFAULT_GM_SUMMARIES_BUCKET)
- parser.add_argument('--json-filename',
- help=('JSON summary filename to read for each builder; '
- 'defaults to %(default)s.'),
- default=DEFAULT_JSON_FILENAME)
- parser.add_argument('--port', type=int,
- help=('Which TCP port to listen on for HTTP requests; '
- 'defaults to %(default)s'),
- default=DEFAULT_PORT)
- parser.add_argument('--reload', type=int,
- help=('How often (a period in seconds) to update the '
- 'results. If specified, both expected and actual '
- 'results will be updated by running "gclient sync" '
- 'on your Skia checkout as a whole. '
- 'By default, we do not reload at all, and you '
- 'must restart the server to pick up new data.'),
- default=0)
- parser.add_argument('--threads', type=int,
- help=('How many parallel threads we use to download '
- 'images and generate diffs; defaults to '
- '%(default)s'),
- default=imagediffdb.DEFAULT_NUM_WORKER_THREADS)
- parser.add_argument('--truncate', action='store_true',
- help=('FOR TESTING ONLY: truncate the set of images we '
- 'process, to speed up testing.'))
- args = parser.parse_args()
- if args.compare_configs:
- config_pairs = CONFIG_PAIRS_TO_COMPARE
- else:
- config_pairs = None
-
- if args.rietveld_issue:
- actuals_source = download_actuals.RietveldIssueActuals(args.rietveld_issue,
- args.json_filename)
- else:
- actuals_source = download_actuals.TipOfTreeActuals(args.gm_summaries_bucket,
- args.json_filename)
-
- global _SERVER
- _SERVER = Server(actuals_source,
- actuals_dir=args.actuals_dir,
- json_filename=args.json_filename,
- port=args.port, export=args.export, editable=args.editable,
- reload_seconds=args.reload, config_pairs=config_pairs,
- builder_regex_list=args.builders, boto_file_path=args.boto,
- imagediffdb_threads=args.threads)
- if args.truncate:
- _SERVER.truncate_results = True
- _SERVER.run()
-
-
-if __name__ == '__main__':
- main()
diff --git a/gm/rebaseline_server/static/.gitignore b/gm/rebaseline_server/static/.gitignore
deleted file mode 100644
index c8e67d128f..0000000000
--- a/gm/rebaseline_server/static/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-generated-html/
-generated-images/
-generated-json/
diff --git a/gm/rebaseline_server/static/constants.js b/gm/rebaseline_server/static/constants.js
deleted file mode 100644
index a9601ece71..0000000000
--- a/gm/rebaseline_server/static/constants.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Constants used by our imagediff-viewing Javascript code.
- */
-var module = angular.module(
- 'ConstantsModule',
- []
-);
-
-module.constant('constants', (function() {
- return {
- // NOTE: Keep these in sync with ../column.py
- KEY__EXTRACOLUMNHEADERS__HEADER_TEXT: 'headerText',
- KEY__EXTRACOLUMNHEADERS__HEADER_URL: 'headerUrl',
- KEY__EXTRACOLUMNHEADERS__IS_FILTERABLE: 'isFilterable',
- KEY__EXTRACOLUMNHEADERS__IS_SORTABLE: 'isSortable',
- KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER: 'useFreeformFilter',
- KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS: 'valuesAndCounts',
-
- // NOTE: Keep these in sync with ../imagediffdb.py
- KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL: 'maxDiffPerChannel',
- KEY__DIFFERENCES__NUM_DIFF_PIXELS: 'numDifferingPixels',
- KEY__DIFFERENCES__PERCENT_DIFF_PIXELS: 'percentDifferingPixels',
- KEY__DIFFERENCES__PERCEPTUAL_DIFF: 'perceptualDifference',
- KEY__DIFFERENCES__DIFF_URL: 'diffUrl',
- KEY__DIFFERENCES__WHITE_DIFF_URL: 'whiteDiffUrl',
-
- // NOTE: Keep these in sync with ../imagepair.py
- KEY__IMAGEPAIRS__DIFFERENCES: 'differenceData',
- KEY__IMAGEPAIRS__EXPECTATIONS: 'expectations',
- KEY__IMAGEPAIRS__EXTRACOLUMNS: 'extraColumns',
- KEY__IMAGEPAIRS__IMAGE_A_URL: 'imageAUrl',
- KEY__IMAGEPAIRS__IMAGE_B_URL: 'imageBUrl',
- KEY__IMAGEPAIRS__IS_DIFFERENT: 'isDifferent',
- KEY__IMAGEPAIRS__SOURCE_JSON_FILE: 'sourceJsonFile',
-
- // NOTE: Keep these in sync with ../imagepairset.py
- KEY__ROOT__EXTRACOLUMNHEADERS: 'extraColumnHeaders',
- KEY__ROOT__EXTRACOLUMNORDER: 'extraColumnOrder',
- KEY__ROOT__HEADER: 'header',
- KEY__ROOT__IMAGEPAIRS: 'imagePairs',
- KEY__ROOT__IMAGESETS: 'imageSets',
- //
- KEY__IMAGESETS__FIELD__BASE_URL: 'baseUrl',
- KEY__IMAGESETS__FIELD__DESCRIPTION: 'description',
- KEY__IMAGESETS__SET__DIFFS: 'diffs',
- KEY__IMAGESETS__SET__IMAGE_A: 'imageA',
- KEY__IMAGESETS__SET__IMAGE_B: 'imageB',
- KEY__IMAGESETS__SET__WHITEDIFFS: 'whiteDiffs',
-
- // NOTE: Keep these in sync with ../results.py
- KEY__EXPECTATIONS__BUGS: 'bugs',
- KEY__EXPECTATIONS__IGNOREFAILURE: 'ignore-failure',
- KEY__EXPECTATIONS__REVIEWED: 'reviewed-by-human',
- //
- KEY__EXTRACOLUMNS__BUILDER: 'builder',
- KEY__EXTRACOLUMNS__CONFIG: 'config',
- KEY__EXTRACOLUMNS__RESULT_TYPE: 'resultType',
- KEY__EXTRACOLUMNS__TEST: 'test',
- //
- KEY__HEADER__DATAHASH: 'dataHash',
- KEY__HEADER__IS_EDITABLE: 'isEditable',
- KEY__HEADER__IS_EXPORTED: 'isExported',
- KEY__HEADER__IS_STILL_LOADING: 'resultsStillLoading',
- KEY__HEADER__RESULTS_ALL: 'all',
- KEY__HEADER__RESULTS_FAILURES: 'failures',
- KEY__HEADER__SCHEMA_VERSION: 'schemaVersion',
- KEY__HEADER__SET_A_DESCRIPTIONS: 'setA',
- KEY__HEADER__SET_B_DESCRIPTIONS: 'setB',
- KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE: 'timeNextUpdateAvailable',
- KEY__HEADER__TIME_UPDATED: 'timeUpdated',
- KEY__HEADER__TYPE: 'type',
- VALUE__HEADER__SCHEMA_VERSION: 5,
- //
- KEY__RESULT_TYPE__FAILED: 'failed',
- KEY__RESULT_TYPE__FAILUREIGNORED: 'failure-ignored',
- KEY__RESULT_TYPE__NOCOMPARISON: 'no-comparison',
- KEY__RESULT_TYPE__SUCCEEDED: 'succeeded',
- //
- KEY__SET_DESCRIPTIONS__DIR: 'dir',
- KEY__SET_DESCRIPTIONS__REPO_REVISION: 'repoRevision',
- KEY__SET_DESCRIPTIONS__SECTION: 'section',
-
- // NOTE: Keep these in sync with ../server.py
- KEY__EDITS__MODIFICATIONS: 'modifications',
- KEY__EDITS__OLD_RESULTS_HASH: 'oldResultsHash',
- KEY__EDITS__OLD_RESULTS_TYPE: 'oldResultsType',
- KEY__LIVE_EDITS__MODIFICATIONS: 'modifications',
- KEY__LIVE_EDITS__SET_A_DESCRIPTIONS: 'setA',
- KEY__LIVE_EDITS__SET_B_DESCRIPTIONS: 'setB',
-
- // These are just used on the client side, no need to sync with server code.
- KEY__IMAGEPAIRS__ROWSPAN: 'rowspan',
- URL_KEY__SCHEMA_VERSION: 'urlSchemaVersion',
- URL_VALUE__SCHEMA_VERSION__CURRENT: 1,
-
- // Utility constants only used on the client side.
- ASC: 'asc',
- DESC: 'desc',
- }
-})())
diff --git a/gm/rebaseline_server/static/live-loader.js b/gm/rebaseline_server/static/live-loader.js
deleted file mode 100644
index ab15aee41a..0000000000
--- a/gm/rebaseline_server/static/live-loader.js
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
- * Loader:
- * Reads GM result reports written out by results.py, and imports
- * them into $scope.extraColumnHeaders and $scope.imagePairs .
- */
-var Loader = angular.module(
- 'Loader',
- ['ConstantsModule']
-);
-
-// This configuration is needed to allow downloads of the diff patch.
-// See https://github.com/angular/angular.js/issues/3889
-Loader.config(['$compileProvider', function($compileProvider) {
- $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|file|blob):/);
-}]);
-
-Loader.directive(
- 'resultsUpdatedCallbackDirective',
- ['$timeout',
- function($timeout) {
- return function(scope, element, attrs) {
- if (scope.$last) {
- $timeout(function() {
- scope.resultsUpdatedCallback();
- });
- }
- };
- }
- ]
-);
-
-// TODO(epoger): Combine ALL of our filtering operations (including
-// truncation) into this one filter, so that runs most efficiently?
-// (We would have to make sure truncation still took place after
-// sorting, though.)
-Loader.filter(
- 'removeHiddenImagePairs',
- function(constants) {
- return function(unfilteredImagePairs, filterableColumnNames, showingColumnValues,
- viewingTab) {
- var filteredImagePairs = [];
- for (var i = 0; i < unfilteredImagePairs.length; i++) {
- var imagePair = unfilteredImagePairs[i];
- var extraColumnValues = imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS];
- var allColumnValuesAreVisible = true;
- // Loop over all columns, and if any of them contain values not found in
- // showingColumnValues[columnName], don't include this imagePair.
- //
- // We use this same filtering mechanism regardless of whether each column
- // has USE_FREEFORM_FILTER set or not; if that flag is set, then we will
- // have already used the freeform text entry block to populate
- // showingColumnValues[columnName].
- for (var j = 0; j < filterableColumnNames.length; j++) {
- var columnName = filterableColumnNames[j];
- var columnValue = extraColumnValues[columnName];
- if (!showingColumnValues[columnName][columnValue]) {
- allColumnValuesAreVisible = false;
- break;
- }
- }
- if (allColumnValuesAreVisible && (viewingTab == imagePair.tab)) {
- filteredImagePairs.push(imagePair);
- }
- }
- return filteredImagePairs;
- };
- }
-);
-
-/**
- * Limit the input imagePairs to some max number, and merge identical rows
- * (adjacent rows which have the same (imageA, imageB) pair).
- *
- * @param unfilteredImagePairs imagePairs to filter
- * @param maxPairs maximum number of pairs to output, or <0 for no limit
- * @param mergeIdenticalRows if true, merge identical rows by setting
- * ROWSPAN>1 on the first merged row, and ROWSPAN=0 for the rest
- */
-Loader.filter(
- 'mergeAndLimit',
- function(constants) {
- return function(unfilteredImagePairs, maxPairs, mergeIdenticalRows) {
- var numPairs = unfilteredImagePairs.length;
- if ((maxPairs > 0) && (maxPairs < numPairs)) {
- numPairs = maxPairs;
- }
- var filteredImagePairs = [];
- if (!mergeIdenticalRows || (numPairs == 1)) {
- // Take a shortcut if we're not merging identical rows.
- // We still need to set ROWSPAN to 1 for each row, for the HTML viewer.
- for (var i = numPairs-1; i >= 0; i--) {
- var imagePair = unfilteredImagePairs[i];
- imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] = 1;
- filteredImagePairs[i] = imagePair;
- }
- } else if (numPairs > 1) {
- // General case--there are at least 2 rows, so we may need to merge some.
- // Work from the bottom up, so we can keep a running total of how many
- // rows should be merged, and set ROWSPAN of the top row accordingly.
- var imagePair = unfilteredImagePairs[numPairs-1];
- var nextRowImageAUrl = imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL];
- var nextRowImageBUrl = imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL];
- imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] = 1;
- filteredImagePairs[numPairs-1] = imagePair;
- for (var i = numPairs-2; i >= 0; i--) {
- imagePair = unfilteredImagePairs[i];
- var thisRowImageAUrl = imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL];
- var thisRowImageBUrl = imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL];
- if ((thisRowImageAUrl == nextRowImageAUrl) &&
- (thisRowImageBUrl == nextRowImageBUrl)) {
- imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] =
- filteredImagePairs[i+1][constants.KEY__IMAGEPAIRS__ROWSPAN] + 1;
- filteredImagePairs[i+1][constants.KEY__IMAGEPAIRS__ROWSPAN] = 0;
- } else {
- imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] = 1;
- nextRowImageAUrl = thisRowImageAUrl;
- nextRowImageBUrl = thisRowImageBUrl;
- }
- filteredImagePairs[i] = imagePair;
- }
- } else {
- // No results.
- }
- return filteredImagePairs;
- };
- }
-);
-
-
-Loader.controller(
- 'Loader.Controller',
- function($scope, $http, $filter, $location, $log, $timeout, constants) {
- $scope.readyToDisplay = false;
- $scope.constants = constants;
- $scope.windowTitle = "Loading GM Results...";
- $scope.setADir = $location.search().setADir;
- $scope.setASection = $location.search().setASection;
- $scope.setBDir = $location.search().setBDir;
- $scope.setBSection = $location.search().setBSection;
- $scope.loadingMessage = "please wait...";
-
- var currSortAsc = true;
-
-
- /**
- * On initial page load, load a full dictionary of results.
- * Once the dictionary is loaded, unhide the page elements so they can
- * render the data.
- */
- $scope.liveQueryUrl =
- "/live-results/setADir=" + encodeURIComponent($scope.setADir) +
- "&setASection=" + encodeURIComponent($scope.setASection) +
- "&setBDir=" + encodeURIComponent($scope.setBDir) +
- "&setBSection=" + encodeURIComponent($scope.setBSection);
- $http.get($scope.liveQueryUrl).success(
- function(data, status, header, config) {
- var dataHeader = data[constants.KEY__ROOT__HEADER];
- if (dataHeader[constants.KEY__HEADER__SCHEMA_VERSION] !=
- constants.VALUE__HEADER__SCHEMA_VERSION) {
- $scope.loadingMessage = "ERROR: Got JSON file with schema version "
- + dataHeader[constants.KEY__HEADER__SCHEMA_VERSION]
- + " but expected schema version "
- + constants.VALUE__HEADER__SCHEMA_VERSION;
- } else if (dataHeader[constants.KEY__HEADER__IS_STILL_LOADING]) {
- // Apply the server's requested reload delay to local time,
- // so we will wait the right number of seconds regardless of clock
- // skew between client and server.
- var reloadDelayInSeconds =
- dataHeader[constants.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE] -
- dataHeader[constants.KEY__HEADER__TIME_UPDATED];
- var timeNow = new Date().getTime();
- var timeToReload = timeNow + reloadDelayInSeconds * 1000;
- $scope.loadingMessage =
- "server is still loading results; will retry at " +
- $scope.localTimeString(timeToReload / 1000);
- $timeout(
- function(){location.reload();},
- timeToReload - timeNow);
- } else {
- $scope.loadingMessage = "processing data, please wait...";
-
- $scope.header = dataHeader;
- $scope.extraColumnHeaders = data[constants.KEY__ROOT__EXTRACOLUMNHEADERS];
- $scope.orderedColumnNames = data[constants.KEY__ROOT__EXTRACOLUMNORDER];
- $scope.imagePairs = data[constants.KEY__ROOT__IMAGEPAIRS];
- $scope.imageSets = data[constants.KEY__ROOT__IMAGESETS];
-
- // set the default sort column and make it ascending.
- $scope.sortColumnSubdict = constants.KEY__IMAGEPAIRS__DIFFERENCES;
- $scope.sortColumnKey = constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF;
- currSortAsc = true;
-
- $scope.showSubmitAdvancedSettings = false;
- $scope.submitAdvancedSettings = {};
- $scope.submitAdvancedSettings[
- constants.KEY__EXPECTATIONS__REVIEWED] = true;
- $scope.submitAdvancedSettings[
- constants.KEY__EXPECTATIONS__IGNOREFAILURE] = false;
- $scope.submitAdvancedSettings['bug'] = '';
-
- // Create the list of tabs (lists into which the user can file each
- // test). This may vary, depending on isEditable.
- $scope.tabs = [
- 'Unfiled', 'Hidden'
- ];
- if (dataHeader[constants.KEY__HEADER__IS_EDITABLE]) {
- $scope.tabs = $scope.tabs.concat(
- ['Pending Approval']);
- }
- $scope.defaultTab = $scope.tabs[0];
- $scope.viewingTab = $scope.defaultTab;
-
- // Track the number of results on each tab.
- $scope.numResultsPerTab = {};
- for (var i = 0; i < $scope.tabs.length; i++) {
- $scope.numResultsPerTab[$scope.tabs[i]] = 0;
- }
- $scope.numResultsPerTab[$scope.defaultTab] = $scope.imagePairs.length;
-
- // Add index and tab fields to all records.
- for (var i = 0; i < $scope.imagePairs.length; i++) {
- $scope.imagePairs[i].index = i;
- $scope.imagePairs[i].tab = $scope.defaultTab;
- }
-
- // Arrays within which the user can toggle individual elements.
- $scope.selectedImagePairs = [];
-
- // Set up filters.
- //
- // filterableColumnNames is a list of all column names we can filter on.
- // allColumnValues[columnName] is a list of all known values
- // for a given column.
- // showingColumnValues[columnName] is a set indicating which values
- // in a given column would cause us to show a row, rather than hiding it.
- //
- // columnStringMatch[columnName] is a string used as a pattern to generate
- // showingColumnValues[columnName] for columns we filter using free-form text.
- // It is ignored for any columns with USE_FREEFORM_FILTER == false.
- $scope.filterableColumnNames = [];
- $scope.allColumnValues = {};
- $scope.showingColumnValues = {};
- $scope.columnStringMatch = {};
-
- angular.forEach(
- Object.keys($scope.extraColumnHeaders),
- function(columnName) {
- var columnHeader = $scope.extraColumnHeaders[columnName];
- if (columnHeader[constants.KEY__EXTRACOLUMNHEADERS__IS_FILTERABLE]) {
- $scope.filterableColumnNames.push(columnName);
- $scope.allColumnValues[columnName] = $scope.columnSliceOf2DArray(
- columnHeader[constants.KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS], 0);
- $scope.showingColumnValues[columnName] = {};
- $scope.toggleValuesInSet($scope.allColumnValues[columnName],
- $scope.showingColumnValues[columnName]);
- $scope.columnStringMatch[columnName] = "";
- }
- }
- );
-
- // TODO(epoger): Special handling for RESULT_TYPE column:
- // by default, show only KEY__RESULT_TYPE__FAILED results
- $scope.showingColumnValues[constants.KEY__EXTRACOLUMNS__RESULT_TYPE] = {};
- $scope.showingColumnValues[constants.KEY__EXTRACOLUMNS__RESULT_TYPE][
- constants.KEY__RESULT_TYPE__FAILED] = true;
-
- // Set up mapping for URL parameters.
- // parameter name -> copier object to load/save parameter value
- $scope.queryParameters.map = {
- 'setADir': $scope.queryParameters.copiers.simple,
- 'setASection': $scope.queryParameters.copiers.simple,
- 'setBDir': $scope.queryParameters.copiers.simple,
- 'setBSection': $scope.queryParameters.copiers.simple,
- 'displayLimitPending': $scope.queryParameters.copiers.simple,
- 'showThumbnailsPending': $scope.queryParameters.copiers.simple,
- 'mergeIdenticalRowsPending': $scope.queryParameters.copiers.simple,
- 'imageSizePending': $scope.queryParameters.copiers.simple,
- 'sortColumnSubdict': $scope.queryParameters.copiers.simple,
- 'sortColumnKey': $scope.queryParameters.copiers.simple,
- };
- // Some parameters are handled differently based on whether they USE_FREEFORM_FILTER.
- angular.forEach(
- $scope.filterableColumnNames,
- function(columnName) {
- if ($scope.extraColumnHeaders[columnName]
- [constants.KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER]) {
- $scope.queryParameters.map[columnName] =
- $scope.queryParameters.copiers.columnStringMatch;
- } else {
- $scope.queryParameters.map[columnName] =
- $scope.queryParameters.copiers.showingColumnValuesSet;
- }
- }
- );
-
- // If any defaults were overridden in the URL, get them now.
- $scope.queryParameters.load();
-
- // Any image URLs which are relative should be relative to the JSON
- // file's source directory; absolute URLs should be left alone.
- var baseUrlKey = constants.KEY__IMAGESETS__FIELD__BASE_URL;
- angular.forEach(
- $scope.imageSets,
- function(imageSet) {
- var baseUrl = imageSet[baseUrlKey];
- if ((baseUrl.substring(0, 1) != '/') &&
- (baseUrl.indexOf('://') == -1)) {
- imageSet[baseUrlKey] = '/' + baseUrl;
- }
- }
- );
-
- $scope.readyToDisplay = true;
- $scope.updateResults();
- $scope.loadingMessage = "";
- $scope.windowTitle = "Current GM Results";
-
- $timeout( function() {
- make_results_header_sticky();
- });
- }
- }
- ).error(
- function(data, status, header, config) {
- $scope.loadingMessage = "FAILED to load.";
- $scope.windowTitle = "Failed to Load GM Results";
- }
- );
-
-
- //
- // Select/Clear/Toggle all tests.
- //
-
- /**
- * Select all currently showing tests.
- */
- $scope.selectAllImagePairs = function() {
- var numImagePairsShowing = $scope.limitedImagePairs.length;
- for (var i = 0; i < numImagePairsShowing; i++) {
- var index = $scope.limitedImagePairs[i].index;
- if (!$scope.isValueInArray(index, $scope.selectedImagePairs)) {
- $scope.toggleValueInArray(index, $scope.selectedImagePairs);
- }
- }
- }
-
- /**
- * Deselect all currently showing tests.
- */
- $scope.clearAllImagePairs = function() {
- var numImagePairsShowing = $scope.limitedImagePairs.length;
- for (var i = 0; i < numImagePairsShowing; i++) {
- var index = $scope.limitedImagePairs[i].index;
- if ($scope.isValueInArray(index, $scope.selectedImagePairs)) {
- $scope.toggleValueInArray(index, $scope.selectedImagePairs);
- }
- }
- }
-
- /**
- * Toggle selection of all currently showing tests.
- */
- $scope.toggleAllImagePairs = function() {
- var numImagePairsShowing = $scope.limitedImagePairs.length;
- for (var i = 0; i < numImagePairsShowing; i++) {
- var index = $scope.limitedImagePairs[i].index;
- $scope.toggleValueInArray(index, $scope.selectedImagePairs);
- }
- }
-
- /**
- * Toggle selection state of a subset of the currently showing tests.
- *
- * @param startIndex index within $scope.limitedImagePairs of the first
- * test to toggle selection state of
- * @param num number of tests (in a contiguous block) to toggle
- */
- $scope.toggleSomeImagePairs = function(startIndex, num) {
- var numImagePairsShowing = $scope.limitedImagePairs.length;
- for (var i = startIndex; i < startIndex + num; i++) {
- var index = $scope.limitedImagePairs[i].index;
- $scope.toggleValueInArray(index, $scope.selectedImagePairs);
- }
- }
-
-
- //
- // Tab operations.
- //
-
- /**
- * Change the selected tab.
- *
- * @param tab (string): name of the tab to select
- */
- $scope.setViewingTab = function(tab) {
- $scope.viewingTab = tab;
- $scope.updateResults();
- }
-
- /**
- * Move the imagePairs in $scope.selectedImagePairs to a different tab,
- * and then clear $scope.selectedImagePairs.
- *
- * @param newTab (string): name of the tab to move the tests to
- */
- $scope.moveSelectedImagePairsToTab = function(newTab) {
- $scope.moveImagePairsToTab($scope.selectedImagePairs, newTab);
- $scope.selectedImagePairs = [];
- $scope.updateResults();
- }
-
- /**
- * Move a subset of $scope.imagePairs to a different tab.
- *
- * @param imagePairIndices (array of ints): indices into $scope.imagePairs
- * indicating which test results to move
- * @param newTab (string): name of the tab to move the tests to
- */
- $scope.moveImagePairsToTab = function(imagePairIndices, newTab) {
- var imagePairIndex;
- var numImagePairs = imagePairIndices.length;
- for (var i = 0; i < numImagePairs; i++) {
- imagePairIndex = imagePairIndices[i];
- $scope.numResultsPerTab[$scope.imagePairs[imagePairIndex].tab]--;
- $scope.imagePairs[imagePairIndex].tab = newTab;
- }
- $scope.numResultsPerTab[newTab] += numImagePairs;
- }
-
-
- //
- // $scope.queryParameters:
- // Transfer parameter values between $scope and the URL query string.
- //
- $scope.queryParameters = {};
-
- // load and save functions for parameters of each type
- // (load a parameter value into $scope from nameValuePairs,
- // save a parameter value from $scope into nameValuePairs)
- $scope.queryParameters.copiers = {
- 'simple': {
- 'load': function(nameValuePairs, name) {
- var value = nameValuePairs[name];
- if (value) {
- $scope[name] = value;
- }
- },
- 'save': function(nameValuePairs, name) {
- nameValuePairs[name] = $scope[name];
- }
- },
-
- 'columnStringMatch': {
- 'load': function(nameValuePairs, name) {
- var value = nameValuePairs[name];
- if (value) {
- $scope.columnStringMatch[name] = value;
- }
- },
- 'save': function(nameValuePairs, name) {
- nameValuePairs[name] = $scope.columnStringMatch[name];
- }
- },
-
- 'showingColumnValuesSet': {
- 'load': function(nameValuePairs, name) {
- var value = nameValuePairs[name];
- if (value) {
- var valueArray = value.split(',');
- $scope.showingColumnValues[name] = {};
- $scope.toggleValuesInSet(valueArray, $scope.showingColumnValues[name]);
- }
- },
- 'save': function(nameValuePairs, name) {
- nameValuePairs[name] = Object.keys($scope.showingColumnValues[name]).join(',');
- }
- },
-
- };
-
- // Loads all parameters into $scope from the URL query string;
- // any which are not found within the URL will keep their current value.
- $scope.queryParameters.load = function() {
- var nameValuePairs = $location.search();
-
- // If urlSchemaVersion is not specified, we assume the current version.
- var urlSchemaVersion = constants.URL_VALUE__SCHEMA_VERSION__CURRENT;
- if (constants.URL_KEY__SCHEMA_VERSION in nameValuePairs) {
- urlSchemaVersion = nameValuePairs[constants.URL_KEY__SCHEMA_VERSION];
- } else if ('hiddenResultTypes' in nameValuePairs) {
- // The combination of:
- // - absence of an explicit urlSchemaVersion, and
- // - presence of the old 'hiddenResultTypes' field
- // tells us that the URL is from the original urlSchemaVersion.
- // See https://codereview.chromium.org/367173002/
- urlSchemaVersion = 0;
- }
- $scope.urlSchemaVersionLoaded = urlSchemaVersion;
-
- if (urlSchemaVersion != constants.URL_VALUE__SCHEMA_VERSION__CURRENT) {
- nameValuePairs = $scope.upconvertUrlNameValuePairs(nameValuePairs, urlSchemaVersion);
- }
- angular.forEach($scope.queryParameters.map,
- function(copier, paramName) {
- copier.load(nameValuePairs, paramName);
- }
- );
- };
-
- // Saves all parameters from $scope into the URL query string.
- $scope.queryParameters.save = function() {
- var nameValuePairs = {};
- nameValuePairs[constants.URL_KEY__SCHEMA_VERSION] = constants.URL_VALUE__SCHEMA_VERSION__CURRENT;
- angular.forEach($scope.queryParameters.map,
- function(copier, paramName) {
- copier.save(nameValuePairs, paramName);
- }
- );
- $location.search(nameValuePairs);
- };
-
- /**
- * Converts URL name/value pairs that were stored by a previous urlSchemaVersion
- * to the currently needed format.
- *
- * @param oldNValuePairs name/value pairs found in the loaded URL
- * @param oldUrlSchemaVersion which version of the schema was used to generate that URL
- *
- * @returns nameValuePairs as needed by the current URL parser
- */
- $scope.upconvertUrlNameValuePairs = function(oldNameValuePairs, oldUrlSchemaVersion) {
- var newNameValuePairs = {};
- angular.forEach(oldNameValuePairs,
- function(value, name) {
- if (oldUrlSchemaVersion < 1) {
- if ('hiddenConfigs' == name) {
- name = 'config';
- var valueSet = {};
- $scope.toggleValuesInSet(value.split(','), valueSet);
- $scope.toggleValuesInSet(
- $scope.allColumnValues[constants.KEY__EXTRACOLUMNS__CONFIG],
- valueSet);
- value = Object.keys(valueSet).join(',');
- } else if ('hiddenResultTypes' == name) {
- name = 'resultType';
- var valueSet = {};
- $scope.toggleValuesInSet(value.split(','), valueSet);
- $scope.toggleValuesInSet(
- $scope.allColumnValues[constants.KEY__EXTRACOLUMNS__RESULT_TYPE],
- valueSet);
- value = Object.keys(valueSet).join(',');
- }
- }
-
- newNameValuePairs[name] = value;
- }
- );
- return newNameValuePairs;
- }
-
-
- //
- // updateResults() and friends.
- //
-
- /**
- * Set $scope.areUpdatesPending (to enable/disable the Update Results
- * button).
- *
- * TODO(epoger): We could reduce the amount of code by just setting the
- * variable directly (from, e.g., a button's ng-click handler). But when
- * I tried that, the HTML elements depending on the variable did not get
- * updated.
- * It turns out that this is due to variable scoping within an ng-repeat
- * element; see http://stackoverflow.com/questions/15388344/behavior-of-assignment-expression-invoked-by-ng-click-within-ng-repeat
- *
- * @param val boolean value to set $scope.areUpdatesPending to
- */
- $scope.setUpdatesPending = function(val) {
- $scope.areUpdatesPending = val;
- }
-
- /**
- * Update the displayed results, based on filters/settings,
- * and call $scope.queryParameters.save() so that the new filter results
- * can be bookmarked.
- */
- $scope.updateResults = function() {
- $scope.renderStartTime = window.performance.now();
- $log.debug("renderStartTime: " + $scope.renderStartTime);
- $scope.displayLimit = $scope.displayLimitPending;
- $scope.mergeIdenticalRows = $scope.mergeIdenticalRowsPending;
-
- // For each USE_FREEFORM_FILTER column, populate showingColumnValues.
- // This is more efficient than applying the freeform filter within the
- // tight loop in removeHiddenImagePairs.
- angular.forEach(
- $scope.filterableColumnNames,
- function(columnName) {
- var columnHeader = $scope.extraColumnHeaders[columnName];
- if (columnHeader[constants.KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER]) {
- var columnStringMatch = $scope.columnStringMatch[columnName];
- var showingColumnValues = {};
- angular.forEach(
- $scope.allColumnValues[columnName],
- function(columnValue) {
- if (-1 != columnValue.indexOf(columnStringMatch)) {
- showingColumnValues[columnValue] = true;
- }
- }
- );
- $scope.showingColumnValues[columnName] = showingColumnValues;
- }
- }
- );
-
- // TODO(epoger): Every time we apply a filter, AngularJS creates
- // another copy of the array. Is there a way we can filter out
- // the imagePairs as they are displayed, rather than storing multiple
- // array copies? (For better performance.)
-
- if ($scope.viewingTab == $scope.defaultTab) {
- var doReverse = !currSortAsc;
-
- $scope.filteredImagePairs =
- $filter("orderBy")(
- $filter("removeHiddenImagePairs")(
- $scope.imagePairs,
- $scope.filterableColumnNames,
- $scope.showingColumnValues,
- $scope.viewingTab
- ),
- [$scope.getSortColumnValue, $scope.getSecondOrderSortValue],
- doReverse);
- $scope.limitedImagePairs = $filter("mergeAndLimit")(
- $scope.filteredImagePairs, $scope.displayLimit, $scope.mergeIdenticalRows);
- } else {
- $scope.filteredImagePairs =
- $filter("orderBy")(
- $filter("filter")(
- $scope.imagePairs,
- {tab: $scope.viewingTab},
- true
- ),
- [$scope.getSortColumnValue, $scope.getSecondOrderSortValue]);
- $scope.limitedImagePairs = $filter("mergeAndLimit")(
- $scope.filteredImagePairs, -1, $scope.mergeIdenticalRows);
- }
- $scope.showThumbnails = $scope.showThumbnailsPending;
- $scope.imageSize = $scope.imageSizePending;
- $scope.setUpdatesPending(false);
- $scope.queryParameters.save();
- }
-
- /**
- * This function is called when the results have been completely rendered
- * after updateResults().
- */
- $scope.resultsUpdatedCallback = function() {
- $scope.renderEndTime = window.performance.now();
- $log.debug("renderEndTime: " + $scope.renderEndTime);
- }
-
- /**
- * Re-sort the displayed results.
- *
- * @param subdict (string): which KEY__IMAGEPAIRS__* subdictionary
- * the sort column key is within, or 'none' if the sort column
- * key is one of KEY__IMAGEPAIRS__*
- * @param key (string): sort by value associated with this key in subdict
- */
- $scope.sortResultsBy = function(subdict, key) {
- // if we are already sorting by this column then toggle between asc/desc
- if ((subdict === $scope.sortColumnSubdict) && ($scope.sortColumnKey === key)) {
- currSortAsc = !currSortAsc;
- } else {
- $scope.sortColumnSubdict = subdict;
- $scope.sortColumnKey = key;
- currSortAsc = true;
- }
- $scope.updateResults();
- }
-
- /**
- * Returns ASC or DESC (from constants) if currently the data
- * is sorted by the provided column.
- *
- * @param colName: name of the column for which we need to get the class.
- */
-
- $scope.sortedByColumnsCls = function (colName) {
- if ($scope.sortColumnKey !== colName) {
- return '';
- }
-
- var result = (currSortAsc) ? constants.ASC : constants.DESC;
- console.log("sort class:", result);
- return result;
- };
-
- /**
- * For a particular ImagePair, return the value of the column we are
- * sorting on (according to $scope.sortColumnSubdict and
- * $scope.sortColumnKey).
- *
- * @param imagePair: imagePair to get a column value out of.
- */
- $scope.getSortColumnValue = function(imagePair) {
- if ($scope.sortColumnSubdict in imagePair) {
- return imagePair[$scope.sortColumnSubdict][$scope.sortColumnKey];
- } else if ($scope.sortColumnKey in imagePair) {
- return imagePair[$scope.sortColumnKey];
- } else {
- return undefined;
- }
- };
-
- /**
- * For a particular ImagePair, return the value we use for the
- * second-order sort (tiebreaker when multiple rows have
- * the same getSortColumnValue()).
- *
- * We join the imageA and imageB urls for this value, so that we merge
- * adjacent rows as much as possible.
- *
- * @param imagePair: imagePair to get a column value out of.
- */
- $scope.getSecondOrderSortValue = function(imagePair) {
- return imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] + "-vs-" +
- imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL];
- };
-
- /**
- * Set $scope.columnStringMatch[name] = value, and update results.
- *
- * @param name
- * @param value
- */
- $scope.setColumnStringMatch = function(name, value) {
- $scope.columnStringMatch[name] = value;
- $scope.updateResults();
- };
-
- /**
- * Update $scope.showingColumnValues[columnName] and $scope.columnStringMatch[columnName]
- * so that ONLY entries with this columnValue are showing, and update the visible results.
- * (We update both of those, so we cover both freeform and checkbox filtered columns.)
- *
- * @param columnName
- * @param columnValue
- */
- $scope.showOnlyColumnValue = function(columnName, columnValue) {
- $scope.columnStringMatch[columnName] = columnValue;
- $scope.showingColumnValues[columnName] = {};
- $scope.toggleValueInSet(columnValue, $scope.showingColumnValues[columnName]);
- $scope.updateResults();
- };
-
- /**
- * Update $scope.showingColumnValues[columnName] and $scope.columnStringMatch[columnName]
- * so that ALL entries are showing, and update the visible results.
- * (We update both of those, so we cover both freeform and checkbox filtered columns.)
- *
- * @param columnName
- */
- $scope.showAllColumnValues = function(columnName) {
- $scope.columnStringMatch[columnName] = "";
- $scope.showingColumnValues[columnName] = {};
- $scope.toggleValuesInSet($scope.allColumnValues[columnName],
- $scope.showingColumnValues[columnName]);
- $scope.updateResults();
- };
-
-
- //
- // Operations for sending info back to the server.
- //
-
- /**
- * Tell the server that the actual results of these particular tests
- * are acceptable.
- *
- * This assumes that the original expectations are in imageSetA, and the
- * new expectations are in imageSetB. That's fine, because the server
- * mandates that anyway (it will swap the sets if the user requests them
- * in the opposite order).
- *
- * @param imagePairsSubset an array of test results, most likely a subset of
- * $scope.imagePairs (perhaps with some modifications)
- */
- $scope.submitApprovals = function(imagePairsSubset) {
- $scope.submitPending = true;
- $scope.diffResults = "";
-
- // Convert bug text field to null or 1-item array.
- var bugs = null;
- var bugNumber = parseInt($scope.submitAdvancedSettings['bug']);
- if (!isNaN(bugNumber)) {
- bugs = [bugNumber];
- }
-
- var updatedExpectations = [];
- for (var i = 0; i < imagePairsSubset.length; i++) {
- var imagePair = imagePairsSubset[i];
- var updatedExpectation = {};
- updatedExpectation[constants.KEY__IMAGEPAIRS__EXPECTATIONS] =
- imagePair[constants.KEY__IMAGEPAIRS__EXPECTATIONS];
- updatedExpectation[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS] =
- imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS];
- updatedExpectation[constants.KEY__IMAGEPAIRS__SOURCE_JSON_FILE] =
- imagePair[constants.KEY__IMAGEPAIRS__SOURCE_JSON_FILE];
- // IMAGE_B_URL contains the actual image (which is now the expectation)
- updatedExpectation[constants.KEY__IMAGEPAIRS__IMAGE_B_URL] =
- imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL];
-
- // Advanced settings...
- if (null == updatedExpectation[constants.KEY__IMAGEPAIRS__EXPECTATIONS]) {
- updatedExpectation[constants.KEY__IMAGEPAIRS__EXPECTATIONS] = {};
- }
- updatedExpectation[constants.KEY__IMAGEPAIRS__EXPECTATIONS]
- [constants.KEY__EXPECTATIONS__REVIEWED] =
- $scope.submitAdvancedSettings[
- constants.KEY__EXPECTATIONS__REVIEWED];
- if (true == $scope.submitAdvancedSettings[
- constants.KEY__EXPECTATIONS__IGNOREFAILURE]) {
- // if it's false, don't send it at all (just keep the default)
- updatedExpectation[constants.KEY__IMAGEPAIRS__EXPECTATIONS]
- [constants.KEY__EXPECTATIONS__IGNOREFAILURE] = true;
- }
- updatedExpectation[constants.KEY__IMAGEPAIRS__EXPECTATIONS]
- [constants.KEY__EXPECTATIONS__BUGS] = bugs;
-
- updatedExpectations.push(updatedExpectation);
- }
- var modificationData = {};
- modificationData[constants.KEY__LIVE_EDITS__MODIFICATIONS] =
- updatedExpectations;
- modificationData[constants.KEY__LIVE_EDITS__SET_A_DESCRIPTIONS] =
- $scope.header[constants.KEY__HEADER__SET_A_DESCRIPTIONS];
- modificationData[constants.KEY__LIVE_EDITS__SET_B_DESCRIPTIONS] =
- $scope.header[constants.KEY__HEADER__SET_B_DESCRIPTIONS];
- $http({
- method: "POST",
- url: "/live-edits",
- data: modificationData
- }).success(function(data, status, headers, config) {
- $scope.diffResults = data;
- var blob = new Blob([$scope.diffResults], {type: 'text/plain'});
- $scope.diffResultsBlobUrl = window.URL.createObjectURL(blob);
- $scope.submitPending = false;
- }).error(function(data, status, headers, config) {
- alert("There was an error submitting your baselines.\n\n" +
- "Please see server-side log for details.");
- $scope.submitPending = false;
- });
- };
-
-
- //
- // Operations we use to mimic Set semantics, in such a way that
- // checking for presence within the Set is as fast as possible.
- // But getting a list of all values within the Set is not necessarily
- // possible.
- // TODO(epoger): move into a separate .js file?
- //
-
- /**
- * Returns the number of values present within set "set".
- *
- * @param set an Object which we use to mimic set semantics
- */
- $scope.setSize = function(set) {
- return Object.keys(set).length;
- };
-
- /**
- * Returns true if value "value" is present within set "set".
- *
- * @param value a value of any type
- * @param set an Object which we use to mimic set semantics
- * (this should make isValueInSet faster than if we used an Array)
- */
- $scope.isValueInSet = function(value, set) {
- return (true == set[value]);
- };
-
- /**
- * If value "value" is already in set "set", remove it; otherwise, add it.
- *
- * @param value a value of any type
- * @param set an Object which we use to mimic set semantics
- */
- $scope.toggleValueInSet = function(value, set) {
- if (true == set[value]) {
- delete set[value];
- } else {
- set[value] = true;
- }
- };
-
- /**
- * For each value in valueArray, call toggleValueInSet(value, set).
- *
- * @param valueArray
- * @param set
- */
- $scope.toggleValuesInSet = function(valueArray, set) {
- var arrayLength = valueArray.length;
- for (var i = 0; i < arrayLength; i++) {
- $scope.toggleValueInSet(valueArray[i], set);
- }
- };
-
-
- //
- // Array operations; similar to our Set operations, but operate on a
- // Javascript Array so we *can* easily get a list of all values in the Set.
- // TODO(epoger): move into a separate .js file?
- //
-
- /**
- * Returns true if value "value" is present within array "array".
- *
- * @param value a value of any type
- * @param array a Javascript Array
- */
- $scope.isValueInArray = function(value, array) {
- return (-1 != array.indexOf(value));
- };
-
- /**
- * If value "value" is already in array "array", remove it; otherwise,
- * add it.
- *
- * @param value a value of any type
- * @param array a Javascript Array
- */
- $scope.toggleValueInArray = function(value, array) {
- var i = array.indexOf(value);
- if (-1 == i) {
- array.push(value);
- } else {
- array.splice(i, 1);
- }
- };
-
-
- //
- // Miscellaneous utility functions.
- // TODO(epoger): move into a separate .js file?
- //
-
- /**
- * Returns a single "column slice" of a 2D array.
- *
- * For example, if array is:
- * [[A0, A1],
- * [B0, B1],
- * [C0, C1]]
- * and index is 0, this this will return:
- * [A0, B0, C0]
- *
- * @param array a Javascript Array
- * @param column (numeric): index within each row array
- */
- $scope.columnSliceOf2DArray = function(array, column) {
- var slice = [];
- var numRows = array.length;
- for (var row = 0; row < numRows; row++) {
- slice.push(array[row][column]);
- }
- return slice;
- };
-
- /**
- * Returns a human-readable (in local time zone) time string for a
- * particular moment in time.
- *
- * @param secondsPastEpoch (numeric): seconds past epoch in UTC
- */
- $scope.localTimeString = function(secondsPastEpoch) {
- var d = new Date(secondsPastEpoch * 1000);
- return d.toString();
- };
-
- /**
- * Returns a hex color string (such as "#aabbcc") for the given RGB values.
- *
- * @param r (numeric): red channel value, 0-255
- * @param g (numeric): green channel value, 0-255
- * @param b (numeric): blue channel value, 0-255
- */
- $scope.hexColorString = function(r, g, b) {
- var rString = r.toString(16);
- if (r < 16) {
- rString = "0" + rString;
- }
- var gString = g.toString(16);
- if (g < 16) {
- gString = "0" + gString;
- }
- var bString = b.toString(16);
- if (b < 16) {
- bString = "0" + bString;
- }
- return '#' + rString + gString + bString;
- };
-
- /**
- * Returns a hex color string (such as "#aabbcc") for the given brightness.
- *
- * @param brightnessString (string): 0-255, 0 is completely black
- *
- * TODO(epoger): It might be nice to tint the color when it's not completely
- * black or completely white.
- */
- $scope.brightnessStringToHexColor = function(brightnessString) {
- var v = parseInt(brightnessString);
- return $scope.hexColorString(v, v, v);
- };
- }
-);
diff --git a/gm/rebaseline_server/static/live-view.html b/gm/rebaseline_server/static/live-view.html
deleted file mode 100644
index 1662adf89c..0000000000
--- a/gm/rebaseline_server/static/live-view.html
+++ /dev/null
@@ -1,446 +0,0 @@
-<!DOCTYPE html>
-
-<html ng-app="Loader" ng-controller="Loader.Controller">
-
-<head>
- <title ng-bind="windowTitle"></title>
- <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
- <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.js"></script>
- <script src="constants.js"></script>
- <script src="live-loader.js"></script>
- <script src="utils.js"></script>
-
- <link rel="stylesheet" href="view.css">
-</head>
-
-<body>
- <h2>
- Instructions, roadmap, etc. are at
- <a href="http://tinyurl.com/SkiaRebaselineServer">
- http://tinyurl.com/SkiaRebaselineServer
- </a>
- </h2>
-
- <em ng-show="!readyToDisplay">
- Loading results of query:
- <ul>
- <li>setA: "{{setASection}}" within {{setADir}}</li>
- <li>setB: "{{setBSection}}" within {{setBDir}}</li>
- </ul>
- <br>
- {{loadingMessage}}
- </em>
-
- <div ng-show="readyToDisplay">
-
- <div class="warning-div"
- ng-show="urlSchemaVersionLoaded != constants.URL_VALUE__SCHEMA_VERSION__CURRENT">
- WARNING! The URL you loaded used schema version {{urlSchemaVersionLoaded}}, rather than
- the most recent version {{constants.URL_VALUE__SCHEMA_VERSION__CURRENT}}. It has been
- converted to the most recent version on a best-effort basis; you may wish to double-check
- which records are displayed.
- </div>
-
- <div ng-show="header[constants.KEY__HEADER__TIME_UPDATED]">
- setA: "{{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__SECTION]}}"
- within {{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__DIR]}}
- <span ng-show="header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]">at <a href="https://skia.googlesource.com/skia/+/{{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]}}">rev {{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]}}</a></span>
- <br>
- setB: "{{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__SECTION]}}"
- within {{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__DIR]}}
- <span ng-show="header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]">at <a href="https://skia.googlesource.com/skia/+/{{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]}}">rev {{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]}}</a></span>
- <br>
- <a href="{{liveQueryUrl}}">latest raw JSON diffs between these two sets</a><br>
- These results current as of
- {{localTimeString(header[constants.KEY__HEADER__TIME_UPDATED])}}
- </div>
-
- <div class="tab-wrapper"><!-- tabs -->
- <div class="tab-spacer" ng-repeat="tab in tabs">
- <div class="tab tab-{{tab == viewingTab}}"
- ng-click="setViewingTab(tab)">
- &nbsp;{{tab}} ({{numResultsPerTab[tab]}})&nbsp;
- </div>
- <div class="tab-spacer">
- &nbsp;
- </div>
- </div>
- </div><!-- tabs -->
-
- <div class="tab-main"><!-- main display area of selected tab -->
-
- <br>
- <!-- We only show the filters/settings table on the Unfiled tab. -->
- <table ng-show="viewingTab == defaultTab" border="1">
- <tr>
- <th colspan="4">
- Filters
- </th>
- <th>
- Settings
- </th>
- </tr>
- <tr valign="top">
-
- <!-- filters -->
- <td ng-repeat="columnName in orderedColumnNames">
-
- <!-- Only display filterable columns here... -->
- <div ng-if="extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__IS_FILTERABLE]">
- {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}}<br>
-
- <!-- If we filter this column using free-form text match... -->
- <div ng-if="extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER]">
- <input type="text"
- ng-model="columnStringMatch[columnName]"
- ng-change="setUpdatesPending(true)"/>
- <br>
- <button ng-click="setColumnStringMatch(columnName, '')"
- ng-disabled="('' == columnStringMatch[columnName])">
- clear (show all)
- </button>
- </div>
-
- <!-- If we filter this column using checkboxes... -->
- <div ng-if="!extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER]">
- <label ng-repeat="valueAndCount in extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS]">
- <input type="checkbox"
- name="resultTypes"
- value="{{valueAndCount[0]}}"
- ng-checked="isValueInSet(valueAndCount[0], showingColumnValues[columnName])"
- ng-click="toggleValueInSet(valueAndCount[0], showingColumnValues[columnName]); setUpdatesPending(true)">
- {{valueAndCount[0]}} ({{valueAndCount[1]}})<br>
- </label>
- <button ng-click="showingColumnValues[columnName] = {}; toggleValuesInSet(allColumnValues[columnName], showingColumnValues[columnName]); updateResults()"
- ng-disabled="!readyToDisplay || allColumnValues[columnName].length == setSize(showingColumnValues[columnName])">
- all
- </button>
- <button ng-click="showingColumnValues[columnName] = {}; updateResults()"
- ng-disabled="!readyToDisplay || 0 == setSize(showingColumnValues[columnName])">
- none
- </button>
- <button ng-click="toggleValuesInSet(allColumnValues[columnName], showingColumnValues[columnName]); updateResults()">
- toggle
- </button>
- </div>
-
- </div>
- </td>
-
- <!-- settings -->
- <td><table>
- <tr><td>
- <input type="checkbox" ng-model="showThumbnailsPending"
- ng-init="showThumbnailsPending = true"
- ng-change="areUpdatesPending = true"/>
- Show thumbnails
- </td></tr>
- <tr><td>
- <input type="checkbox" ng-model="mergeIdenticalRowsPending"
- ng-init="mergeIdenticalRowsPending = true"
- ng-change="areUpdatesPending = true"/>
- Merge identical rows
- </td></tr>
- <tr><td>
- Image width
- <input type="text" ng-model="imageSizePending"
- ng-init="imageSizePending=100"
- ng-change="areUpdatesPending = true"
- maxlength="4"/>
- </td></tr>
- <tr><td>
- Max records to display
- <input type="text" ng-model="displayLimitPending"
- ng-init="displayLimitPending=50"
- ng-change="areUpdatesPending = true"
- maxlength="4"/>
- </td></tr>
- <tr><td>
- <button class="update-results-button"
- ng-click="updateResults()"
- ng-disabled="!areUpdatesPending">
- Update Results
- </button>
- </td></tr>
- </tr></table></td>
- </tr>
- </table>
-
- <p>
-
- <!-- Submission UI that we only show in the Pending Approval tab. -->
- <div ng-show="'Pending Approval' == viewingTab">
- <div style="display:inline-block">
- <button style="font-size:20px"
- ng-click="submitApprovals(filteredImagePairs)"
- ng-disabled="submitPending || (filteredImagePairs.length == 0)">
- Get a patchfile to update these {{filteredImagePairs.length}} expectations
- </button>
- </div>
- <div style="display:inline-block">
- <div style="font-size:20px"
- ng-show="submitPending">
- Submitting, please wait...
- </div>
- </div>
- <div>
- Advanced settings...
- <input type="checkbox" ng-model="showSubmitAdvancedSettings">
- show
- <ul ng-show="showSubmitAdvancedSettings">
- <li ng-repeat="setting in [constants.KEY__EXPECTATIONS__REVIEWED, constants.KEY__EXPECTATIONS__IGNOREFAILURE]">
- {{setting}}
- <input type="checkbox" ng-model="submitAdvancedSettings[setting]">
- </li>
- <li ng-repeat="setting in ['bug']">
- {{setting}}
- <input type="text" ng-model="submitAdvancedSettings[setting]">
- </li>
- </ul>
- </div>
- <div ng-show="diffResults">
- <p>
- Here is the patch to apply to your local checkout:
- <br>
- <textarea rows="8" cols="50">{{diffResults}}</textarea>
- <br>
- <a download="patch.txt" ng-href="{{diffResultsBlobUrl}}">
- Click here to download that patch as a text file.
- </a>
- </div>
- </div>
-
- <p>
-
- <table border="0"><tr><td> <!-- table holding results header + results table -->
- <table border="0" width="100%"> <!-- results header -->
- <tr>
- <td>
- Found {{filteredImagePairs.length}} matches;
- <span ng-show="filteredImagePairs.length > limitedImagePairs.length">
- displaying the first {{limitedImagePairs.length}}.
- </span>
- <span ng-show="filteredImagePairs.length <= limitedImagePairs.length">
- displaying them all.
- </span>
- <span ng-show="renderEndTime > renderStartTime">
- Rendered in {{(renderEndTime - renderStartTime).toFixed(0)}} ms.
- </span>
- <br>
- (click on the column header radio buttons to re-sort by that column)
- </td>
- <td align="right">
- <div>
- all tests shown:
- <button ng-click="selectAllImagePairs()">
- select
- </button>
- <button ng-click="clearAllImagePairs()">
- clear
- </button>
- <button ng-click="toggleAllImagePairs()">
- toggle
- </button>
- </div>
- <div ng-repeat="otherTab in tabs">
- <button ng-click="moveSelectedImagePairsToTab(otherTab)"
- ng-disabled="selectedImagePairs.length == 0"
- ng-show="otherTab != viewingTab">
- move {{selectedImagePairs.length}} selected tests to {{otherTab}} tab
- </button>
- </div>
- </td>
- </tr>
- </table> <!-- results header -->
- </td></tr><tr><td>
- <table border="1" ng-app="diff_viewer"> <!-- results -->
- <tr>
- <!-- Most column headers are displayed in a common fashion... -->
- <th ng-repeat="columnName in orderedColumnNames">
- <a ng-class="'sort-' + sortedByColumnsCls(columnName)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXTRACOLUMNS, columnName)"
- href=""
- class="sortable-header">
- {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}}
- </a>
- </th>
- <!-- ... but there are a few columns where we display things differently. -->
- <th>
- <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__EXPECTATIONS__BUGS)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXPECTATIONS, constants.KEY__EXPECTATIONS__BUGS)"
- href=""
- class="sortable-header">
- bugs
- </a>
- </th>
- <th width="{{imageSize}}">
- <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__IMAGEPAIRS__IMAGE_A_URL)"
- ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_A_URL)"
- href=""
- title="setA: '{{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__SECTION]}}' within {{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__DIR]}}"
- class="sortable-header">
- <span ng-show="'Pending Approval' != viewingTab">
- {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
- </span>
- <span ng-show="'Pending Approval' == viewingTab">
- old expectations
- </span>
- </a>
- </th>
- <th width="{{imageSize}}">
- <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__IMAGEPAIRS__IMAGE_B_URL)"
- ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_B_URL)"
- href=""
- title="setB: '{{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__SECTION]}}' within {{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__DIR]}}"
- class="sortable-header">
- <span ng-show="'Pending Approval' != viewingTab">
- {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
- </span>
- <span ng-show="'Pending Approval' == viewingTab">
- new expectations
- </span>
- </a>
- </th>
- <th width="{{imageSize}}">
- <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)"
- href=""
- class="sortable-header">
- differing pixels in white
- </a>
- </th>
- <th width="{{imageSize}}">
- <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)"
- href=""
- class="sortable-header">
- perceptual difference
- </a>
- <br>
- <input type="range" ng-model="pixelDiffBgColorBrightness"
- ng-init="pixelDiffBgColorBrightness=64; pixelDiffBgColor=brightnessStringToHexColor(pixelDiffBgColorBrightness)"
- ng-change="pixelDiffBgColor=brightnessStringToHexColor(pixelDiffBgColorBrightness)"
- title="image background brightness"
- min="0" max="255"/>
- </th>
- <th>
- <!-- imagepair-selection checkbox column -->
- </th>
- </tr>
-
- <tr ng-repeat="imagePair in limitedImagePairs" valign="top"
- ng-class-odd="'results-odd'" ng-class-even="'results-even'"
- results-updated-callback-directive>
-
- <td ng-repeat="columnName in orderedColumnNames">
- {{imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS][columnName]}}
- <br>
- <button class="show-only-button"
- ng-show="viewingTab == defaultTab"
- ng-disabled="1 == setSize(showingColumnValues[columnName])"
- ng-click="showOnlyColumnValue(columnName, imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS][columnName])"
- title="show only results of {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}} {{imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS][columnName]}}">
- show only
- </button>
- <br>
- <button class="show-all-button"
- ng-show="viewingTab == defaultTab"
- ng-disabled="allColumnValues[columnName].length == setSize(showingColumnValues[columnName])"
- ng-click="showAllColumnValues(columnName)"
- title="show results of all {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}}s">
- show all
- </button>
- </td>
-
- <!-- bugs -->
- <td>
- <a ng-repeat="bug in imagePair[constants.KEY__IMAGEPAIRS__EXPECTATIONS][constants.KEY__EXPECTATIONS__BUGS]"
- href="https://code.google.com/p/skia/issues/detail?id={{bug}}"
- target="_blank">
- {{bug}}
- </a>
- </td>
-
- <!-- image A -->
- <td width="{{imageSize}}" ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}">
- <div ng-if="imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] != null">
- <a href="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL]}}" target="_blank">View Image</a><br/>
- <img ng-if="showThumbnails"
- width="{{imageSize}}"
- ng-src="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL]}}" />
- </div>
- <div ng-show="imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] == null"
- style="text-align:center">
- &ndash;none&ndash;
- </div>
- </td>
-
- <!-- image B -->
- <td width="{{imageSize}}" ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}">
- <div ng-if="imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL] != null">
- <a href="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]}}" target="_blank">View Image</a><br/>
- <img ng-if="showThumbnails"
- width="{{imageSize}}"
- ng-src="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]}}" />
- </div>
- <div ng-show="imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL] == null"
- style="text-align:center">
- &ndash;none&ndash;
- </div>
- </td>
-
- <!-- whitediffs: every differing pixel shown in white -->
- <td width="{{imageSize}}" ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}">
- <div ng-if="imagePair[constants.KEY__IMAGEPAIRS__IS_DIFFERENT]"
- title="{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__NUM_DIFF_PIXELS] | number:0}} of {{(100 * imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__NUM_DIFF_PIXELS] / imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS]) | number:0}} pixels ({{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS].toFixed(4)}}%) differ from expectation.">
-
- <a href="{{imageSets[constants.KEY__IMAGESETS__SET__WHITEDIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__WHITE_DIFF_URL]}}" target="_blank">View Image</a><br/>
- <img ng-if="showThumbnails"
- width="{{imageSize}}"
- ng-src="{{imageSets[constants.KEY__IMAGESETS__SET__WHITEDIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__WHITE_DIFF_URL]}}" />
- <br/>
- {{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS].toFixed(4)}}%
- ({{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__NUM_DIFF_PIXELS]}})
- </div>
- <div ng-show="!imagePair[constants.KEY__IMAGEPAIRS__IS_DIFFERENT]"
- style="text-align:center">
- &ndash;none&ndash;
- </div>
- </td>
-
- <!-- diffs: per-channel RGB deltas -->
- <td width="{{imageSize}}" ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}">
- <div ng-if="imagePair[constants.KEY__IMAGEPAIRS__IS_DIFFERENT]"
- title="Perceptual difference measure is {{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF].toFixed(4)}}%. Maximum difference per channel: R={{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL][0]}}, G={{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL][1]}}, B={{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL][2]}}">
-
- <a href="{{imageSets[constants.KEY__IMAGESETS__SET__DIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__DIFF_URL]}}" target="_blank">View Image</a><br/>
- <img ng-if="showThumbnails"
- ng-style="{backgroundColor: pixelDiffBgColor}"
- width="{{imageSize}}"
- ng-src="{{imageSets[constants.KEY__IMAGESETS__SET__DIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__DIFF_URL]}}" />
- <br/>
- {{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF].toFixed(4)}}%
- {{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL]}}
- </div>
- <div ng-show="!imagePair[constants.KEY__IMAGEPAIRS__IS_DIFFERENT]"
- style="text-align:center">
- &ndash;none&ndash;
- </div>
- </td>
-
- <td ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}">
- <br/>
- <input type="checkbox"
- name="rowSelect"
- value="{{imagePair.index}}"
- ng-checked="isValueInArray(imagePair.index, selectedImagePairs)"
- ng-click="toggleSomeImagePairs($index, imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN])">
- </tr>
- </table> <!-- imagePairs -->
- </td></tr></table> <!-- table holding results header + imagePairs table -->
-
- </div><!-- main display area of selected tab -->
- </div><!-- everything: hide until readyToDisplay -->
-
-</body>
-</html>
diff --git a/gm/rebaseline_server/static/loader.js b/gm/rebaseline_server/static/loader.js
deleted file mode 100644
index bfc639e33b..0000000000
--- a/gm/rebaseline_server/static/loader.js
+++ /dev/null
@@ -1,1035 +0,0 @@
-/*
- * Loader:
- * Reads GM result reports written out by results.py, and imports
- * them into $scope.extraColumnHeaders and $scope.imagePairs .
- */
-var Loader = angular.module(
- 'Loader',
- ['ConstantsModule']
-);
-
-Loader.directive(
- 'resultsUpdatedCallbackDirective',
- ['$timeout',
- function($timeout) {
- return function(scope, element, attrs) {
- if (scope.$last) {
- $timeout(function() {
- scope.resultsUpdatedCallback();
- });
- }
- };
- }
- ]
-);
-
-// TODO(epoger): Combine ALL of our filtering operations (including
-// truncation) into this one filter, so that runs most efficiently?
-// (We would have to make sure truncation still took place after
-// sorting, though.)
-Loader.filter(
- 'removeHiddenImagePairs',
- function(constants) {
- return function(unfilteredImagePairs, filterableColumnNames, showingColumnValues,
- viewingTab) {
- var filteredImagePairs = [];
- for (var i = 0; i < unfilteredImagePairs.length; i++) {
- var imagePair = unfilteredImagePairs[i];
- var extraColumnValues = imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS];
- var allColumnValuesAreVisible = true;
- // Loop over all columns, and if any of them contain values not found in
- // showingColumnValues[columnName], don't include this imagePair.
- //
- // We use this same filtering mechanism regardless of whether each column
- // has USE_FREEFORM_FILTER set or not; if that flag is set, then we will
- // have already used the freeform text entry block to populate
- // showingColumnValues[columnName].
- for (var j = 0; j < filterableColumnNames.length; j++) {
- var columnName = filterableColumnNames[j];
- var columnValue = extraColumnValues[columnName];
- if (!showingColumnValues[columnName][columnValue]) {
- allColumnValuesAreVisible = false;
- break;
- }
- }
- if (allColumnValuesAreVisible && (viewingTab == imagePair.tab)) {
- filteredImagePairs.push(imagePair);
- }
- }
- return filteredImagePairs;
- };
- }
-);
-
-/**
- * Limit the input imagePairs to some max number, and merge identical rows
- * (adjacent rows which have the same (imageA, imageB) pair).
- *
- * @param unfilteredImagePairs imagePairs to filter
- * @param maxPairs maximum number of pairs to output, or <0 for no limit
- * @param mergeIdenticalRows if true, merge identical rows by setting
- * ROWSPAN>1 on the first merged row, and ROWSPAN=0 for the rest
- */
-Loader.filter(
- 'mergeAndLimit',
- function(constants) {
- return function(unfilteredImagePairs, maxPairs, mergeIdenticalRows) {
- var numPairs = unfilteredImagePairs.length;
- if ((maxPairs > 0) && (maxPairs < numPairs)) {
- numPairs = maxPairs;
- }
- var filteredImagePairs = [];
- if (!mergeIdenticalRows || (numPairs == 1)) {
- // Take a shortcut if we're not merging identical rows.
- // We still need to set ROWSPAN to 1 for each row, for the HTML viewer.
- for (var i = numPairs-1; i >= 0; i--) {
- var imagePair = unfilteredImagePairs[i];
- imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] = 1;
- filteredImagePairs[i] = imagePair;
- }
- } else if (numPairs > 1) {
- // General case--there are at least 2 rows, so we may need to merge some.
- // Work from the bottom up, so we can keep a running total of how many
- // rows should be merged, and set ROWSPAN of the top row accordingly.
- var imagePair = unfilteredImagePairs[numPairs-1];
- var nextRowImageAUrl = imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL];
- var nextRowImageBUrl = imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL];
- imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] = 1;
- filteredImagePairs[numPairs-1] = imagePair;
- for (var i = numPairs-2; i >= 0; i--) {
- imagePair = unfilteredImagePairs[i];
- var thisRowImageAUrl = imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL];
- var thisRowImageBUrl = imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL];
- if ((thisRowImageAUrl == nextRowImageAUrl) &&
- (thisRowImageBUrl == nextRowImageBUrl)) {
- imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] =
- filteredImagePairs[i+1][constants.KEY__IMAGEPAIRS__ROWSPAN] + 1;
- filteredImagePairs[i+1][constants.KEY__IMAGEPAIRS__ROWSPAN] = 0;
- } else {
- imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] = 1;
- nextRowImageAUrl = thisRowImageAUrl;
- nextRowImageBUrl = thisRowImageBUrl;
- }
- filteredImagePairs[i] = imagePair;
- }
- } else {
- // No results.
- }
- return filteredImagePairs;
- };
- }
-);
-
-
-Loader.controller(
- 'Loader.Controller',
- function($scope, $http, $filter, $location, $log, $timeout, constants) {
- $scope.readyToDisplay = false;
- $scope.constants = constants;
- $scope.windowTitle = "Loading GM Results...";
- $scope.resultsToLoad = $location.search().resultsToLoad;
- $scope.loadingMessage = "please wait...";
-
- var currSortAsc = true;
-
-
- /**
- * On initial page load, load a full dictionary of results.
- * Once the dictionary is loaded, unhide the page elements so they can
- * render the data.
- */
- $http.get($scope.resultsToLoad).success(
- function(data, status, header, config) {
- var dataHeader = data[constants.KEY__ROOT__HEADER];
- if (dataHeader[constants.KEY__HEADER__SCHEMA_VERSION] !=
- constants.VALUE__HEADER__SCHEMA_VERSION) {
- $scope.loadingMessage = "ERROR: Got JSON file with schema version "
- + dataHeader[constants.KEY__HEADER__SCHEMA_VERSION]
- + " but expected schema version "
- + constants.VALUE__HEADER__SCHEMA_VERSION;
- } else if (dataHeader[constants.KEY__HEADER__IS_STILL_LOADING]) {
- // Apply the server's requested reload delay to local time,
- // so we will wait the right number of seconds regardless of clock
- // skew between client and server.
- var reloadDelayInSeconds =
- dataHeader[constants.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE] -
- dataHeader[constants.KEY__HEADER__TIME_UPDATED];
- var timeNow = new Date().getTime();
- var timeToReload = timeNow + reloadDelayInSeconds * 1000;
- $scope.loadingMessage =
- "server is still loading results; will retry at " +
- $scope.localTimeString(timeToReload / 1000);
- $timeout(
- function(){location.reload();},
- timeToReload - timeNow);
- } else {
- $scope.loadingMessage = "processing data, please wait...";
-
- $scope.header = dataHeader;
- $scope.extraColumnHeaders = data[constants.KEY__ROOT__EXTRACOLUMNHEADERS];
- $scope.orderedColumnNames = data[constants.KEY__ROOT__EXTRACOLUMNORDER];
- $scope.imagePairs = data[constants.KEY__ROOT__IMAGEPAIRS];
- $scope.imageSets = data[constants.KEY__ROOT__IMAGESETS];
-
- // set the default sort column and make it ascending.
- $scope.sortColumnSubdict = constants.KEY__IMAGEPAIRS__DIFFERENCES;
- $scope.sortColumnKey = constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF;
- currSortAsc = true;
-
- $scope.showSubmitAdvancedSettings = false;
- $scope.submitAdvancedSettings = {};
- $scope.submitAdvancedSettings[
- constants.KEY__EXPECTATIONS__REVIEWED] = true;
- $scope.submitAdvancedSettings[
- constants.KEY__EXPECTATIONS__IGNOREFAILURE] = false;
- $scope.submitAdvancedSettings['bug'] = '';
-
- // Create the list of tabs (lists into which the user can file each
- // test). This may vary, depending on isEditable.
- $scope.tabs = [
- 'Unfiled', 'Hidden'
- ];
- if (dataHeader[constants.KEY__HEADER__IS_EDITABLE]) {
- $scope.tabs = $scope.tabs.concat(
- ['Pending Approval']);
- }
- $scope.defaultTab = $scope.tabs[0];
- $scope.viewingTab = $scope.defaultTab;
-
- // Track the number of results on each tab.
- $scope.numResultsPerTab = {};
- for (var i = 0; i < $scope.tabs.length; i++) {
- $scope.numResultsPerTab[$scope.tabs[i]] = 0;
- }
- $scope.numResultsPerTab[$scope.defaultTab] = $scope.imagePairs.length;
-
- // Add index and tab fields to all records.
- for (var i = 0; i < $scope.imagePairs.length; i++) {
- $scope.imagePairs[i].index = i;
- $scope.imagePairs[i].tab = $scope.defaultTab;
- }
-
- // Arrays within which the user can toggle individual elements.
- $scope.selectedImagePairs = [];
-
- // Set up filters.
- //
- // filterableColumnNames is a list of all column names we can filter on.
- // allColumnValues[columnName] is a list of all known values
- // for a given column.
- // showingColumnValues[columnName] is a set indicating which values
- // in a given column would cause us to show a row, rather than hiding it.
- //
- // columnStringMatch[columnName] is a string used as a pattern to generate
- // showingColumnValues[columnName] for columns we filter using free-form text.
- // It is ignored for any columns with USE_FREEFORM_FILTER == false.
- $scope.filterableColumnNames = [];
- $scope.allColumnValues = {};
- $scope.showingColumnValues = {};
- $scope.columnStringMatch = {};
-
- angular.forEach(
- Object.keys($scope.extraColumnHeaders),
- function(columnName) {
- var columnHeader = $scope.extraColumnHeaders[columnName];
- if (columnHeader[constants.KEY__EXTRACOLUMNHEADERS__IS_FILTERABLE]) {
- $scope.filterableColumnNames.push(columnName);
- $scope.allColumnValues[columnName] = $scope.columnSliceOf2DArray(
- columnHeader[constants.KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS], 0);
- $scope.showingColumnValues[columnName] = {};
- $scope.toggleValuesInSet($scope.allColumnValues[columnName],
- $scope.showingColumnValues[columnName]);
- $scope.columnStringMatch[columnName] = "";
- }
- }
- );
-
- // TODO(epoger): Special handling for RESULT_TYPE column:
- // by default, show only KEY__RESULT_TYPE__FAILED results
- $scope.showingColumnValues[constants.KEY__EXTRACOLUMNS__RESULT_TYPE] = {};
- $scope.showingColumnValues[constants.KEY__EXTRACOLUMNS__RESULT_TYPE][
- constants.KEY__RESULT_TYPE__FAILED] = true;
-
- // Set up mapping for URL parameters.
- // parameter name -> copier object to load/save parameter value
- $scope.queryParameters.map = {
- 'resultsToLoad': $scope.queryParameters.copiers.simple,
- 'displayLimitPending': $scope.queryParameters.copiers.simple,
- 'showThumbnailsPending': $scope.queryParameters.copiers.simple,
- 'mergeIdenticalRowsPending': $scope.queryParameters.copiers.simple,
- 'imageSizePending': $scope.queryParameters.copiers.simple,
- 'sortColumnSubdict': $scope.queryParameters.copiers.simple,
- 'sortColumnKey': $scope.queryParameters.copiers.simple,
- };
- // Some parameters are handled differently based on whether they USE_FREEFORM_FILTER.
- angular.forEach(
- $scope.filterableColumnNames,
- function(columnName) {
- if ($scope.extraColumnHeaders[columnName]
- [constants.KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER]) {
- $scope.queryParameters.map[columnName] =
- $scope.queryParameters.copiers.columnStringMatch;
- } else {
- $scope.queryParameters.map[columnName] =
- $scope.queryParameters.copiers.showingColumnValuesSet;
- }
- }
- );
-
- // If any defaults were overridden in the URL, get them now.
- $scope.queryParameters.load();
-
- // Any image URLs which are relative should be relative to the JSON
- // file's source directory; absolute URLs should be left alone.
- var baseUrlKey = constants.KEY__IMAGESETS__FIELD__BASE_URL;
- angular.forEach(
- $scope.imageSets,
- function(imageSet) {
- var baseUrl = imageSet[baseUrlKey];
- if ((baseUrl.substring(0, 1) != '/') &&
- (baseUrl.indexOf('://') == -1)) {
- imageSet[baseUrlKey] = $scope.resultsToLoad + '/../' + baseUrl;
- }
- }
- );
-
- $scope.readyToDisplay = true;
- $scope.updateResults();
- $scope.loadingMessage = "";
- $scope.windowTitle = "Current GM Results";
-
- $timeout( function() {
- make_results_header_sticky();
- });
- }
- }
- ).error(
- function(data, status, header, config) {
- $scope.loadingMessage = "FAILED to load.";
- $scope.windowTitle = "Failed to Load GM Results";
- }
- );
-
-
- //
- // Select/Clear/Toggle all tests.
- //
-
- /**
- * Select all currently showing tests.
- */
- $scope.selectAllImagePairs = function() {
- var numImagePairsShowing = $scope.limitedImagePairs.length;
- for (var i = 0; i < numImagePairsShowing; i++) {
- var index = $scope.limitedImagePairs[i].index;
- if (!$scope.isValueInArray(index, $scope.selectedImagePairs)) {
- $scope.toggleValueInArray(index, $scope.selectedImagePairs);
- }
- }
- };
-
- /**
- * Deselect all currently showing tests.
- */
- $scope.clearAllImagePairs = function() {
- var numImagePairsShowing = $scope.limitedImagePairs.length;
- for (var i = 0; i < numImagePairsShowing; i++) {
- var index = $scope.limitedImagePairs[i].index;
- if ($scope.isValueInArray(index, $scope.selectedImagePairs)) {
- $scope.toggleValueInArray(index, $scope.selectedImagePairs);
- }
- }
- };
-
- /**
- * Toggle selection of all currently showing tests.
- */
- $scope.toggleAllImagePairs = function() {
- var numImagePairsShowing = $scope.limitedImagePairs.length;
- for (var i = 0; i < numImagePairsShowing; i++) {
- var index = $scope.limitedImagePairs[i].index;
- $scope.toggleValueInArray(index, $scope.selectedImagePairs);
- }
- };
-
- /**
- * Toggle selection state of a subset of the currently showing tests.
- *
- * @param startIndex index within $scope.limitedImagePairs of the first
- * test to toggle selection state of
- * @param num number of tests (in a contiguous block) to toggle
- */
- $scope.toggleSomeImagePairs = function(startIndex, num) {
- var numImagePairsShowing = $scope.limitedImagePairs.length;
- for (var i = startIndex; i < startIndex + num; i++) {
- var index = $scope.limitedImagePairs[i].index;
- $scope.toggleValueInArray(index, $scope.selectedImagePairs);
- }
- };
-
-
- //
- // Tab operations.
- //
-
- /**
- * Change the selected tab.
- *
- * @param tab (string): name of the tab to select
- */
- $scope.setViewingTab = function(tab) {
- $scope.viewingTab = tab;
- $scope.updateResults();
- };
-
- /**
- * Move the imagePairs in $scope.selectedImagePairs to a different tab,
- * and then clear $scope.selectedImagePairs.
- *
- * @param newTab (string): name of the tab to move the tests to
- */
- $scope.moveSelectedImagePairsToTab = function(newTab) {
- $scope.moveImagePairsToTab($scope.selectedImagePairs, newTab);
- $scope.selectedImagePairs = [];
- $scope.updateResults();
- };
-
- /**
- * Move a subset of $scope.imagePairs to a different tab.
- *
- * @param imagePairIndices (array of ints): indices into $scope.imagePairs
- * indicating which test results to move
- * @param newTab (string): name of the tab to move the tests to
- */
- $scope.moveImagePairsToTab = function(imagePairIndices, newTab) {
- var imagePairIndex;
- var numImagePairs = imagePairIndices.length;
- for (var i = 0; i < numImagePairs; i++) {
- imagePairIndex = imagePairIndices[i];
- $scope.numResultsPerTab[$scope.imagePairs[imagePairIndex].tab]--;
- $scope.imagePairs[imagePairIndex].tab = newTab;
- }
- $scope.numResultsPerTab[newTab] += numImagePairs;
- };
-
-
- //
- // $scope.queryParameters:
- // Transfer parameter values between $scope and the URL query string.
- //
- $scope.queryParameters = {};
-
- // load and save functions for parameters of each type
- // (load a parameter value into $scope from nameValuePairs,
- // save a parameter value from $scope into nameValuePairs)
- $scope.queryParameters.copiers = {
- 'simple': {
- 'load': function(nameValuePairs, name) {
- var value = nameValuePairs[name];
- if (value) {
- $scope[name] = value;
- }
- },
- 'save': function(nameValuePairs, name) {
- nameValuePairs[name] = $scope[name];
- }
- },
-
- 'columnStringMatch': {
- 'load': function(nameValuePairs, name) {
- var value = nameValuePairs[name];
- if (value) {
- $scope.columnStringMatch[name] = value;
- }
- },
- 'save': function(nameValuePairs, name) {
- nameValuePairs[name] = $scope.columnStringMatch[name];
- }
- },
-
- 'showingColumnValuesSet': {
- 'load': function(nameValuePairs, name) {
- var value = nameValuePairs[name];
- if (value) {
- var valueArray = value.split(',');
- $scope.showingColumnValues[name] = {};
- $scope.toggleValuesInSet(valueArray, $scope.showingColumnValues[name]);
- }
- },
- 'save': function(nameValuePairs, name) {
- nameValuePairs[name] = Object.keys($scope.showingColumnValues[name]).join(',');
- }
- },
-
- };
-
- // Loads all parameters into $scope from the URL query string;
- // any which are not found within the URL will keep their current value.
- $scope.queryParameters.load = function() {
- var nameValuePairs = $location.search();
-
- // If urlSchemaVersion is not specified, we assume the current version.
- var urlSchemaVersion = constants.URL_VALUE__SCHEMA_VERSION__CURRENT;
- if (constants.URL_KEY__SCHEMA_VERSION in nameValuePairs) {
- urlSchemaVersion = nameValuePairs[constants.URL_KEY__SCHEMA_VERSION];
- } else if ('hiddenResultTypes' in nameValuePairs) {
- // The combination of:
- // - absence of an explicit urlSchemaVersion, and
- // - presence of the old 'hiddenResultTypes' field
- // tells us that the URL is from the original urlSchemaVersion.
- // See https://codereview.chromium.org/367173002/
- urlSchemaVersion = 0;
- }
- $scope.urlSchemaVersionLoaded = urlSchemaVersion;
-
- if (urlSchemaVersion != constants.URL_VALUE__SCHEMA_VERSION__CURRENT) {
- nameValuePairs = $scope.upconvertUrlNameValuePairs(nameValuePairs, urlSchemaVersion);
- }
- angular.forEach($scope.queryParameters.map,
- function(copier, paramName) {
- copier.load(nameValuePairs, paramName);
- }
- );
- };
-
- // Saves all parameters from $scope into the URL query string.
- $scope.queryParameters.save = function() {
- var nameValuePairs = {};
- nameValuePairs[constants.URL_KEY__SCHEMA_VERSION] = constants.URL_VALUE__SCHEMA_VERSION__CURRENT;
- angular.forEach($scope.queryParameters.map,
- function(copier, paramName) {
- copier.save(nameValuePairs, paramName);
- }
- );
- $location.search(nameValuePairs);
- };
-
- /**
- * Converts URL name/value pairs that were stored by a previous urlSchemaVersion
- * to the currently needed format.
- *
- * @param oldNValuePairs name/value pairs found in the loaded URL
- * @param oldUrlSchemaVersion which version of the schema was used to generate that URL
- *
- * @returns nameValuePairs as needed by the current URL parser
- */
- $scope.upconvertUrlNameValuePairs = function(oldNameValuePairs, oldUrlSchemaVersion) {
- var newNameValuePairs = {};
- angular.forEach(oldNameValuePairs,
- function(value, name) {
- if (oldUrlSchemaVersion < 1) {
- if ('hiddenConfigs' == name) {
- name = 'config';
- var valueSet = {};
- $scope.toggleValuesInSet(value.split(','), valueSet);
- $scope.toggleValuesInSet(
- $scope.allColumnValues[constants.KEY__EXTRACOLUMNS__CONFIG],
- valueSet);
- value = Object.keys(valueSet).join(',');
- } else if ('hiddenResultTypes' == name) {
- name = 'resultType';
- var valueSet = {};
- $scope.toggleValuesInSet(value.split(','), valueSet);
- $scope.toggleValuesInSet(
- $scope.allColumnValues[constants.KEY__EXTRACOLUMNS__RESULT_TYPE],
- valueSet);
- value = Object.keys(valueSet).join(',');
- }
- }
-
- newNameValuePairs[name] = value;
- }
- );
- return newNameValuePairs;
- }
-
-
- //
- // updateResults() and friends.
- //
-
- /**
- * Set $scope.areUpdatesPending (to enable/disable the Update Results
- * button).
- *
- * TODO(epoger): We could reduce the amount of code by just setting the
- * variable directly (from, e.g., a button's ng-click handler). But when
- * I tried that, the HTML elements depending on the variable did not get
- * updated.
- * It turns out that this is due to variable scoping within an ng-repeat
- * element; see http://stackoverflow.com/questions/15388344/behavior-of-assignment-expression-invoked-by-ng-click-within-ng-repeat
- *
- * @param val boolean value to set $scope.areUpdatesPending to
- */
- $scope.setUpdatesPending = function(val) {
- $scope.areUpdatesPending = val;
- }
-
- /**
- * Update the displayed results, based on filters/settings,
- * and call $scope.queryParameters.save() so that the new filter results
- * can be bookmarked.
- */
- $scope.updateResults = function() {
- $scope.renderStartTime = window.performance.now();
- $log.debug("renderStartTime: " + $scope.renderStartTime);
- $scope.displayLimit = $scope.displayLimitPending;
- $scope.mergeIdenticalRows = $scope.mergeIdenticalRowsPending;
-
- // For each USE_FREEFORM_FILTER column, populate showingColumnValues.
- // This is more efficient than applying the freeform filter within the
- // tight loop in removeHiddenImagePairs.
- angular.forEach(
- $scope.filterableColumnNames,
- function(columnName) {
- var columnHeader = $scope.extraColumnHeaders[columnName];
- if (columnHeader[constants.KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER]) {
- var columnStringMatch = $scope.columnStringMatch[columnName];
- var showingColumnValues = {};
- angular.forEach(
- $scope.allColumnValues[columnName],
- function(columnValue) {
- if (-1 != columnValue.indexOf(columnStringMatch)) {
- showingColumnValues[columnValue] = true;
- }
- }
- );
- $scope.showingColumnValues[columnName] = showingColumnValues;
- }
- }
- );
-
- // TODO(epoger): Every time we apply a filter, AngularJS creates
- // another copy of the array. Is there a way we can filter out
- // the imagePairs as they are displayed, rather than storing multiple
- // array copies? (For better performance.)
- if ($scope.viewingTab == $scope.defaultTab) {
- var doReverse = !currSortAsc;
-
- $scope.filteredImagePairs =
- $filter("orderBy")(
- $filter("removeHiddenImagePairs")(
- $scope.imagePairs,
- $scope.filterableColumnNames,
- $scope.showingColumnValues,
- $scope.viewingTab
- ),
- // [$scope.getSortColumnValue, $scope.getSecondOrderSortValue],
- $scope.getSortColumnValue,
- doReverse);
- $scope.limitedImagePairs = $filter("mergeAndLimit")(
- $scope.filteredImagePairs, $scope.displayLimit, $scope.mergeIdenticalRows);
- } else {
- $scope.filteredImagePairs =
- $filter("orderBy")(
- $filter("filter")(
- $scope.imagePairs,
- {tab: $scope.viewingTab},
- true
- ),
- // [$scope.getSortColumnValue, $scope.getSecondOrderSortValue]);
- $scope.getSortColumnValue);
- $scope.limitedImagePairs = $filter("mergeAndLimit")(
- $scope.filteredImagePairs, -1, $scope.mergeIdenticalRows);
- }
- $scope.showThumbnails = $scope.showThumbnailsPending;
- $scope.imageSize = $scope.imageSizePending;
- $scope.setUpdatesPending(false);
- $scope.queryParameters.save();
- }
-
- /**
- * This function is called when the results have been completely rendered
- * after updateResults().
- */
- $scope.resultsUpdatedCallback = function() {
- $scope.renderEndTime = window.performance.now();
- $log.debug("renderEndTime: " + $scope.renderEndTime);
- };
-
- /**
- * Re-sort the displayed results.
- *
- * @param subdict (string): which KEY__IMAGEPAIRS__* subdictionary
- * the sort column key is within, or 'none' if the sort column
- * key is one of KEY__IMAGEPAIRS__*
- * @param key (string): sort by value associated with this key in subdict
- */
- $scope.sortResultsBy = function(subdict, key) {
- // if we are already sorting by this column then toggle between asc/desc
- if ((subdict === $scope.sortColumnSubdict) && ($scope.sortColumnKey === key)) {
- currSortAsc = !currSortAsc;
- } else {
- $scope.sortColumnSubdict = subdict;
- $scope.sortColumnKey = key;
- currSortAsc = true;
- }
- $scope.updateResults();
- };
-
- /**
- * Returns ASC or DESC (from constants) if currently the data
- * is sorted by the provided column.
- *
- * @param colName: name of the column for which we need to get the class.
- */
-
- $scope.sortedByColumnsCls = function (colName) {
- if ($scope.sortColumnKey !== colName) {
- return '';
- }
-
- var result = (currSortAsc) ? constants.ASC : constants.DESC;
- console.log("sort class:", result);
- return result;
- };
-
- /**
- * For a particular ImagePair, return the value of the column we are
- * sorting on (according to $scope.sortColumnSubdict and
- * $scope.sortColumnKey).
- *
- * @param imagePair: imagePair to get a column value out of.
- */
- $scope.getSortColumnValue = function(imagePair) {
- if ($scope.sortColumnSubdict in imagePair) {
- return imagePair[$scope.sortColumnSubdict][$scope.sortColumnKey];
- } else if ($scope.sortColumnKey in imagePair) {
- return imagePair[$scope.sortColumnKey];
- } else {
- return undefined;
- }
- };
-
- /**
- * For a particular ImagePair, return the value we use for the
- * second-order sort (tiebreaker when multiple rows have
- * the same getSortColumnValue()).
- *
- * We join the imageA and imageB urls for this value, so that we merge
- * adjacent rows as much as possible.
- *
- * @param imagePair: imagePair to get a column value out of.
- */
- $scope.getSecondOrderSortValue = function(imagePair) {
- return imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] + "-vs-" +
- imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL];
- };
-
- /**
- * Set $scope.columnStringMatch[name] = value, and update results.
- *
- * @param name
- * @param value
- */
- $scope.setColumnStringMatch = function(name, value) {
- $scope.columnStringMatch[name] = value;
- $scope.updateResults();
- };
-
- /**
- * Update $scope.showingColumnValues[columnName] and $scope.columnStringMatch[columnName]
- * so that ONLY entries with this columnValue are showing, and update the visible results.
- * (We update both of those, so we cover both freeform and checkbox filtered columns.)
- *
- * @param columnName
- * @param columnValue
- */
- $scope.showOnlyColumnValue = function(columnName, columnValue) {
- $scope.columnStringMatch[columnName] = columnValue;
- $scope.showingColumnValues[columnName] = {};
- $scope.toggleValueInSet(columnValue, $scope.showingColumnValues[columnName]);
- $scope.updateResults();
- };
-
- /**
- * Update $scope.showingColumnValues[columnName] and $scope.columnStringMatch[columnName]
- * so that ALL entries are showing, and update the visible results.
- * (We update both of those, so we cover both freeform and checkbox filtered columns.)
- *
- * @param columnName
- */
- $scope.showAllColumnValues = function(columnName) {
- $scope.columnStringMatch[columnName] = "";
- $scope.showingColumnValues[columnName] = {};
- $scope.toggleValuesInSet($scope.allColumnValues[columnName],
- $scope.showingColumnValues[columnName]);
- $scope.updateResults();
- };
-
-
- //
- // Operations for sending info back to the server.
- //
-
- /**
- * Tell the server that the actual results of these particular tests
- * are acceptable.
- *
- * TODO(epoger): This assumes that the original expectations are in
- * imageSetA, and the actuals are in imageSetB.
- *
- * @param imagePairsSubset an array of test results, most likely a subset of
- * $scope.imagePairs (perhaps with some modifications)
- */
- $scope.submitApprovals = function(imagePairsSubset) {
- $scope.submitPending = true;
-
- // Convert bug text field to null or 1-item array.
- var bugs = null;
- var bugNumber = parseInt($scope.submitAdvancedSettings['bug']);
- if (!isNaN(bugNumber)) {
- bugs = [bugNumber];
- }
-
- // TODO(epoger): This is a suboptimal way to prevent users from
- // rebaselining failures in alternative renderModes, but it does work.
- // For a better solution, see
- // https://code.google.com/p/skia/issues/detail?id=1748 ('gm: add new
- // result type, RenderModeMismatch')
- var encounteredComparisonConfig = false;
-
- var updatedExpectations = [];
- for (var i = 0; i < imagePairsSubset.length; i++) {
- var imagePair = imagePairsSubset[i];
- var updatedExpectation = {};
- updatedExpectation[constants.KEY__IMAGEPAIRS__EXPECTATIONS] =
- imagePair[constants.KEY__IMAGEPAIRS__EXPECTATIONS];
- updatedExpectation[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS] =
- imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS];
- // IMAGE_B_URL contains the actual image (which is now the expectation)
- updatedExpectation[constants.KEY__IMAGEPAIRS__IMAGE_B_URL] =
- imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL];
- if (0 == updatedExpectation[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS]
- [constants.KEY__EXTRACOLUMNS__CONFIG]
- .indexOf('comparison-')) {
- encounteredComparisonConfig = true;
- }
-
- // Advanced settings...
- if (null == updatedExpectation[constants.KEY__IMAGEPAIRS__EXPECTATIONS]) {
- updatedExpectation[constants.KEY__IMAGEPAIRS__EXPECTATIONS] = {};
- }
- updatedExpectation[constants.KEY__IMAGEPAIRS__EXPECTATIONS]
- [constants.KEY__EXPECTATIONS__REVIEWED] =
- $scope.submitAdvancedSettings[
- constants.KEY__EXPECTATIONS__REVIEWED];
- if (true == $scope.submitAdvancedSettings[
- constants.KEY__EXPECTATIONS__IGNOREFAILURE]) {
- // if it's false, don't send it at all (just keep the default)
- updatedExpectation[constants.KEY__IMAGEPAIRS__EXPECTATIONS]
- [constants.KEY__EXPECTATIONS__IGNOREFAILURE] = true;
- }
- updatedExpectation[constants.KEY__IMAGEPAIRS__EXPECTATIONS]
- [constants.KEY__EXPECTATIONS__BUGS] = bugs;
-
- updatedExpectations.push(updatedExpectation);
- }
- if (encounteredComparisonConfig) {
- alert("Approval failed -- you cannot approve results with config " +
- "type comparison-*");
- $scope.submitPending = false;
- return;
- }
- var modificationData = {};
- modificationData[constants.KEY__EDITS__MODIFICATIONS] =
- updatedExpectations;
- modificationData[constants.KEY__EDITS__OLD_RESULTS_HASH] =
- $scope.header[constants.KEY__HEADER__DATAHASH];
- modificationData[constants.KEY__EDITS__OLD_RESULTS_TYPE] =
- $scope.header[constants.KEY__HEADER__TYPE];
- $http({
- method: "POST",
- url: "/edits",
- data: modificationData
- }).success(function(data, status, headers, config) {
- var imagePairIndicesToMove = [];
- for (var i = 0; i < imagePairsSubset.length; i++) {
- imagePairIndicesToMove.push(imagePairsSubset[i].index);
- }
- $scope.moveImagePairsToTab(imagePairIndicesToMove,
- "HackToMakeSureThisImagePairDisappears");
- $scope.updateResults();
- alert("New baselines submitted successfully!\n\n" +
- "You still need to commit the updated expectations files on " +
- "the server side to the Skia repo.\n\n" +
- "When you click OK, your web UI will reload; after that " +
- "completes, you will see the updated data (once the server has " +
- "finished loading the update results into memory!) and you can " +
- "submit more baselines if you want.");
- // I don't know why, but if I just call reload() here it doesn't work.
- // Making a timer call it fixes the problem.
- $timeout(function(){location.reload();}, 1);
- }).error(function(data, status, headers, config) {
- alert("There was an error submitting your baselines.\n\n" +
- "Please see server-side log for details.");
- $scope.submitPending = false;
- });
- };
-
-
- //
- // Operations we use to mimic Set semantics, in such a way that
- // checking for presence within the Set is as fast as possible.
- // But getting a list of all values within the Set is not necessarily
- // possible.
- // TODO(epoger): move into a separate .js file?
- //
-
- /**
- * Returns the number of values present within set "set".
- *
- * @param set an Object which we use to mimic set semantics
- */
- $scope.setSize = function(set) {
- return Object.keys(set).length;
- };
-
- /**
- * Returns true if value "value" is present within set "set".
- *
- * @param value a value of any type
- * @param set an Object which we use to mimic set semantics
- * (this should make isValueInSet faster than if we used an Array)
- */
- $scope.isValueInSet = function(value, set) {
- return (true == set[value]);
- };
-
- /**
- * If value "value" is already in set "set", remove it; otherwise, add it.
- *
- * @param value a value of any type
- * @param set an Object which we use to mimic set semantics
- */
- $scope.toggleValueInSet = function(value, set) {
- if (true == set[value]) {
- delete set[value];
- } else {
- set[value] = true;
- }
- };
-
- /**
- * For each value in valueArray, call toggleValueInSet(value, set).
- *
- * @param valueArray
- * @param set
- */
- $scope.toggleValuesInSet = function(valueArray, set) {
- var arrayLength = valueArray.length;
- for (var i = 0; i < arrayLength; i++) {
- $scope.toggleValueInSet(valueArray[i], set);
- }
- };
-
-
- //
- // Array operations; similar to our Set operations, but operate on a
- // Javascript Array so we *can* easily get a list of all values in the Set.
- // TODO(epoger): move into a separate .js file?
- //
-
- /**
- * Returns true if value "value" is present within array "array".
- *
- * @param value a value of any type
- * @param array a Javascript Array
- */
- $scope.isValueInArray = function(value, array) {
- return (-1 != array.indexOf(value));
- };
-
- /**
- * If value "value" is already in array "array", remove it; otherwise,
- * add it.
- *
- * @param value a value of any type
- * @param array a Javascript Array
- */
- $scope.toggleValueInArray = function(value, array) {
- var i = array.indexOf(value);
- if (-1 == i) {
- array.push(value);
- } else {
- array.splice(i, 1);
- }
- };
-
-
- //
- // Miscellaneous utility functions.
- // TODO(epoger): move into a separate .js file?
- //
-
- /**
- * Returns a single "column slice" of a 2D array.
- *
- * For example, if array is:
- * [[A0, A1],
- * [B0, B1],
- * [C0, C1]]
- * and index is 0, this this will return:
- * [A0, B0, C0]
- *
- * @param array a Javascript Array
- * @param column (numeric): index within each row array
- */
- $scope.columnSliceOf2DArray = function(array, column) {
- var slice = [];
- var numRows = array.length;
- for (var row = 0; row < numRows; row++) {
- slice.push(array[row][column]);
- }
- return slice;
- };
-
- /**
- * Returns a human-readable (in local time zone) time string for a
- * particular moment in time.
- *
- * @param secondsPastEpoch (numeric): seconds past epoch in UTC
- */
- $scope.localTimeString = function(secondsPastEpoch) {
- var d = new Date(secondsPastEpoch * 1000);
- return d.toString();
- };
-
- /**
- * Returns a hex color string (such as "#aabbcc") for the given RGB values.
- *
- * @param r (numeric): red channel value, 0-255
- * @param g (numeric): green channel value, 0-255
- * @param b (numeric): blue channel value, 0-255
- */
- $scope.hexColorString = function(r, g, b) {
- var rString = r.toString(16);
- if (r < 16) {
- rString = "0" + rString;
- }
- var gString = g.toString(16);
- if (g < 16) {
- gString = "0" + gString;
- }
- var bString = b.toString(16);
- if (b < 16) {
- bString = "0" + bString;
- }
- return '#' + rString + gString + bString;
- };
-
- /**
- * Returns a hex color string (such as "#aabbcc") for the given brightness.
- *
- * @param brightnessString (string): 0-255, 0 is completely black
- *
- * TODO(epoger): It might be nice to tint the color when it's not completely
- * black or completely white.
- */
- $scope.brightnessStringToHexColor = function(brightnessString) {
- var v = parseInt(brightnessString);
- return $scope.hexColorString(v, v, v);
- };
-
- }
-);
diff --git a/gm/rebaseline_server/static/new/bower.json b/gm/rebaseline_server/static/new/bower.json
deleted file mode 100644
index 775213dd56..0000000000
--- a/gm/rebaseline_server/static/new/bower.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "rebasline",
- "version": "0.1.0",
- "authors": [],
- "description": "Rebaseline Server",
- "license": "BSD",
- "private": true,
- "ignore": [
- "**/.*",
- "node_modules",
- "bower_components",
- "third_party/bower_components",
- "test",
- "tests"
- ],
- "dependencies": {
- "angular": "1.2.x",
- "angular-route": "1.2.x",
- "angular-bootstrap": "0.11.x",
- "bootstrap": "3.1.x"
- }
-}
diff --git a/gm/rebaseline_server/static/new/css/app.css b/gm/rebaseline_server/static/new/css/app.css
deleted file mode 100644
index fb0cc09e5c..0000000000
--- a/gm/rebaseline_server/static/new/css/app.css
+++ /dev/null
@@ -1,71 +0,0 @@
-/* app css stylesheet */
-
-.formPadding {
- padding-left: 2em !important;
- padding-right: 0 !important;
-}
-
-.controlBox {
- border-left: 1px solid #ddd;
- border-right: 1px solid #ddd;
- border-bottom: 1px solid #ddd;
- padding-right: 0;
- width: 100%;
- padding-top: 2em;
-}
-
-.simpleLegend {
- font-size: 16px;
- margin-bottom: 3px;
- width: 95%;
-}
-
-.settingsForm {
- padding-left: 1em;
- padding-right: 0;
-}
-
-
-.resultsHeaderActions {
- float: right;
-}
-
-.sticky {
- position: fixed;
- top: 2px;
- box-shadow: -2px 2px 5px 0 rgba(0,0,0,.45);
- background: white;
- right: 2px;
- padding: 10px;
- border: 2px solid #222;
-}
-
-.sortDesc {
- background:no-repeat left center url(data:image/gif;base64,R0lGODlhCgAKALMAAHFxcYKCgp2dnaampq+vr83NzeHh4f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAAAgAIf/8SUNDUkdCRzEwMTIAAAUwYXBwbAIgAABtbnRyUkdCIFhZWiAH2QACABkACwAaAAthY3NwQVBQTAAAAABhcHBsAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtkc2NtAAABCAAAAvJkZXNjAAAD/AAAAG9nWFlaAAAEbAAAABR3dHB0AAAEgAAAABRyWFlaAAAElAAAABRiWFlaAAAEqAAAABRyVFJDAAAEvAAAAA5jcHJ0AAAEzAAAADhjaGFkAAAFBAAAACxn/1RSQwAABLwAAAAOYlRSQwAABLwAAAAObWx1YwAAAAAAAAARAAAADGVuVVMAAAAmAAACfmVzRVMAAAAmAAABgmRhREsAAAAuAAAB6mRlREUAAAAsAAABqGZpRkkAAAAoAAAA3GZyRlUAAAAoAAABKml0SVQAAAAoAAACVm5sTkwAAAAoAAACGG5iTk8AAAAmAAABBHB0QlIAAAAmAAABgnN2U0UAAAAmAAABBGphSlAAAAAaAAABUmtvS1IAAAAWAAACQHpoVFcAAAAWAAABbHpoQ04AAAAWAAAB1HJ1UlUAAAAiAAACpHBsUEwAAAAsAAACxgBZAGwAZQBpAG4AZf8AbgAgAFIARwBCAC0AcAByAG8AZgBpAGkAbABpAEcAZQBuAGUAcgBpAHMAawAgAFIARwBCAC0AcAByAG8AZgBpAGwAUAByAG8AZgBpAGwAIABHAOkAbgDpAHIAaQBxAHUAZQAgAFIAVgBCTgCCLAAgAFIARwBCACAw1zDtMNUwoTCkMOuQGnUoACAAUgBHAEIAIIJyX2ljz4/wAFAAZQByAGYAaQBsACAAUgBHAEIAIABHAGUAbgDpAHIAaQBjAG8AQQBsAGwAZwBlAG0AZQBpAG4AZQBzACAAUgBHAEIALQBQAHIAbwBmAGkAbGZukBoAIABSAEcAQgAgY8+P8GX/h072AEcAZQBuAGUAcgBlAGwAIABSAEcAQgAtAGIAZQBzAGsAcgBpAHYAZQBsAHMAZQBBAGwAZwBlAG0AZQBlAG4AIABSAEcAQgAtAHAAcgBvAGYAaQBlAGzHfLwYACAAUgBHAEIAINUEuFzTDMd8AFAAcgBvAGYAaQBsAG8AIABSAEcAQgAgAEcAZQBuAGUAcgBpAGMAbwBHAGUAbgBlAHIAaQBjACAAUgBHAEIAIABQAHIAbwBmAGkAbABlBB4EMQRJBDgEOQAgBD8EQAQ+BEQEOAQ7BEwAIABSAEcAQgBVAG4AaQB3AGUAcgBzAGEAbABuAHkAIABwAHIAbwBm/wBpAGwAIABSAEcAQgAAZGVzYwAAAAAAAAAUR2VuZXJpYyBSR0IgUHJvZmlsZQAAAAAAAAAAAAAAFEdlbmVyaWMgUkdCIFByb2ZpbGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABadQAArHMAABc0WFlaIAAAAAAAAPNSAAEAAAABFs9YWVogAAAAAAAAdE0AAD3uAAAD0FhZWiAAAAAAAAAoGgAAFZ8AALg2Y3VydgAAAAAAAAABAc0AAHRleHQAAAAAQ29weXJpZ2h0IDIwMDcgQXBwbGUgSW5jLkMsIGFsbCByaWdodHMgcmVzZXJ2ZWQuAHNmMzIAAAAAAAEMQgAABd7///MmAAAHkgAA/ZH///ui///9owAAA9wAAMBsACwAAAAACgAKAAAEJZAMIcakQZjNtyhFxwEIIRofAookUnapu26t+6KFLYe1TgQ5VwQAOw%3D%3D);
-}
-
-.sortAsc {
- background:no-repeat left center url(data:image/gif;base64,R0lGODlhCgAKALMAAHFxcYKCgp2dnaampq+vr83NzeHh4f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAAAgAIf/8SUNDUkdCRzEwMTIAAAUwYXBwbAIgAABtbnRyUkdCIFhZWiAH2QACABkACwAaAAthY3NwQVBQTAAAAABhcHBsAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtkc2NtAAABCAAAAvJkZXNjAAAD/AAAAG9nWFlaAAAEbAAAABR3dHB0AAAEgAAAABRyWFlaAAAElAAAABRiWFlaAAAEqAAAABRyVFJDAAAEvAAAAA5jcHJ0AAAEzAAAADhjaGFkAAAFBAAAACxn/1RSQwAABLwAAAAOYlRSQwAABLwAAAAObWx1YwAAAAAAAAARAAAADGVuVVMAAAAmAAACfmVzRVMAAAAmAAABgmRhREsAAAAuAAAB6mRlREUAAAAsAAABqGZpRkkAAAAoAAAA3GZyRlUAAAAoAAABKml0SVQAAAAoAAACVm5sTkwAAAAoAAACGG5iTk8AAAAmAAABBHB0QlIAAAAmAAABgnN2U0UAAAAmAAABBGphSlAAAAAaAAABUmtvS1IAAAAWAAACQHpoVFcAAAAWAAABbHpoQ04AAAAWAAAB1HJ1UlUAAAAiAAACpHBsUEwAAAAsAAACxgBZAGwAZQBpAG4AZf8AbgAgAFIARwBCAC0AcAByAG8AZgBpAGkAbABpAEcAZQBuAGUAcgBpAHMAawAgAFIARwBCAC0AcAByAG8AZgBpAGwAUAByAG8AZgBpAGwAIABHAOkAbgDpAHIAaQBxAHUAZQAgAFIAVgBCTgCCLAAgAFIARwBCACAw1zDtMNUwoTCkMOuQGnUoACAAUgBHAEIAIIJyX2ljz4/wAFAAZQByAGYAaQBsACAAUgBHAEIAIABHAGUAbgDpAHIAaQBjAG8AQQBsAGwAZwBlAG0AZQBpAG4AZQBzACAAUgBHAEIALQBQAHIAbwBmAGkAbGZukBoAIABSAEcAQgAgY8+P8GX/h072AEcAZQBuAGUAcgBlAGwAIABSAEcAQgAtAGIAZQBzAGsAcgBpAHYAZQBsAHMAZQBBAGwAZwBlAG0AZQBlAG4AIABSAEcAQgAtAHAAcgBvAGYAaQBlAGzHfLwYACAAUgBHAEIAINUEuFzTDMd8AFAAcgBvAGYAaQBsAG8AIABSAEcAQgAgAEcAZQBuAGUAcgBpAGMAbwBHAGUAbgBlAHIAaQBjACAAUgBHAEIAIABQAHIAbwBmAGkAbABlBB4EMQRJBDgEOQAgBD8EQAQ+BEQEOAQ7BEwAIABSAEcAQgBVAG4AaQB3AGUAcgBzAGEAbABuAHkAIABwAHIAbwBm/wBpAGwAIABSAEcAQgAAZGVzYwAAAAAAAAAUR2VuZXJpYyBSR0IgUHJvZmlsZQAAAAAAAAAAAAAAFEdlbmVyaWMgUkdCIFByb2ZpbGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABadQAArHMAABc0WFlaIAAAAAAAAPNSAAEAAAABFs9YWVogAAAAAAAAdE0AAD3uAAAD0FhZWiAAAAAAAAAoGgAAFZ8AALg2Y3VydgAAAAAAAAABAc0AAHRleHQAAAAAQ29weXJpZ2h0IDIwMDcgQXBwbGUgSW5jLkMsIGFsbCByaWdodHMgcmVzZXJ2ZWQuAHNmMzIAAAAAAAEMQgAABd7///MmAAAHkgAA/ZH///ui///9owAAA9wAAMBsACwAAAAACgAKAAAEJRBJREKZsxQDsCSGIVzZFnYTGIqktp7fG46uzAn2TAyCMPC9QAQAOw%3D%3D);
-}
-
-.sortableHeader {
- padding-right: 3px;
- padding-left: 13px;
- margin-left: 4px;
-}
-
-.updateBtn {
- padding-top: 1em;
- margin-left: 0;
-}
-
-.filterBox {
- border: 1px solid #DDDDDD;
- margin-right: 1em;
- padding-top: 5px;
- padding-bottom: 5px;
-}
-
-.filterKey {
- font-weight: bold;
-} \ No newline at end of file
diff --git a/gm/rebaseline_server/static/new/js/app.js b/gm/rebaseline_server/static/new/js/app.js
deleted file mode 100644
index 0a1fac0a45..0000000000
--- a/gm/rebaseline_server/static/new/js/app.js
+++ /dev/null
@@ -1,1130 +0,0 @@
-'use strict';
-
-/**
- * TODO (stephana@): This is still work in progress.
- * It does not offer the same functionality as the current version, but
- * will serve as the starting point for a new backend.
- * It works with the current backend, but does not support rebaselining.
- */
-
-/*
- * Wrap everything into an IIFE to not polute the global namespace.
- */
-(function () {
-
- // Declare app level module which contains everything of the current app.
- // ui.bootstrap refers to directives defined in the AngularJS Bootstrap
- // UI package (http://angular-ui.github.io/bootstrap/).
- var app = angular.module('rbtApp', ['ngRoute', 'ui.bootstrap']);
-
- // Configure the different within app views.
- app.config(['$routeProvider', function($routeProvider) {
- $routeProvider.when('/', {templateUrl: 'partials/index-view.html',
- controller: 'IndexCtrl'});
- $routeProvider.when('/view', {templateUrl: 'partials/rebaseline-view.html',
- controller: 'RebaselineCrtrl'});
- $routeProvider.otherwise({redirectTo: '/'});
- }]);
-
-
- // TODO (stephana): Some of these constants are 'gm' specific. In the
- // next iteration we need to remove those as we move the more generic
- // 'dm' testing tool.
- //
- // Shared constants used here and in the markup. These are exported when
- // when used by a controller.
- var c = {
- // Define different view states as we load the data.
- ST_LOADING: 1,
- ST_STILL_LOADING: 2,
- ST_READY: 3,
-
- // These column types are used by the Column class.
- COL_T_FILTER: 'filter',
- COL_T_IMAGE: 'image',
- COL_T_REGULAR: 'regular',
-
- // Request parameters used to select between subsets of results.
- RESULTS_ALL: 'all',
- RESULTS_FAILURES: 'failures',
-
- // Filter types are used by the Column class.
- FILTER_FREE_FORM: 'free_form',
- FILTER_CHECK_BOX: 'checkbox',
-
- // Columns either provided by the backend response or added in code.
- // TODO (stephana): This should go away once we switch to 'dm'.
- COL_BUGS: 'bugs',
- COL_IGNORE_FAILURE: 'ignore-failure',
- COL_REVIEWED_BY_HUMANS: 'reviewed-by-human',
-
- // Defines the order in which image columns appear.
- // TODO (stephana@): needs to be driven by backend data.
- IMG_COL_ORDER: [
- {
- key: 'imageA',
- urlField: ['imageAUrl']
- },
- {
- key: 'imageB',
- urlField: ['imageBUrl']
- },
- {
- key: 'whiteDiffs',
- urlField: ['differenceData', 'whiteDiffUrl'],
- percentField: ['differenceData', 'percentDifferingPixels'],
- valueField: ['differenceData', 'numDifferingPixels']
- },
- {
- key: 'diffs',
- urlField: ['differenceData', 'diffUrl'],
- percentField: ['differenceData', 'perceptualDifference'],
- valueField: ['differenceData', 'maxDiffPerChannel']
- }
- ],
-
- // Choice of availabe image size selection.
- IMAGE_SIZES: [
- 100,
- 200,
- 400
- ],
-
- // Choice of available number of records selection.
- MAX_RECORDS: [
- '100',
- '200',
- '300'
- ]
- }; // end constants
-
- /*
- * Index Controller
- */
- // TODO (stephana): Remove $timeout since it only simulates loading delay.
- app.controller('IndexCtrl', ['$scope', '$timeout', 'dataService',
- function($scope, $timeout, dataService) {
- // init the scope
- $scope.c = c;
- $scope.state = c.ST_LOADING;
- $scope.qStr = dataService.getQueryString;
-
- // TODO (stephana): Remove and replace with index data generated by the
- // backend to reflect the current "known" image sets to compare.
- $scope.allSKPs = [
- {
- params: {
- setBSection: 'actual-results',
- setASection: 'expected-results',
- setBDir: 'gs://chromium-skia-skp-summaries/' +
- 'Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug',
- setADir: 'repo:expectations/skp/' +
- 'Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug'
- },
- title: 'expected vs actuals on ' +
- 'Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug'
- },
- {
- params: {
- setBSection: 'actual-results',
- setASection: 'expected-results',
- setBDir: 'gs://chromium-skia-skp-summaries/' +
- 'Test-Ubuntu12-ShuttleA-GTX660-x86-Release',
- setADir: 'repo:expectations/skp/'+
- 'Test-Ubuntu12-ShuttleA-GTX660-x86-Release'
- },
- title: 'expected vs actuals on Test-Ubuntu12-ShuttleA-GTX660-x86-Release'
- },
- {
- params: {
- setBSection: 'actual-results',
- setASection: 'actual-results',
- setBDir: 'gs://chromium-skia-skp-summaries/' +
- 'Test-Ubuntu12-ShuttleA-GTX660-x86-Release',
- setADir: 'gs://chromium-skia-skp-summaries/' +
- 'Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug'
- },
- title: 'Actuals on Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug ' +
- 'vs Test-Ubuntu12-ShuttleA-GTX660-x86-Release'
- }
- ];
-
- // TODO (stephana): Remove this once we load index data from the server.
- $timeout(function () {
- $scope.state = c.ST_READY;
- });
- }]);
-
- /*
- * RebaselineCtrl
- * Controls the main comparison view.
- *
- * @param {service} dataService Service that encapsulates functions to
- * retrieve data from the backend.
- *
- */
- app.controller('RebaselineCrtrl', ['$scope', '$timeout', 'dataService',
- function($scope, $timeout, dataService) {
- // determine which to request
- // TODO (stephana): This should be extracted from the query parameters.
- var target = c.TARGET_GM;
-
- // process the rquest arguments
- // TODO (stephana): This should be determined from the query parameters.
- var loadFn = dataService.loadAll;
-
- // controller state variables
- var allData = null;
- var filterFuncs = null;
- var currentData = null;
- var selectedData = null;
-
- // Index of the column that should provide the sort key
- var sortByIdx = 0;
-
- // Sort in asending (true) or descending (false) order
- var sortOrderAsc = true;
-
- // Array of functions for each column used for comparison during sort.
- var compareFunctions = null;
-
- // Variables to track load and render times
- var startTime;
- var loadStartTime;
-
-
- /** Load the data from the backend **/
- loadStartTime = Date.now();
- function loadData() {
- loadFn().then(
- function (serverData) {
- $scope.header = serverData.header;
- $scope.loadTime = (Date.now() - loadStartTime)/1000;
-
- // keep polling if the data are not ready yet
- if ($scope.header.resultsStillLoading) {
- $scope.state = c.ST_STILL_LOADING;
- $timeout(loadData, 5000);
- return;
- }
-
- // get the filter colunms and an array to hold filter data by user
- var fcol = getFilterColumns(serverData);
- $scope.filterCols = fcol[0];
- $scope.filterVals = fcol[1];
-
- // Add extra columns and retrieve the image columns
- var otherCols = [ Column.regular(c.COL_BUGS) ];
- var imageCols = getImageColumns(serverData);
-
- // Concat to get all columns
- // NOTE: The order is important since filters are rendered first,
- // followed by regular columns and images
- $scope.allCols = $scope.filterCols.concat(otherCols, imageCols);
-
- // Pre-process the data and get the filter functions.
- var dataFilters = getDataAndFilters(serverData, $scope.filterCols,
- otherCols, imageCols);
- allData = dataFilters[0];
- filterFuncs = dataFilters[1];
-
- // Get regular columns (== not image columns)
- var regularCols = $scope.filterCols.concat(otherCols);
-
- // Get the compare functions for regular and image columns. These
- // are then used to sort by the respective columns.
- compareFunctions = DataRow.getCompareFunctions(regularCols,
- imageCols);
-
- // Filter and sort the results to get them ready for rendering
- updateResults();
-
- // Data are ready for display
- $scope.state = c.ST_READY;
- },
- function (httpErrResponse) {
- console.log(httpErrResponse);
- });
- };
-
- /*
- * updateResults
- * Central render function. Everytime settings/filters/etc. changed
- * this function is called to filter, sort and splice the data.
- *
- * NOTE (stephana): There is room for improvement here: before filtering
- * and sorting we could check if this is necessary. But this has not been
- * a bottleneck so far.
- */
- function updateResults () {
- // run digest before we update the results. This allows
- // updateResults to be called from functions trigger by ngChange
- $scope.updating = true;
- startTime = Date.now();
-
- // delay by one render cycle so it can be called via ng-change
- $timeout(function() {
- // filter data
- selectedData = filterData(allData, filterFuncs, $scope.filterVals);
-
- // sort the selected data.
- sortData(selectedData, compareFunctions, sortByIdx, sortOrderAsc);
-
- // only conside the elements that we really need
- var nRecords = $scope.settings.nRecords;
- currentData = selectedData.slice(0, parseInt(nRecords));
-
- DataRow.setRowspanValues(currentData, $scope.mergeIdenticalRows);
-
- // update the scope with relevant data for rendering.
- $scope.data = currentData;
- $scope.totalRecords = allData.length;
- $scope.showingRecords = currentData.length;
- $scope.selectedRecords = selectedData.length;
- $scope.updating = false;
-
- // measure the filter time and total render time (via timeout).
- $scope.filterTime = Date.now() - startTime;
- $timeout(function() {
- $scope.renderTime = Date.now() - startTime;
- });
- });
- };
-
- /**
- * Generate the style value to set the width of images.
- *
- * @param {Column} col Column that we are trying to render.
- * @param {int} paddingPx Number of padding pixels.
- * @param {string} defaultVal Default value if not an image column.
- *
- * @return {string} Value to be used in ng-style element to set the width
- * of a image column.
- **/
- $scope.getImageWidthStyle = function (col, paddingPx, defaultVal) {
- var result = (col.ctype === c.COL_T_IMAGE) ?
- ($scope.imageSize + paddingPx + 'px') : defaultVal;
- return result;
- };
-
- /**
- * Sets the column by which to sort the data. If called for the
- * currently sorted column it will cause the sort to toggle between
- * ascending and descending.
- *
- * @param {int} colIdx Index of the column to use for sorting.
- **/
- $scope.sortBy = function (colIdx) {
- if (sortByIdx === colIdx) {
- sortOrderAsc = !sortOrderAsc;
- } else {
- sortByIdx = colIdx;
- sortOrderAsc = true;
- }
- updateResults();
- };
-
- /**
- * Helper function to generate a CSS class indicating whether this column
- * is the sort key. If it is a class name with the sort direction (Asc/Desc) is
- * return otherwise the default value is returned. In markup we use this
- * to display (or not display) an arrow next to the column name.
- *
- * @param {string} prefix Prefix of the classname to be generated.
- * @param {int} idx Index of the target column.
- * @param {string} defaultVal Value to return if current column is not used
- * for sorting.
- *
- * @return {string} CSS class name that a combination of the prefix and
- * direction indicator ('Asc' or 'Desc') if the column is
- * used for sorting. Otherwise the defaultVal is returned.
- **/
- $scope.getSortedClass = function (prefix, idx, defaultVal) {
- if (idx === sortByIdx) {
- return prefix + ((sortOrderAsc) ? 'Asc' : 'Desc');
- }
-
- return defaultVal;
- };
-
- /**
- * Checkbox to merge identical records has change. Force an update.
- **/
- $scope.mergeRowsChanged = function () {
- updateResults();
- }
-
- /**
- * Max number of records to display has changed. Force an update.
- **/
- $scope.maxRecordsChanged = function () {
- updateResults();
- };
-
- /**
- * Filter settings changed. Force an update.
- **/
- $scope.filtersChanged = function () {
- updateResults();
- };
-
- /**
- * Sets all possible values of the specified values to the given value.
- * That means all checkboxes are eiter selected or unselected.
- * Then force an update.
- *
- * @param {int} idx Index of the target filter column.
- * @param {boolean} val Value to set the filter values to.
- *
- **/
- $scope.setFilterAll = function (idx, val) {
- for(var i=0, len=$scope.filterVals[idx].length; i<len; i++) {
- $scope.filterVals[idx][i] = val;
- }
- updateResults();
- };
-
- /**
- * Toggle the values of a filter. This toggles all values in a
- * filter.
- *
- * @param {int} idx Index of the target filter column.
- **/
- $scope.setFilterToggle = function (idx) {
- for(var i=0, len=$scope.filterVals[idx].length; i<len; i++) {
- $scope.filterVals[idx][i] = !$scope.filterVals[idx][i];
- }
- updateResults();
- };
-
- // ****************************************
- // Initialize the scope.
- // ****************************************
-
- // Inject the constants into the scope and set the initial state.
- $scope.c = c;
- $scope.state = c.ST_LOADING;
-
- // Initial settings
- $scope.settings = {
- showThumbnails: true,
- imageSize: c.IMAGE_SIZES[0],
- nRecords: c.MAX_RECORDS[0],
- mergeIdenticalRows: true
- };
-
- // Initial values for filters set in loadData()
- $scope.filterVals = [];
-
- // Information about records - set in loadData()
- $scope.totalRecords = 0;
- $scope.showingRecords = 0;
- $scope.updating = false;
-
- // Trigger the data loading.
- loadData();
-
- }]);
-
- // data structs to interface with markup and backend
- /**
- * Models a column. It aggregates attributes of all
- * columns types. Some might be empty. See convenience
- * factory methods below for different column types.
- *
- * @param {string} key Uniquely identifies this columns
- * @param {string} ctype Type of columns. Use COL_* constants.
- * @param {string} ctitle Human readable title of the column.
- * @param {string} ftype Filter type. Use FILTER_* constants.
- * @param {FilterOpt[]} foptions Filter options. For 'checkbox' filters this
- is used to render all the checkboxes.
- For freeform filters this is a list of all
- available values.
- * @param {string} baseUrl Baseurl for image columns. All URLs are relative
- to this.
- *
- * @return {Column} Instance of the Column class.
- **/
- function Column(key, ctype, ctitle, ftype, foptions, baseUrl) {
- this.key = key;
- this.ctype = ctype;
- this.ctitle = ctitle;
- this.ftype = ftype;
- this.foptions = foptions;
- this.baseUrl = baseUrl;
- this.foptionsArr = [];
-
- // get the array of filter options for lookup in indexOfOptVal
- if (this.foptions) {
- for(var i=0, len=foptions.length; i<len; i++) {
- this.foptionsArr.push(this.foptions[i].value);
- }
- }
- }
-
- /**
- * Find the index of an value in a column with a fixed set
- * of options.
- *
- * @param {string} optVal Value of the column.
- *
- * @return {int} Index of optVal in this column.
- **/
- Column.prototype.indexOfOptVal = function (optVal) {
- return this.foptionsArr.indexOf(optVal);
- };
-
- /**
- * Set filter options for this column.
- *
- * @param {FilterOpt[]} foptions Possible values for this column.
- **/
- Column.prototype.setFilterOptions = function (foptions) {
- this.foptions = foptions;
- };
-
- /**
- * Factory function to create a filter column. Same args as Column()
- **/
- Column.filter = function(key, ctitle, ftype, foptions) {
- return new Column(key, c.COL_T_FILTER, ctitle || key, ftype, foptions);
- }
-
- /**
- * Factory function to create an image column. Same args as Column()
- **/
- Column.image = function (key, ctitle, baseUrl) {
- return new Column(key, c.COL_T_IMAGE, ctitle || key, null, null, baseUrl);
- };
-
- /**
- * Factory function to create a regular column. Same args as Column()
- **/
- Column.regular = function (key, ctitle) {
- return new Column(key, c.COL_T_REGULAR, ctitle || key);
- };
-
- /**
- * Helper class to wrap a single option in a filter.
- *
- * @param {string} value Option value.
- * @param {int} count Number of instances of this option in the dataset.
- *
- * @return {} Instance of FiltertOpt
- **/
- function FilterOpt(value, count) {
- this.value = value;
- this.count = count;
- }
-
- /**
- * Container for a single row in the dataset.
- *
- * @param {int} rowspan Number of rows (including this and following rows)
- that have identical values.
- * @param {string[]} dataCols Values of the respective columns (combination
- of filter and regular columns)
- * @param {ImgVal[]} imageCols Image meta data for the image columns.
- *
- * @return {DataRow} Instance of DataRow.
- **/
- function DataRow(rowspan, dataCols, imageCols) {
- this.rowspan = rowspan;
- this.dataCols = dataCols;
- this.imageCols = imageCols;
- }
-
- /**
- * Gets the comparator functions for the columns in this dataset.
- * The comparators are then used to sort the dataset by the respective
- * column.
- *
- * @param {Column[]} dataCols Data columns (= non-image columns)
- * @param {Column[]} imgCols Image columns.
- *
- * @return {Function[]} Array of functions that can be used to sort by the
- * respective column.
- **/
- DataRow.getCompareFunctions = function (dataCols, imgCols) {
- var result = [];
- for(var i=0, len=dataCols.length; i<len; i++) {
- result.push(( function (col, idx) {
- return function (a, b) {
- return (a.dataCols[idx] < b.dataCols[idx]) ? -1 :
- ((a.dataCols[idx] === b.dataCols[idx]) ? 0 : 1);
- };
- }(dataCols[i], i) ));
- }
-
- for(var i=0, len=imgCols.length; i<len; i++) {
- result.push((function (col, idx) {
- return function (a,b) {
- var aVal = a.imageCols[idx].percent;
- var bVal = b.imageCols[idx].percent;
-
- return (aVal < bVal) ? -1 : ((aVal === bVal) ? 0 : 1);
- };
- }(imgCols[i], i) ));
- }
-
- return result;
- };
-
- /**
- * Set the rowspan values of a given array of DataRow instances.
- *
- * @param {DataRow[]} data Dataset in desired order (after sorting).
- * @param {mergeRows} mergeRows Indicate whether to sort
- **/
- DataRow.setRowspanValues = function (data, mergeRows) {
- var curIdx, rowspan, cur;
- if (mergeRows) {
- for(var i=0, len=data.length; i<len;) {
- curIdx = i;
- cur = data[i];
- rowspan = 1;
- for(i++; ((i<len) && (data[i].dataCols === cur.dataCols)); i++) {
- rowspan++;
- data[i].rowspan=0;
- }
- data[curIdx].rowspan = rowspan;
- }
- } else {
- for(var i=0, len=data.length; i<len; i++) {
- data[i].rowspan = 1;
- }
- }
- };
-
- /**
- * Wrapper class for image related data.
- *
- * @param {string} url Relative Url of the image or null if not available.
- * @param {float} percent Percent of pixels that are differing.
- * @param {int} value Absolute number of pixes differing.
- *
- * @return {ImgVal} Instance of ImgVal.
- **/
- function ImgVal(url, percent, value) {
- this.url = url;
- this.percent = percent;
- this.value = value;
- }
-
- /**
- * Extracts the filter columns from the JSON response of the server.
- *
- * @param {object} data Server response.
- *
- * @return {Column[]} List of filter columns as described in 'header' field.
- **/
- function getFilterColumns(data) {
- var result = [];
- var vals = [];
- var colOrder = data.extraColumnOrder;
- var colHeaders = data.extraColumnHeaders;
- var fopts, optVals, val;
-
- for(var i=0, len=colOrder.length; i<len; i++) {
- if (colHeaders[colOrder[i]].isFilterable) {
- if (colHeaders[colOrder[i]].useFreeformFilter) {
- result.push(Column.filter(colOrder[i],
- colHeaders[colOrder[i]].headerText,
- c.FILTER_FREE_FORM));
- vals.push('');
- }
- else {
- fopts = [];
- optVals = [];
-
- // extract the different options for this column
- for(var j=0, jlen=colHeaders[colOrder[i]].valuesAndCounts.length;
- j<jlen; j++) {
- val = colHeaders[colOrder[i]].valuesAndCounts[j];
- fopts.push(new FilterOpt(val[0], val[1]));
- optVals.push(false);
- }
-
- // ad the column and values
- result.push(Column.filter(colOrder[i],
- colHeaders[colOrder[i]].headerText,
- c.FILTER_CHECK_BOX,
- fopts));
- vals.push(optVals);
- }
- }
- }
-
- return [result, vals];
- }
-
- /**
- * Extracts the image columns from the JSON response of the server.
- *
- * @param {object} data Server response.
- *
- * @return {Column[]} List of images columns as described in 'header' field.
- **/
- function getImageColumns(data) {
- var CO = c.IMG_COL_ORDER;
- var imgSet;
- var result = [];
- for(var i=0, len=CO.length; i<len; i++) {
- imgSet = data.imageSets[CO[i].key];
- result.push(Column.image(CO[i].key,
- imgSet.description,
- ensureTrailingSlash(imgSet.baseUrl)));
- }
- return result;
- }
-
- /**
- * Make sure Url has a trailing '/'.
- *
- * @param {string} url Base url.
- * @return {string} Same url with a trailing '/' or same as input if it
- already contained '/'.
- **/
- function ensureTrailingSlash(url) {
- var result = url.trim();
-
- // TODO: remove !!!
- result = fixUrl(url);
- if (result[result.length-1] !== '/') {
- result += '/';
- }
- return result;
- }
-
- // TODO: remove. The backend should provide absoute URLs
- function fixUrl(url) {
- url = url.trim();
- if ('http' === url.substr(0, 4)) {
- return url;
- }
-
- var idx = url.indexOf('static');
- if (idx != -1) {
- return '/' + url.substr(idx);
- }
-
- return url;
- };
-
- /**
- * Processes that data and returns filter functions.
- *
- * @param {object} Server response.
- * @param {Column[]} filterCols Filter columns.
- * @param {Column[]} otherCols Columns that are neither filters nor images.
- * @param {Column[]} imageCols Image columns.
- *
- * @return {[]} Returns a pair [dataRows, filterFunctions] where:
- * - dataRows is an array of DataRow instances.
- * - filterFunctions is an array of functions that can be used to
- * filter the column at the corresponding index.
- *
- **/
- function getDataAndFilters(data, filterCols, otherCols, imageCols) {
- var el;
- var result = [];
- var lookupIndices = [];
- var indexerFuncs = [];
- var temp;
-
- // initialize the lookupIndices
- var filterFuncs = initIndices(filterCols, lookupIndices, indexerFuncs);
-
- // iterate over the data and get the rows
- for(var i=0, len=data.imagePairs.length; i<len; i++) {
- el = data.imagePairs[i];
- temp = new DataRow(1, getColValues(el, filterCols, otherCols),
- getImageValues(el, imageCols));
- result.push(temp);
-
- // index the row
- for(var j=0, jlen=filterCols.length; j < jlen; j++) {
- indexerFuncs[j](lookupIndices[j], filterCols[j], temp.dataCols[j], i);
- }
- }
-
- setFreeFormFilterOptions(filterCols, lookupIndices);
- return [result, filterFuncs];
- }
-
- /**
- * Initiazile the lookup indices and indexer functions for the filter
- * columns.
- *
- * @param {Column} filterCols Filter columns
- * @param {[]} lookupIndices Will be filled with datastructures for
- fast lookup (output parameter)
- * @param {[]} lookupIndices Will be filled with functions to index data
- of the column with the corresponding column.
- *
- * @return {[]} Returns an array of filter functions that can be used to
- filter the respective column.
- **/
- function initIndices(filterCols, lookupIndices, indexerFuncs) {
- var filterFuncs = [];
- var temp;
-
- for(var i=0, len=filterCols.length; i<len; i++) {
- if (filterCols[i].ftype === c.FILTER_FREE_FORM) {
- lookupIndices.push({});
- indexerFuncs.push(indexFreeFormValue);
- filterFuncs.push(
- getFreeFormFilterFunc(lookupIndices[lookupIndices.length-1]));
- }
- else if (filterCols[i].ftype === c.FILTER_CHECK_BOX) {
- temp = [];
- for(var j=0, jlen=filterCols[i].foptions.length; j<jlen; j++) {
- temp.push([]);
- }
- lookupIndices.push(temp);
- indexerFuncs.push(indexDiscreteValue);
- filterFuncs.push(
- getDiscreteFilterFunc(lookupIndices[lookupIndices.length-1]));
- }
- }
-
- return filterFuncs;
- }
-
- /**
- * Helper function that extracts the values of free form columns from
- * the lookupIndex and injects them into the Column object as FilterOpt
- * objects.
- **/
- function setFreeFormFilterOptions(filterCols, lookupIndices) {
- var temp, k;
- for(var i=0, len=filterCols.length; i<len; i++) {
- if (filterCols[i].ftype === c.FILTER_FREE_FORM) {
- temp = []
- for(k in lookupIndices[i]) {
- if (lookupIndices[i].hasOwnProperty(k)) {
- temp.push(new FilterOpt(k, lookupIndices[i][k].length));
- }
- }
- filterCols[i].setFilterOptions(temp);
- }
- }
- }
-
- /**
- * Index a discrete column (column with fixed number of values).
- *
- **/
- function indexDiscreteValue(lookupIndex, col, dataVal, dataRowIndex) {
- var i = col.indexOfOptVal(dataVal);
- lookupIndex[i].push(dataRowIndex);
- }
-
- /**
- * Index a column with free form text (= not fixed upfront)
- *
- **/
- function indexFreeFormValue(lookupIndex, col, dataVal, dataRowIndex) {
- if (!lookupIndex[dataVal]) {
- lookupIndex[dataVal] = [];
- }
- lookupIndex[dataVal].push(dataRowIndex);
- }
-
-
- /**
- * Get the function to filter a column with the given lookup index
- * for discrete (fixed upfront) values.
- *
- **/
- function getDiscreteFilterFunc(lookupIndex) {
- return function(filterVal) {
- var result = [];
- for(var i=0, len=lookupIndex.length; i < len; i++) {
- if (filterVal[i]) {
- // append the indices to the current array
- result.push.apply(result, lookupIndex[i]);
- }
- }
- return { nofilter: false, records: result };
- };
- }
-
- /**
- * Get the function to filter a column with the given lookup index
- * for free form values.
- *
- **/
- function getFreeFormFilterFunc(lookupIndex) {
- return function(filterVal) {
- filterVal = filterVal.trim();
- if (filterVal === '') {
- return { nofilter: true };
- }
- return {
- nofilter: false,
- records: lookupIndex[filterVal] || []
- };
- };
- }
-
- /**
- * Filters the data based on the given filterColumns and
- * corresponding filter values.
- *
- * @return {[]} Subset of the input dataset based on the
- * filter values.
- **/
- function filterData(data, filterFuncs, filterVals) {
- var recordSets = [];
- var filterResult;
-
- // run through all the filters
- for(var i=0, len=filterFuncs.length; i<len; i++) {
- filterResult = filterFuncs[i](filterVals[i]);
- if (!filterResult.nofilter) {
- recordSets.push(filterResult.records);
- }
- }
-
- // If there are no restrictions then return the whole dataset.
- if (recordSets.length === 0) {
- return data;
- }
-
- // intersect the records returned by filters.
- var targets = intersectArrs(recordSets);
- var result = [];
- for(var i=0, len=targets.length; i<len; i++) {
- result.push(data[targets[i]]);
- }
-
- return result;
- }
-
- /**
- * Creates an object where the keys are the elements of the input array
- * and the values are true. To be used for set operations with integer.
- **/
- function arrToObj(arr) {
- var o = {};
- var i,len;
- for(i=0, len=arr.length; i<len; i++) {
- o[arr[i]] = true;
- }
- return o;
- }
-
- /**
- * Converts the keys of an object to an array after converting
- * each key to integer. To be used for set operations with integers.
- **/
- function objToArr(obj) {
- var result = [];
- for(var k in obj) {
- if (obj.hasOwnProperty(k)) {
- result.push(parseInt(k));
- }
- }
- return result;
- }
-
- /**
- * Find the intersection of a set of arrays.
- **/
- function intersectArrs(sets) {
- var temp, obj;
-
- if (sets.length === 1) {
- return sets[0];
- }
-
- // sort by size and load the smallest into the object
- sets.sort(function(a,b) { return a.length - b.length; });
- obj = arrToObj(sets[0]);
-
- // shrink the hash as we fail to find elements in the other sets
- for(var i=1, len=sets.length; i<len; i++) {
- temp = arrToObj(sets[i]);
- for(var k in obj) {
- if (obj.hasOwnProperty(k) && !temp[k]) {
- delete obj[k];
- }
- }
- }
-
- return objToArr(obj);
- }
-
- /**
- * Extract the column values from an ImagePair (contained in the server
- * response) into filter and data columns.
- *
- * @return {[]} Array of data contained in one data row.
- **/
- function getColValues(imagePair, filterCols, otherCols) {
- var result = [];
- for(var i=0, len=filterCols.length; i<len; i++) {
- result.push(imagePair.extraColumns[filterCols[i].key]);
- }
-
- for(var i=0, len=otherCols.length; i<len; i++) {
- result.push(get_robust(imagePair, ['expectations', otherCols[i].key]));
- }
-
- return result;
- }
-
- /**
- * Extract the image meta data from an Image pair returned by the server.
- **/
- function getImageValues(imagePair, imageCols) {
- var result=[];
- var url, value, percent, diff;
- var CO = c.IMG_COL_ORDER;
-
- for(var i=0, len=imageCols.length; i<len; i++) {
- percent = get_robust(imagePair, CO[i].percentField);
- value = get_robust(imagePair, CO[i].valueField);
- url = get_robust(imagePair, CO[i].urlField);
- if (url) {
- url = imageCols[i].baseUrl + url;
- }
- result.push(new ImgVal(url, percent, value));
- }
-
- return result;
- }
-
- /**
- * Given an object find sub objects for the given index without
- * throwing an error if any of the sub objects do not exist.
- **/
- function get_robust(obj, idx) {
- if (!idx) {
- return;
- }
-
- for(var i=0, len=idx.length; i<len; i++) {
- if ((typeof obj === 'undefined') || (!idx[i])) {
- return; // returns 'undefined'
- }
-
- obj = obj[idx[i]];
- }
-
- return obj;
- }
-
- /**
- * Set all elements in the array to the given value.
- **/
- function setArrVals(arr, newVal) {
- for(var i=0, len=arr.length; i<len; i++) {
- arr[i] = newVal;
- }
- }
-
- /**
- * Toggle the elements of a boolean array.
- *
- **/
- function toggleArrVals(arr) {
- for(var i=0, len=arr.length; i<len; i++) {
- arr[i] = !arr[i];
- }
- }
-
- /**
- * Sort the array of DataRow instances with the given compare functions
- * and the column at the given index either in ascending or descending order.
- **/
- function sortData (allData, compareFunctions, sortByIdx, sortOrderAsc) {
- var cmpFn = compareFunctions[sortByIdx];
- var useCmp = cmpFn;
- if (!sortOrderAsc) {
- useCmp = function ( _ ) {
- return -cmpFn.apply(this, arguments);
- };
- }
- allData.sort(useCmp);
- }
-
-
- // ***************************** Services *********************************
-
- /**
- * Encapsulates all interactions with the backend by handling
- * Urls and HTTP requests. Also exposes some utility functions
- * related to processing Urls.
- */
- app.factory('dataService', [ '$http', function ($http) {
- /** Backend related constants **/
- var c = {
- /** Url to retrieve failures */
- FAILURES: '/results/failures',
-
- /** Url to retrieve all GM results */
- ALL: '/results/all'
- };
-
- /**
- * Convenience function to retrieve all results.
- *
- * @return {Promise} Will resolve to either the data (success) or to
- * the HTTP response (error).
- **/
- function loadAll() {
- return httpGetData(c.ALL);
- }
-
- /**
- * Make a HTTP get request with the given query parameters.
- *
- * @param {}
- * @param {}
- *
- * @return {}
- **/
- function httpGetData(url, queryParams) {
- var reqConfig = {
- method: 'GET',
- url: url,
- params: queryParams
- };
-
- return $http(reqConfig).then(
- function(successResp) {
- return successResp.data;
- });
- }
-
- /**
- * Takes an arbitrary number of objects and generates a Url encoded
- * query string.
- *
- **/
- function getQueryString( _params_ ) {
- var result = [];
- for(var i=0, len=arguments.length; i < len; i++) {
- if (arguments[i]) {
- for(var k in arguments[i]) {
- if (arguments[i].hasOwnProperty(k)) {
- result.push(encodeURIComponent(k) + '=' +
- encodeURIComponent(arguments[i][k]));
- }
- }
- }
- }
- return result.join("&");
- }
-
- // Interface of the service:
- return {
- getQueryString: getQueryString,
- loadAll: loadAll
- };
-
- }]);
-
-})();
diff --git a/gm/rebaseline_server/static/new/new-index.html b/gm/rebaseline_server/static/new/new-index.html
deleted file mode 100644
index b7067f19dd..0000000000
--- a/gm/rebaseline_server/static/new/new-index.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" ng-app="rbtApp">
-
-<head>
- <meta name="viewport" content="width=device-width">
- <meta charset="utf-8">
- <title>Rebaseline Tool</title>
- <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
- <link rel="stylesheet" href="css/app.css">
-</head>
-<body>
-
-
- <div class="container-fluid">
- <div class="pull-right">
- Instructions, roadmap, etc. are at <a href="http://goo.gl/CqeVHq" target="_blank">http://goo.gl/CqeVHq</a>
- </div>
- </div>
-
- <!-- Include the different views here.
- Make everything fluid to scale to the maximum size of any screen. -->
- <div class="container-fluid">
- <div ng-view></div>
- </div>
-
- <!-- do everything local right now: Move to CDN fix when it's a performance issue -->
- <script src="bower_components/angular/angular.js"></script>
- <script src="bower_components/angular-route/angular-route.js"></script>
-
- <!-- Local includes external libs -->
- <script src="bower_components/angular-bootstrap/ui-bootstrap.js"></script>
- <script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>
-
- <!-- Local JS -->
- <script src="js/app.js"></script>
-</body>
-</html>
diff --git a/gm/rebaseline_server/static/new/partials/index-view.html b/gm/rebaseline_server/static/new/partials/index-view.html
deleted file mode 100644
index 72db231d08..0000000000
--- a/gm/rebaseline_server/static/new/partials/index-view.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<div class="container-fluid ng-cloak" ng-cloak>
- <div class="row" ng-show="state === c.ST_LOADING">
- <h4>Loading ...</h4>
- </div>
-
- <div class="row" ng-show="state === c.ST_READY">
- <h4>GM Expectations vs Actuals:</h4>
- <ul>
- <li><a href="#/view?{{ qStr({ resultsToLoad: c.RESULTS_FAILURES }) }}">Failures</a></li>
- <li><a href="#/view?{{ qStr({ resultsToLoad: c.RESULTS_ALL }) }}">All</a></li>
- </ul>
-
- <h4>Rendered SKPs:</h4>
- <ul>
- <li ng-repeat="oneSKP in allSKPs">
- <a href="#/view?{{ qStr(oneSKP.params) }}">
- {{oneSKP.title}}
- </a>
- </li>
- </ul>
- </div>
-</div>
diff --git a/gm/rebaseline_server/static/new/partials/rebaseline-view.html b/gm/rebaseline_server/static/new/partials/rebaseline-view.html
deleted file mode 100644
index a2c28f7357..0000000000
--- a/gm/rebaseline_server/static/new/partials/rebaseline-view.html
+++ /dev/null
@@ -1,207 +0,0 @@
-<div class="container-fluid ng-cloak" ng-cloak>
-
- <div class="row" ng-show="state === c.ST_LOADING">
- <h4>Loading ...</h4>
- </div>
-
- <div class="row" ng-show="state === c.ST_STILL_LOADING">
- <h4>Still loading from backend.</h4>
- <div>
- Load time so far: {{ loadTime | number:0 }} s.
- </div>
- </div>
-
- <div class="row" ng-show="state === c.ST_READY">
- <tabset>
- <tab heading="Unfiled">
- <!-- settings -->
- <div class="container controlBox">
- <form class="form-inline settingsForm" novalidate >
- <legend class="simpleLegend">Settings</legend>
- <div class="checkbox formPadding">
- <label>
- <input type="checkbox"
- ng-model="settings.showThumbnails">Show thumbnails
- </label>
- </div>
-
- <div class="checkbox formPadding">
- <label>
- <input type="checkbox"
- ng-model="settings.mergeIdenticalRows"
- ng-change="mergeRowsChanged(mergeIdenticalRows)"> Merge identical rows
- </label>
- </div>
-
- <div class="form-group formPadding">
- <label for="imageWidth">Image Width</label>
- <select ng-model="settings.imageSize"
- ng-options="iSize for iSize in c.IMAGE_SIZES"
- class="form-control input-sm">
-
- </select>
- </div>
- <div class="form-group formPadding">
- <label>Max records</label>
- <select ng-model="settings.nRecords"
- ng-options="n for n in c.MAX_RECORDS"
- ng-change="maxRecordsChanged();"
- class="form-control input-sm">
- </select>
- </div>
- </form>
- <br>
-
- <form class="form settingsForm" novalidate>
- <legend class="simpleLegend">Filters</legend>
- <div class="container-fluid">
- <div class="col-lg-2 filterBox" ng-repeat="oneCol in filterCols">
- <div class="filterKey">{{ oneCol.key }}</div>
-
- <!-- If we filter this column using free-form text match... -->
- <div ng-if="oneCol.ftype === c.FILTER_FREE_FORM">
- <input type="text"
- ng-model="filterVals[$index]"
- typeahead="opt.value for opt in oneCol.foptions | filter:$viewValue"
- class="form-control input-sm">
- <br>
- <a ng-click="filterVals[$index]=''"
- ng-disabled="'' === filterVals[$index]"
- href="">
- Clear
- </a>
- </div>
-
- <!-- If we filter this column using checkboxes... -->
- <div ng-if="oneCol.ftype === c.FILTER_CHECK_BOX">
-
- <div class="checkbox" ng-repeat="oneOpt in oneCol.foptions">
- <label>
- <input type="checkbox"
- ng-model="filterVals[$parent.$index][$index]">{{oneOpt.value}} ({{ oneOpt.count }})
- </label>
- </div>
- <div>
- <a ng-click="setFilterAll($index, true)" href="">All</a> -
- <a ng-click="setFilterAll($index, False)" href="">None</a> -
- <a ng-click="setFilterToggle($index)" href="">Toggle</a>
- </div>
- </div>
- </div>
- <br>
- </div>
-
- <div class="container updateBtn">
- <button class="btn btn-success col-lg-4 pull-left"
- ng-click="filtersChanged()"
- ng-disabled="updating">
- {{ updating && 'Updating ...' || 'Update' }}
- </button>
- </div>
-
- </form>
-
- <br>
-
- <!-- Rows -->
-
- <!-- results header -->
- <div class="col-lg-12 resultsHeaderActions well">
- <div class="col-lg-6">
- <h4>Showing {{showingRecords}} of {{selectedRecords}} (of {{totalRecords}} total)</h4>
- <span ng-show="renderTime > 0">
- Rendered in {{renderTime | number:0 }} ms (filtered and sorted in {{ filterTime | number:0 }} ms).
- </span>
- <br>
- (click on the column header radio buttons to re-sort by that column)
- </div>
-
-
- <div class="col-lg-6">
- All tests shown:
- <button class="btn btn-default btn-sm" ng-click="selectAllImagePairs()">Select</button>
- <button class="btn btn-default btn-sm" ng-click="clearAllImagePairs()">Clear</button>
- <button class="btn btn-default btn-sm" ng-click="toggleAllImagePairs()">Toggle</button>
-
- <div ng-repeat="otherTab in tabs">
- <button class="btn btn-default btn-sm"
- ng-click="moveSelectedImagePairsToTab(otherTab)"
- ng-disabled="selectedImagePairs.length == 0"
- ng-show="otherTab != viewingTab">
- Move {{selectedImagePairs.length}} selected tests to {{otherTab}} tab
- </button>
- </div>
- </div>
- <br>
- </div>
-
- <!-- results -->
- <table class="table table-bordered">
- <thead>
- <tr>
- <!-- Most column headers are displayed in a common fashion... -->
- <th ng-repeat="oneCol in allCols" ng-style="{ 'min-width': getImageWidthStyle(oneCol, 20, 'auto') }">
- <a ng-class="getSortedClass('sort', $index, '')"
- ng-click="sortBy($index)"
- href=""
- class="sortableHeader">
- {{ oneCol.ctitle }}
- </a>
- </th>
- <th>
- <div class="checkbox">
- <label>
- <input type="checkbox" ng-model="allChecked" ng-change="checkAll()">All
- </label>
- </div>
- </th>
- </tr>
- </thead>
- <tbody>
- <tr ng-repeat="oneRow in data">
- <td ng-repeat="oneColVal in oneRow.dataCols">
- {{oneColVal}}
- </td>
-
- <td ng-repeat="oneCol in oneRow.imageCols" ng-if="oneRow.rowspan > 0" rowspan="{{ oneRow.rowspan }}">
- <div ng-show="oneCol.url">
- <a href="{{ oneCol.url }}" target="_blank">View Image</a><br/>
- <img ng-if="settings.showThumbnails"
- ng-style="{ width: settings.imageSize+'px' }"
- ng-src="{{ oneCol.url }}" />
- <div ng-if="oneCol.percent && oneCol.value">
- {{oneCol.percent}}% ({{ oneCol.value }})
- </div>
- </div>
- <div ng-hide="oneCol.url" style="text-align:center">
- <span ng-show="oneCol.url === null">&ndash;none&ndash;</span>
- <span ng-hide="oneCol.url === null">&nbsp;</span>
- </div>
- </td>
-
- <td ng-if="oneRow.rowspan > 0" rowspan="{{ oneRow.rowspan }}">
- <div class="checkbox">
- <input type="checkbox"
- ng-model="checkRows[$index]"
- ng-change="rowCheckChanged($index)">
- </div>
- </td>
- </tr>
- </tbody>
- </table>
-
- </div>
- </tab>
-
- <tab heading="Hidden">
- <h3>Hidden</h3>
- </tab>
-
- <tab heading="Pending Approval">
- <h3>Pending Approval</h3>
- </tab>
-
- </tabset>
-
- </div>
-</div>
diff --git a/gm/rebaseline_server/static/utils.js b/gm/rebaseline_server/static/utils.js
deleted file mode 100644
index e846b90bd6..0000000000
--- a/gm/rebaseline_server/static/utils.js
+++ /dev/null
@@ -1,12 +0,0 @@
-function make_results_header_sticky( ) {
- element = $(".results-header-actions");
- var pos = element.position();
- $(window).scroll( function() {
- var windowPos = $(window).scrollTop();
- if (windowPos > pos.top) {
- element.addClass("sticky");
- } else {
- element.removeClass("sticky");
- }
- });
-}
diff --git a/gm/rebaseline_server/static/view.css b/gm/rebaseline_server/static/view.css
deleted file mode 100644
index 80f28091c4..0000000000
--- a/gm/rebaseline_server/static/view.css
+++ /dev/null
@@ -1,104 +0,0 @@
-/* Special alert areas at the top of the page. */
-.todo-div {
- background-color: #bbffbb;
-}
-.warning-div {
- background-color: #ffbb00;
-}
-
-.tab-wrapper {
- margin-top: 10px;
-}
-
-.tab {
- display: inline-block;
- font-size: 20px;
- padding: 5px;
- border-top-left-radius: 5px;
- border-top-right-radius: 5px;
- position: relative;
-}
-
-/* Tab which has been selected. */
-.tab-true {
- background-color: #ccccff;
- border: 1px solid black;
- border-bottom-width: 0px;
- bottom: -1px;
-}
-/* All other tabs. */
-.tab-false {
- background-color: #8888ff;
- cursor: pointer;
-}
-
-.tab-false:hover {
- background-color: #aa88ff;
-}
-
-/* Spacers between tabs. */
-.tab-spacer {
- display: inline-block;
-}
-/* The main working area (connected to the selected tab). */
-.tab-main {
- background-color: #ccccff;
- border: 1px solid black;
-}
-
-.update-results-button {
- font-size: 30px;
-}
-
-/* Odd and even lines within results display. */
-.results-odd {
- background-color: #ddffdd;
-}
-.results-even {
- background-color: #ddddff;
-}
-
-.show-only-button {
- font-size: 8px;
-}
-.show-all-button {
- font-size: 8px;
-}
-
-.image-link {
- text-decoration: none;
-}
-
-.results-header {
- overflow: hidden;
- padding: 10px;
- background-color: #ccccff;
-}
-
-.results-header-actions {
- float: right;
-}
-
-.sticky {
- position: fixed;
- top: 2px;
- box-shadow: -2px 2px 5px 0 rgba(0,0,0,.45);
- background: white;
- right: 2px;
- padding: 10px;
- border: 2px solid #222;
-}
-
-.sort-desc {
- background:no-repeat left center url(data:image/gif;base64,R0lGODlhCgAKALMAAHFxcYKCgp2dnaampq+vr83NzeHh4f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAAAgAIf/8SUNDUkdCRzEwMTIAAAUwYXBwbAIgAABtbnRyUkdCIFhZWiAH2QACABkACwAaAAthY3NwQVBQTAAAAABhcHBsAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtkc2NtAAABCAAAAvJkZXNjAAAD/AAAAG9nWFlaAAAEbAAAABR3dHB0AAAEgAAAABRyWFlaAAAElAAAABRiWFlaAAAEqAAAABRyVFJDAAAEvAAAAA5jcHJ0AAAEzAAAADhjaGFkAAAFBAAAACxn/1RSQwAABLwAAAAOYlRSQwAABLwAAAAObWx1YwAAAAAAAAARAAAADGVuVVMAAAAmAAACfmVzRVMAAAAmAAABgmRhREsAAAAuAAAB6mRlREUAAAAsAAABqGZpRkkAAAAoAAAA3GZyRlUAAAAoAAABKml0SVQAAAAoAAACVm5sTkwAAAAoAAACGG5iTk8AAAAmAAABBHB0QlIAAAAmAAABgnN2U0UAAAAmAAABBGphSlAAAAAaAAABUmtvS1IAAAAWAAACQHpoVFcAAAAWAAABbHpoQ04AAAAWAAAB1HJ1UlUAAAAiAAACpHBsUEwAAAAsAAACxgBZAGwAZQBpAG4AZf8AbgAgAFIARwBCAC0AcAByAG8AZgBpAGkAbABpAEcAZQBuAGUAcgBpAHMAawAgAFIARwBCAC0AcAByAG8AZgBpAGwAUAByAG8AZgBpAGwAIABHAOkAbgDpAHIAaQBxAHUAZQAgAFIAVgBCTgCCLAAgAFIARwBCACAw1zDtMNUwoTCkMOuQGnUoACAAUgBHAEIAIIJyX2ljz4/wAFAAZQByAGYAaQBsACAAUgBHAEIAIABHAGUAbgDpAHIAaQBjAG8AQQBsAGwAZwBlAG0AZQBpAG4AZQBzACAAUgBHAEIALQBQAHIAbwBmAGkAbGZukBoAIABSAEcAQgAgY8+P8GX/h072AEcAZQBuAGUAcgBlAGwAIABSAEcAQgAtAGIAZQBzAGsAcgBpAHYAZQBsAHMAZQBBAGwAZwBlAG0AZQBlAG4AIABSAEcAQgAtAHAAcgBvAGYAaQBlAGzHfLwYACAAUgBHAEIAINUEuFzTDMd8AFAAcgBvAGYAaQBsAG8AIABSAEcAQgAgAEcAZQBuAGUAcgBpAGMAbwBHAGUAbgBlAHIAaQBjACAAUgBHAEIAIABQAHIAbwBmAGkAbABlBB4EMQRJBDgEOQAgBD8EQAQ+BEQEOAQ7BEwAIABSAEcAQgBVAG4AaQB3AGUAcgBzAGEAbABuAHkAIABwAHIAbwBm/wBpAGwAIABSAEcAQgAAZGVzYwAAAAAAAAAUR2VuZXJpYyBSR0IgUHJvZmlsZQAAAAAAAAAAAAAAFEdlbmVyaWMgUkdCIFByb2ZpbGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABadQAArHMAABc0WFlaIAAAAAAAAPNSAAEAAAABFs9YWVogAAAAAAAAdE0AAD3uAAAD0FhZWiAAAAAAAAAoGgAAFZ8AALg2Y3VydgAAAAAAAAABAc0AAHRleHQAAAAAQ29weXJpZ2h0IDIwMDcgQXBwbGUgSW5jLkMsIGFsbCByaWdodHMgcmVzZXJ2ZWQuAHNmMzIAAAAAAAEMQgAABd7///MmAAAHkgAA/ZH///ui///9owAAA9wAAMBsACwAAAAACgAKAAAEJZAMIcakQZjNtyhFxwEIIRofAookUnapu26t+6KFLYe1TgQ5VwQAOw%3D%3D);
-}
-
-.sort-asc {
- background:no-repeat left center url(data:image/gif;base64,R0lGODlhCgAKALMAAHFxcYKCgp2dnaampq+vr83NzeHh4f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAAAgAIf/8SUNDUkdCRzEwMTIAAAUwYXBwbAIgAABtbnRyUkdCIFhZWiAH2QACABkACwAaAAthY3NwQVBQTAAAAABhcHBsAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtkc2NtAAABCAAAAvJkZXNjAAAD/AAAAG9nWFlaAAAEbAAAABR3dHB0AAAEgAAAABRyWFlaAAAElAAAABRiWFlaAAAEqAAAABRyVFJDAAAEvAAAAA5jcHJ0AAAEzAAAADhjaGFkAAAFBAAAACxn/1RSQwAABLwAAAAOYlRSQwAABLwAAAAObWx1YwAAAAAAAAARAAAADGVuVVMAAAAmAAACfmVzRVMAAAAmAAABgmRhREsAAAAuAAAB6mRlREUAAAAsAAABqGZpRkkAAAAoAAAA3GZyRlUAAAAoAAABKml0SVQAAAAoAAACVm5sTkwAAAAoAAACGG5iTk8AAAAmAAABBHB0QlIAAAAmAAABgnN2U0UAAAAmAAABBGphSlAAAAAaAAABUmtvS1IAAAAWAAACQHpoVFcAAAAWAAABbHpoQ04AAAAWAAAB1HJ1UlUAAAAiAAACpHBsUEwAAAAsAAACxgBZAGwAZQBpAG4AZf8AbgAgAFIARwBCAC0AcAByAG8AZgBpAGkAbABpAEcAZQBuAGUAcgBpAHMAawAgAFIARwBCAC0AcAByAG8AZgBpAGwAUAByAG8AZgBpAGwAIABHAOkAbgDpAHIAaQBxAHUAZQAgAFIAVgBCTgCCLAAgAFIARwBCACAw1zDtMNUwoTCkMOuQGnUoACAAUgBHAEIAIIJyX2ljz4/wAFAAZQByAGYAaQBsACAAUgBHAEIAIABHAGUAbgDpAHIAaQBjAG8AQQBsAGwAZwBlAG0AZQBpAG4AZQBzACAAUgBHAEIALQBQAHIAbwBmAGkAbGZukBoAIABSAEcAQgAgY8+P8GX/h072AEcAZQBuAGUAcgBlAGwAIABSAEcAQgAtAGIAZQBzAGsAcgBpAHYAZQBsAHMAZQBBAGwAZwBlAG0AZQBlAG4AIABSAEcAQgAtAHAAcgBvAGYAaQBlAGzHfLwYACAAUgBHAEIAINUEuFzTDMd8AFAAcgBvAGYAaQBsAG8AIABSAEcAQgAgAEcAZQBuAGUAcgBpAGMAbwBHAGUAbgBlAHIAaQBjACAAUgBHAEIAIABQAHIAbwBmAGkAbABlBB4EMQRJBDgEOQAgBD8EQAQ+BEQEOAQ7BEwAIABSAEcAQgBVAG4AaQB3AGUAcgBzAGEAbABuAHkAIABwAHIAbwBm/wBpAGwAIABSAEcAQgAAZGVzYwAAAAAAAAAUR2VuZXJpYyBSR0IgUHJvZmlsZQAAAAAAAAAAAAAAFEdlbmVyaWMgUkdCIFByb2ZpbGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABadQAArHMAABc0WFlaIAAAAAAAAPNSAAEAAAABFs9YWVogAAAAAAAAdE0AAD3uAAAD0FhZWiAAAAAAAAAoGgAAFZ8AALg2Y3VydgAAAAAAAAABAc0AAHRleHQAAAAAQ29weXJpZ2h0IDIwMDcgQXBwbGUgSW5jLkMsIGFsbCByaWdodHMgcmVzZXJ2ZWQuAHNmMzIAAAAAAAEMQgAABd7///MmAAAHkgAA/ZH///ui///9owAAA9wAAMBsACwAAAAACgAKAAAEJRBJREKZsxQDsCSGIVzZFnYTGIqktp7fG46uzAn2TAyCMPC9QAQAOw%3D%3D);
-}
-
-.sortable-header {
- padding-right: 3px;
- padding-left: 13px;
- margin-left: 4px;
-}
diff --git a/gm/rebaseline_server/static/view.html b/gm/rebaseline_server/static/view.html
deleted file mode 100644
index f6ebf5a9a4..0000000000
--- a/gm/rebaseline_server/static/view.html
+++ /dev/null
@@ -1,417 +0,0 @@
-<!DOCTYPE html>
-
-<html ng-app="Loader" ng-controller="Loader.Controller">
-
-<head>
- <title ng-bind="windowTitle"></title>
- <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
- <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.js"></script>
- <script src="constants.js"></script>
- <script src="loader.js"></script>
- <script src="utils.js"></script>
- <link rel="stylesheet" href="view.css">
-</head>
-
-<body>
- <h2>
- Instructions, roadmap, etc. are at
- <a href="http://tinyurl.com/SkiaRebaselineServer">
- http://tinyurl.com/SkiaRebaselineServer
- </a>
- </h2>
-
- <em ng-show="!readyToDisplay">
- Loading results from <a href="{{resultsToLoad}}">{{resultsToLoad}}</a> ...
- {{loadingMessage}}
- </em>
-
- <div ng-show="readyToDisplay">
-
- <div class="warning-div"
- ng-show="urlSchemaVersionLoaded != constants.URL_VALUE__SCHEMA_VERSION__CURRENT">
- WARNING! The URL you loaded used schema version {{urlSchemaVersionLoaded}}, rather than
- the most recent version {{constants.URL_VALUE__SCHEMA_VERSION__CURRENT}}. It has been
- converted to the most recent version on a best-effort basis; you may wish to double-check
- which records are displayed.
- </div>
-
- <div class="warning-div"
- ng-show="header[constants.KEY__HEADER__IS_EDITABLE] && header[constants.KEY__HEADER__IS_EXPORTED]">
- WARNING! These results are editable and exported, so any user
- who can connect to this server over the network can modify them.
- </div>
-
- <div ng-show="header[constants.KEY__HEADER__TIME_UPDATED]">
- These results, from raw JSON file
- <a href="{{resultsToLoad}}">{{resultsToLoad}}</a>, current as of
- {{localTimeString(header[constants.KEY__HEADER__TIME_UPDATED])}}
- <br>
- To see other sets of results (all results, failures only, etc.),
- <a href="/">click here</a>
- </div>
-
- <div class="tab-wrapper"><!-- tabs -->
- <div class="tab-spacer" ng-repeat="tab in tabs">
- <div class="tab tab-{{tab == viewingTab}}"
- ng-click="setViewingTab(tab)">
- &nbsp;{{tab}} ({{numResultsPerTab[tab]}})&nbsp;
- </div>
- <div class="tab-spacer">
- &nbsp;
- </div>
- </div>
- </div><!-- tabs -->
-
- <div class="tab-main"><!-- main display area of selected tab -->
-
- <br>
- <!-- We only show the filters/settings table on the Unfiled tab. -->
- <table ng-show="viewingTab == defaultTab" border="1">
- <tr>
- <th colspan="4">
- Filters
- </th>
- <th>
- Settings
- </th>
- </tr>
- <tr valign="top">
-
- <!-- filters -->
- <td ng-repeat="columnName in orderedColumnNames">
-
- <!-- Only display filterable columns here... -->
- <div ng-if="extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__IS_FILTERABLE]">
- {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}}<br>
-
- <!-- If we filter this column using free-form text match... -->
- <div ng-if="extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER]">
- <input type="text"
- ng-model="columnStringMatch[columnName]"
- ng-change="setUpdatesPending(true)"/>
- <br>
- <button ng-click="setColumnStringMatch(columnName, '')"
- ng-disabled="('' == columnStringMatch[columnName])">
- clear (show all)
- </button>
- </div>
-
- <!-- If we filter this column using checkboxes... -->
- <div ng-if="!extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER]">
- <label ng-repeat="valueAndCount in extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS]">
- <input type="checkbox"
- name="resultTypes"
- value="{{valueAndCount[0]}}"
- ng-checked="isValueInSet(valueAndCount[0], showingColumnValues[columnName])"
- ng-click="toggleValueInSet(valueAndCount[0], showingColumnValues[columnName]); setUpdatesPending(true)">
- {{valueAndCount[0]}} ({{valueAndCount[1]}})<br>
- </label>
- <button ng-click="showingColumnValues[columnName] = {}; toggleValuesInSet(allColumnValues[columnName], showingColumnValues[columnName]); updateResults()"
- ng-disabled="!readyToDisplay || allColumnValues[columnName].length == setSize(showingColumnValues[columnName])">
- all
- </button>
- <button ng-click="showingColumnValues[columnName] = {}; updateResults()"
- ng-disabled="!readyToDisplay || 0 == setSize(showingColumnValues[columnName])">
- none
- </button>
- <button ng-click="toggleValuesInSet(allColumnValues[columnName], showingColumnValues[columnName]); updateResults()">
- toggle
- </button>
- </div>
-
- </div>
- </td>
-
- <!-- settings -->
- <td><table>
- <tr><td>
- <input type="checkbox" ng-model="showThumbnailsPending"
- ng-init="showThumbnailsPending = true"
- ng-change="areUpdatesPending = true"/>
- Show thumbnails
- </td></tr>
- <tr><td>
- <input type="checkbox" ng-model="mergeIdenticalRowsPending"
- ng-init="mergeIdenticalRowsPending = true"
- ng-change="areUpdatesPending = true"/>
- Merge identical rows
- </td></tr>
- <tr><td>
- Image width
- <input type="text" ng-model="imageSizePending"
- ng-init="imageSizePending=100"
- ng-change="areUpdatesPending = true"
- maxlength="4"/>
- </td></tr>
- <tr><td>
- Max records to display
- <input type="text" ng-model="displayLimitPending"
- ng-init="displayLimitPending=50"
- ng-change="areUpdatesPending = true"
- maxlength="4"/>
- </td></tr>
- <tr><td>
- <button class="update-results-button"
- ng-click="updateResults()"
- ng-disabled="!areUpdatesPending">
- Update Results
- </button>
- </td></tr>
- </tr></table></td>
- </tr>
- </table>
-
- <p>
-
- <!-- Submission UI that we only show in the Pending Approval tab. -->
- <div ng-show="'Pending Approval' == viewingTab">
- <div style="display:inline-block">
- <button style="font-size:20px"
- ng-click="submitApprovals(filteredImagePairs)"
- ng-disabled="submitPending || (filteredImagePairs.length == 0)">
- Update these {{filteredImagePairs.length}} expectations on the server
- </button>
- </div>
- <div style="display:inline-block">
- <div style="font-size:20px"
- ng-show="submitPending">
- Submitting, please wait...
- </div>
- </div>
- <div>
- Advanced settings...
- <input type="checkbox" ng-model="showSubmitAdvancedSettings">
- show
- <ul ng-show="showSubmitAdvancedSettings">
- <li ng-repeat="setting in [constants.KEY__EXPECTATIONS__REVIEWED, constants.KEY__EXPECTATIONS__IGNOREFAILURE]">
- {{setting}}
- <input type="checkbox" ng-model="submitAdvancedSettings[setting]">
- </li>
- <li ng-repeat="setting in ['bug']">
- {{setting}}
- <input type="text" ng-model="submitAdvancedSettings[setting]">
- </li>
- </ul>
- </div>
- </div>
-
- <p>
-
- <div class="results-header"> <!-- results header -->
- <div class="results-header-actions">
- all tests shown:
- <button ng-click="selectAllImagePairs()">
- select
- </button>
- <button ng-click="clearAllImagePairs()">
- clear
- </button>
- <button ng-click="toggleAllImagePairs()">
- toggle
- </button>
- <div ng-repeat="otherTab in tabs">
- <button ng-click="moveSelectedImagePairsToTab(otherTab)"
- ng-disabled="selectedImagePairs.length == 0"
- ng-show="otherTab != viewingTab">
- move {{selectedImagePairs.length}} selected tests to {{otherTab}} tab
- </button>
- </div>
- </div>
- <div class="results-header-stats">
- Found {{filteredImagePairs.length}} matches;
- <span ng-show="filteredImagePairs.length > limitedImagePairs.length">
- displaying the first {{limitedImagePairs.length}}.
- </span>
- <span ng-show="filteredImagePairs.length <= limitedImagePairs.length">
- displaying them all.
- </span>
- <span ng-show="renderEndTime > renderStartTime">
- Rendered in {{(renderEndTime - renderStartTime).toFixed(0)}} ms.
- </span>
- <br>
- (click on the column header radio buttons to re-sort by that column)
- </div>
- </div> <!-- results header -->
-
- <table border="0"><tr><td> <!-- table holding results header + results table -->
- </td></tr><tr><td>
- <table border="1"> <!-- results -->
- <tr>
- <!-- Most column headers are displayed in a common fashion... -->
- <th ng-repeat="columnName in orderedColumnNames">
- <a ng-class="'sort-' + sortedByColumnsCls(columnName)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXTRACOLUMNS, columnName)"
- href=""
- class="sortable-header">
- {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}}
- </a>
- </th>
-
- <!-- ... but there are a few columns where we display things differently. -->
- <th>
- <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__EXPECTATIONS__BUGS)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXPECTATIONS, constants.KEY__EXPECTATIONS__BUGS)"
- href=""
- class="sortable-header">
- bugs
- </a>
- </th>
- <th width="{{imageSize}}">
- <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__IMAGEPAIRS__IMAGE_A_URL)"
- ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_A_URL)"
- href=""
- class="sortable-header">
- {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
- </a>
- </th>
- <th width="{{imageSize}}">
- <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__IMAGEPAIRS__IMAGE_B_URL)"
- ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_B_URL)"
- href=""
- class="sortable-header">
- {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
- </a>
- </th>
- <th width="{{imageSize}}">
- <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)"
- href=""
- class="sortable-header">
- differing pixels in white
- </a>
- </th>
- <th width="{{imageSize}}">
- <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)"
- href=""
- class="sortable-header">
- perceptual difference
- </a>
- <br>
- <input type="range" ng-model="pixelDiffBgColorBrightness"
- ng-init="pixelDiffBgColorBrightness=64; pixelDiffBgColor=brightnessStringToHexColor(pixelDiffBgColorBrightness)"
- ng-change="pixelDiffBgColor=brightnessStringToHexColor(pixelDiffBgColorBrightness)"
- title="image background brightness"
- min="0" max="255"/>
- </th>
- <th>
- <!-- imagepair-selection checkbox column -->
- </th>
- </tr>
-
- <tr ng-repeat="imagePair in limitedImagePairs" valign="top"
- ng-class-odd="'results-odd'" ng-class-even="'results-even'"
- results-updated-callback-directive>
-
- <td ng-repeat="columnName in orderedColumnNames">
- {{imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS][columnName]}}
- <br>
- <button class="show-only-button"
- ng-show="viewingTab == defaultTab"
- ng-disabled="1 == setSize(showingColumnValues[columnName])"
- ng-click="showOnlyColumnValue(columnName, imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS][columnName])"
- title="show only results of {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}} {{imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS][columnName]}}">
- show only
- </button>
- <br>
- <button class="show-all-button"
- ng-show="viewingTab == defaultTab"
- ng-disabled="allColumnValues[columnName].length == setSize(showingColumnValues[columnName])"
- ng-click="showAllColumnValues(columnName)"
- title="show results of all {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}}s">
- show all
- </button>
- </td>
-
- <!-- bugs -->
- <td>
- <a ng-repeat="bug in imagePair[constants.KEY__IMAGEPAIRS__EXPECTATIONS][constants.KEY__EXPECTATIONS__BUGS]"
- href="https://code.google.com/p/skia/issues/detail?id={{bug}}"
- target="_blank">
- {{bug}}
- </a>
- </td>
-
- <!-- image A -->
- <td width="{{imageSize}}" ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}">
- <div ng-if="imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] != null">
- <a href="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL]}}" target="_blank">View Image</a><br/>
- <img ng-if="showThumbnails"
- width="{{imageSize}}"
- ng-src="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL]}}" />
- </div>
- <div ng-show="imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] == null"
- style="text-align:center">
- &ndash;none&ndash;
- </div>
- </td>
-
- <!-- image B -->
- <td width="{{imageSize}}" ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}">
- <div ng-if="imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL] != null">
- <a href="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]}}" target="_blank">View Image</a><br/>
- <img ng-if="showThumbnails"
- width="{{imageSize}}"
- ng-src="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]}}" />
- </div>
- <div ng-show="imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL] == null"
- style="text-align:center">
- &ndash;none&ndash;
- </div>
- </td>
-
- <!-- whitediffs: every differing pixel shown in white -->
- <td width="{{imageSize}}" ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}">
- <div ng-if="imagePair[constants.KEY__IMAGEPAIRS__IS_DIFFERENT]"
- title="{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__NUM_DIFF_PIXELS] | number:0}} of {{(100 * imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__NUM_DIFF_PIXELS] / imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS]) | number:0}} pixels ({{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS].toFixed(4)}}%) differ from expectation.">
-
- <a href="{{imageSets[constants.KEY__IMAGESETS__SET__WHITEDIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__WHITE_DIFF_URL]}}" target="_blank">View Image</a><br/>
- <img ng-if="showThumbnails"
- width="{{imageSize}}"
- ng-src="{{imageSets[constants.KEY__IMAGESETS__SET__WHITEDIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__WHITE_DIFF_URL]}}" />
- <br/>
- {{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS].toFixed(4)}}%
- ({{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__NUM_DIFF_PIXELS]}})
- </div>
- <div ng-show="!imagePair[constants.KEY__IMAGEPAIRS__IS_DIFFERENT]"
- style="text-align:center">
- &ndash;none&ndash;
- </div>
- </td>
-
- <!-- diffs: per-channel RGB deltas -->
- <td width="{{imageSize}}" ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}">
- <div ng-if="imagePair[constants.KEY__IMAGEPAIRS__IS_DIFFERENT]"
- title="Perceptual difference measure is {{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF].toFixed(4)}}%. Maximum difference per channel: R={{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL][0]}}, G={{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL][1]}}, B={{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL][2]}}">
-
- <a href="{{imageSets[constants.KEY__IMAGESETS__SET__DIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__DIFF_URL]}}" target="_blank">View Image</a><br/>
- <img ng-if="showThumbnails"
- ng-style="{backgroundColor: pixelDiffBgColor}"
- width="{{imageSize}}"
- ng-src="{{imageSets[constants.KEY__IMAGESETS__SET__DIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__DIFF_URL]}}" />
- <br/>
- {{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF].toFixed(4)}}%
- {{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL]}}
- </div>
- <div ng-show="!imagePair[constants.KEY__IMAGEPAIRS__IS_DIFFERENT]"
- style="text-align:center">
- &ndash;none&ndash;
- </div>
- </td>
-
- <td ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}">
- <br/>
- <input type="checkbox"
- name="rowSelect"
- value="{{imagePair.index}}"
- ng-checked="isValueInArray(imagePair.index, selectedImagePairs)"
- ng-click="toggleSomeImagePairs($index, imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN])">
- </tr>
- </table> <!-- imagePairs -->
- </td></tr></table> <!-- table holding results header + imagePairs table -->
-
- </div><!-- main display area of selected tab -->
- </div><!-- everything: hide until readyToDisplay -->
-
-</body>
-</html>
diff --git a/gm/rebaseline_server/test_all.py b/gm/rebaseline_server/test_all.py
deleted file mode 100755
index 282ec85732..0000000000
--- a/gm/rebaseline_server/test_all.py
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Run all unittests within this directory tree, recursing into subdirectories.
-"""
-
-import os
-import unittest
-
-
-def main():
- suite = unittest.TestLoader().discover(os.path.dirname(__file__),
- pattern='*_test.py')
- results = unittest.TextTestRunner(verbosity=2).run(suite)
- print repr(results)
- if not results.wasSuccessful():
- raise Exception('failed one or more unittests')
-
-if __name__ == '__main__':
- main()
diff --git a/gm/rebaseline_server/testdata/.gitattributes b/gm/rebaseline_server/testdata/.gitattributes
deleted file mode 100644
index 3606445cad..0000000000
--- a/gm/rebaseline_server/testdata/.gitattributes
+++ /dev/null
@@ -1,2 +0,0 @@
-# All self-test PNG files are fake (human-readable, diffable plaintext files).
-*.png text diff -binary
diff --git a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/3x3bitmaprect/16998423976396106083.png b/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/3x3bitmaprect/16998423976396106083.png
deleted file mode 100644
index d3686ff12d..0000000000
--- a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/3x3bitmaprect/16998423976396106083.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/3x3bitmaprect/16998423976396106083.png
diff --git a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png b/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png
deleted file mode 100644
index 656275a920..0000000000
--- a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png
diff --git a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/aaclip/14456211900777561488.png b/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/aaclip/14456211900777561488.png
deleted file mode 100644
index 371a172ece..0000000000
--- a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/aaclip/14456211900777561488.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/aaclip/14456211900777561488.png
diff --git a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/aaclip/6190901827590820995.png b/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/aaclip/6190901827590820995.png
deleted file mode 100644
index 8a01aa825f..0000000000
--- a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/aaclip/6190901827590820995.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/aaclip/6190901827590820995.png
diff --git a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bigblurs/17309852422285247848.png b/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bigblurs/17309852422285247848.png
deleted file mode 100644
index 2d78e89be3..0000000000
--- a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bigblurs/17309852422285247848.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/bigblurs/17309852422285247848.png
diff --git a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bigblurs/2422083043229439955.png b/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bigblurs/2422083043229439955.png
deleted file mode 100644
index 8d0646720a..0000000000
--- a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bigblurs/2422083043229439955.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/bigblurs/2422083043229439955.png
diff --git a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bitmapsource/16289727936158057543.png b/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bitmapsource/16289727936158057543.png
deleted file mode 100644
index 3c511d5f6a..0000000000
--- a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bitmapsource/16289727936158057543.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/bitmapsource/16289727936158057543.png
diff --git a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bitmapsource/17503582803589749280.png b/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bitmapsource/17503582803589749280.png
deleted file mode 100644
index d2df08ca3a..0000000000
--- a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/bitmapsource/17503582803589749280.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/bitmapsource/17503582803589749280.png
diff --git a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_192_192/3154864687054945306.png b/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_192_192/3154864687054945306.png
deleted file mode 100644
index 9364ccdd8a..0000000000
--- a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_192_192/3154864687054945306.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/filterbitmap_checkerboard_192_192/3154864687054945306.png
diff --git a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_192_192/4719210487426381700.png b/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_192_192/4719210487426381700.png
deleted file mode 100644
index 5c91d33e15..0000000000
--- a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_192_192/4719210487426381700.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/filterbitmap_checkerboard_192_192/4719210487426381700.png
diff --git a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_32_2/15528304435129737588.png b/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_32_2/15528304435129737588.png
deleted file mode 100644
index 3c1de492de..0000000000
--- a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_32_2/15528304435129737588.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/filterbitmap_checkerboard_32_2/15528304435129737588.png
diff --git a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_32_2/712827739969462165.png b/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_32_2/712827739969462165.png
deleted file mode 100644
index 8760be33fb..0000000000
--- a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/filterbitmap_checkerboard_32_2/712827739969462165.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/filterbitmap_checkerboard_32_2/712827739969462165.png
diff --git a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/texdata/3695033638604474475.png b/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/texdata/3695033638604474475.png
deleted file mode 100644
index fee415c72a..0000000000
--- a/gm/rebaseline_server/testdata/inputs/fake-gm-imagefiles/bitmap-64bitMD5/texdata/3695033638604474475.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/texdata/3695033638604474475.png
diff --git a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Android-GalaxyNexus-SGX540-Arm7-Release/actual-results.json b/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Android-GalaxyNexus-SGX540-Arm7-Release/actual-results.json
deleted file mode 100644
index 38ee68c7ba..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Android-GalaxyNexus-SGX540-Arm7-Release/actual-results.json
+++ /dev/null
@@ -1,97 +0,0 @@
-{
- "actual-results" : {
- "failed" : {
- "texdata_gpu.png" : [ "bitmap-64bitMD5", 3695033638604474475 ]
- },
- "failure-ignored" : {
- "filterbitmap_checkerboard_192_192_565.png" : [ "bitmap-64bitMD5", 4719210487426381700 ],
- "filterbitmap_checkerboard_192_192_8888.png" : [ "bitmap-64bitMD5", 3154864687054945306 ],
- "filterbitmap_checkerboard_32_2_565.png" : [ "bitmap-64bitMD5", 15528304435129737588 ],
- "filterbitmap_checkerboard_32_2_8888.png" : [ "bitmap-64bitMD5", 712827739969462165 ]
- },
- "no-comparison" : {
- "bigblurs_565.png" : [ "bitmap-64bitMD5", 2422083043229439955 ],
- "bigblurs_8888.png" : [ "bitmap-64bitMD5", 17309852422285247848 ],
- "bitmapsource_565.png" : [ "bitmap-64bitMD5", 17503582803589749280 ],
- "bitmapsource_8888.png" : [ "bitmap-64bitMD5", 16289727936158057543 ]
- },
- "succeeded" : {
- "3x3bitmaprect_565.png" : [ "bitmap-64bitMD5", 16998423976396106083 ],
- "3x3bitmaprect_8888.png" : [ "bitmap-64bitMD5", 2054956815327187963 ],
- "aaclip_565.png" : [ "bitmap-64bitMD5", 6190901827590820995 ],
- "aaclip_8888.png" : [ "bitmap-64bitMD5", 14456211900777561488 ]
- }
- },
- "expected-results" : {
- "3x3bitmaprect_565.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 16998423976396106083 ]
- ],
- "ignore-failure" : false
- },
- "3x3bitmaprect_8888.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 2054956815327187963 ]
- ],
- "ignore-failure" : false
- },
- "aaclip_565.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 6190901827590820995 ]
- ],
- "ignore-failure" : false
- },
- "aaclip_8888.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 14456211900777561488 ]
- ],
- "ignore-failure" : false
- },
- "bigblurs_565.png" : {
- "allowed-digests" : null,
- "ignore-failure" : false
- },
- "bigblurs_8888.png" : {
- "allowed-digests" : null,
- "ignore-failure" : false
- },
- "bitmapsource_565.png" : {
- "allowed-digests" : null,
- "ignore-failure" : false
- },
- "bitmapsource_8888.png" : {
- "allowed-digests" : null,
- "ignore-failure" : false
- },
- "filterbitmap_checkerboard_192_192_565.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 9917960313903939620 ]
- ],
- "ignore-failure" : true
- },
- "filterbitmap_checkerboard_192_192_8888.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 9917960313903939620 ]
- ],
- "ignore-failure" : true
- },
- "filterbitmap_checkerboard_32_2_565.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 16197252621792695154 ]
- ],
- "ignore-failure" : true
- },
- "filterbitmap_checkerboard_32_2_8888.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 7634650333321761866 ]
- ],
- "ignore-failure" : true
- },
- "texdata_gpu.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 2736593828543197285 ]
- ],
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Builder-We-Have-No-Expectations-File-For/actual-results.json b/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Builder-We-Have-No-Expectations-File-For/actual-results.json
deleted file mode 100644
index 0a1de74445..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Builder-We-Have-No-Expectations-File-For/actual-results.json
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- "actual-results" : {
- "failed" : null,
- "failure-ignored" : {
- "displacement_565.png" : [ "bitmap-64bitMD5", 4569468668668628191 ],
- "displacement_8888.png" : [ "bitmap-64bitMD5", 11401048196735046263 ],
- "displacement_gpu.png" : [ "bitmap-64bitMD5", 5698561127291561694 ],
- "displacement_pdf-mac.png" : [ "bitmap-64bitMD5", 12901125495691049846 ],
- "displacement_pdf-poppler.png" : [ "bitmap-64bitMD5", 16285974094717334658 ]
- },
- "no-comparison" : {
- "bigblurs_565.png" : [ "bitmap-64bitMD5", 14704206703218007573 ],
- "bigblurs_8888.png" : [ "bitmap-64bitMD5", 17309852422285247848 ],
- "bigblurs_gpu.png" : [ "bitmap-64bitMD5", 1822195599289208664 ],
- "bigblurs_pdf-mac.png" : [ "bitmap-64bitMD5", 16171608477794909861 ],
- "bigblurs_pdf-poppler.png" : [ "bitmap-64bitMD5", 6539050160610613353 ]
- },
- "succeeded" : {
- "3x3bitmaprect_565.png" : [ "bitmap-64bitMD5", 16998423976396106083 ],
- "3x3bitmaprect_8888.png" : [ "bitmap-64bitMD5", 2054956815327187963 ],
- "3x3bitmaprect_gpu.png" : [ "bitmap-64bitMD5", 2054956815327187963 ],
- "3x3bitmaprect_pdf-mac.png" : [ "bitmap-64bitMD5", 8518347971308375604 ],
- "3x3bitmaprect_pdf-poppler.png" : [ "bitmap-64bitMD5", 16723580409414313678 ]
- }
- },
- "expected-results" : {
- "3x3bitmaprect_565.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 16998423976396106083 ]
- ],
- "ignore-failure" : false
- },
- "3x3bitmaprect_8888.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 2054956815327187963 ]
- ],
- "ignore-failure" : false
- },
- "3x3bitmaprect_gpu.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 2054956815327187963 ]
- ],
- "ignore-failure" : false
- },
- "3x3bitmaprect_pdf-mac.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 8518347971308375604 ]
- ],
- "ignore-failure" : false
- },
- "3x3bitmaprect_pdf-poppler.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 16723580409414313678 ]
- ],
- "ignore-failure" : false
- },
- "displacement_565.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 16249664097236120848 ]
- ],
- "ignore-failure" : true
- },
- "displacement_8888.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 12120271618448785903 ]
- ],
- "ignore-failure" : true
- },
- "displacement_gpu.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 14033538044845358121 ]
- ],
- "ignore-failure" : true
- },
- "displacement_pdf-mac.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 10149713146651176710 ]
- ],
- "ignore-failure" : true
- },
- "displacement_pdf-poppler.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 4741823272437589681 ]
- ],
- "ignore-failure" : true
- }
- }
-}
diff --git a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/actual-results.json b/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/actual-results.json
deleted file mode 100644
index 354f439e7f..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/actual-results.json
+++ /dev/null
@@ -1,103 +0,0 @@
-{
- "actual-results" : {
- "failed" : {
- "blanket-ignored_565.png" : [ "bitmap-64bitMD5", 22222222 ],
- "blanket-ignored_8888.png" : [ "bitmap-64bitMD5", 22222222 ]
- },
- "failure-ignored" : {
- "displacement_565.png" : [ "bitmap-64bitMD5", 4569468668668628191 ],
- "displacement_8888.png" : [ "bitmap-64bitMD5", 11401048196735046263 ],
- "displacement_gpu.png" : [ "bitmap-64bitMD5", 5698561127291561694 ],
- "displacement_pdf-mac.png" : [ "bitmap-64bitMD5", 12901125495691049846 ],
- "displacement_pdf-poppler.png" : [ "bitmap-64bitMD5", 16285974094717334658 ]
- },
- "no-comparison" : {
- "bigblurs_565.png" : [ "bitmap-64bitMD5", 14704206703218007573 ],
- "bigblurs_8888.png" : [ "bitmap-64bitMD5", 17309852422285247848 ],
- "bigblurs_gpu.png" : [ "bitmap-64bitMD5", 1822195599289208664 ],
- "bigblurs_pdf-mac.png" : [ "bitmap-64bitMD5", 16171608477794909861 ],
- "bigblurs_pdf-poppler.png" : [ "bitmap-64bitMD5", 6539050160610613353 ]
- },
- "succeeded" : {
- "3x3bitmaprect_565.png" : [ "bitmap-64bitMD5", 16998423976396106083 ],
- "3x3bitmaprect_8888.png" : [ "bitmap-64bitMD5", 2054956815327187963 ],
- "3x3bitmaprect_gpu.png" : [ "bitmap-64bitMD5", 2054956815327187963 ],
- "3x3bitmaprect_pdf-mac.png" : [ "bitmap-64bitMD5", 8518347971308375604 ],
- "3x3bitmaprect_pdf-poppler.png" : [ "bitmap-64bitMD5", 16723580409414313678 ]
- }
- },
- "expected-results" : {
- "3x3bitmaprect_565.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 16998423976396106083 ]
- ],
- "ignore-failure" : false
- },
- "3x3bitmaprect_8888.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 2054956815327187963 ]
- ],
- "ignore-failure" : false
- },
- "3x3bitmaprect_gpu.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 2054956815327187963 ]
- ],
- "ignore-failure" : false
- },
- "3x3bitmaprect_pdf-mac.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 8518347971308375604 ]
- ],
- "ignore-failure" : false
- },
- "3x3bitmaprect_pdf-poppler.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 16723580409414313678 ]
- ],
- "ignore-failure" : false
- },
- "blanket-ignored_565.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 111111111 ]
- ],
- "ignore-failure" : false
- },
- "blanket-ignored_8888.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 111111111 ]
- ],
- "ignore-failure" : false
- },
- "displacement_565.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 16249664097236120848 ]
- ],
- "ignore-failure" : true
- },
- "displacement_8888.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 12120271618448785903 ]
- ],
- "ignore-failure" : true
- },
- "displacement_gpu.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 14033538044845358121 ]
- ],
- "ignore-failure" : true
- },
- "displacement_pdf-mac.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 10149713146651176710 ]
- ],
- "ignore-failure" : true
- },
- "displacement_pdf-poppler.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 4741823272437589681 ]
- ],
- "ignore-failure" : true
- }
- }
-}
diff --git a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release-Valgrind/actual-results.json b/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release-Valgrind/actual-results.json
deleted file mode 100644
index a60da4f1db..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release-Valgrind/actual-results.json
+++ /dev/null
@@ -1 +0,0 @@
-This file should not be read by results.py, so its contents don't matter.
diff --git a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN/actual-results.json b/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN/actual-results.json
deleted file mode 100644
index a60da4f1db..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN/actual-results.json
+++ /dev/null
@@ -1 +0,0 @@
-This file should not be read by results.py, so its contents don't matter.
diff --git a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-TSAN/actual-results.json b/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-TSAN/actual-results.json
deleted file mode 100644
index a60da4f1db..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-TSAN/actual-results.json
+++ /dev/null
@@ -1 +0,0 @@
-This file should not be read by results.py, so its contents don't matter.
diff --git a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Win7-ShuttleA-HD2000-x86_64-Debug-Trybot/actual-results.json b/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Win7-ShuttleA-HD2000-x86_64-Debug-Trybot/actual-results.json
deleted file mode 100644
index a60da4f1db..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-actuals/Test-Win7-ShuttleA-HD2000-x86_64-Debug-Trybot/actual-results.json
+++ /dev/null
@@ -1 +0,0 @@
-This file should not be read by results.py, so its contents don't matter.
diff --git a/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Android-GalaxyNexus-SGX540-Arm7-Release/expected-results.json b/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Android-GalaxyNexus-SGX540-Arm7-Release/expected-results.json
deleted file mode 100644
index 75b2663307..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Android-GalaxyNexus-SGX540-Arm7-Release/expected-results.json
+++ /dev/null
@@ -1,109 +0,0 @@
-{
- "actual-results": {
- "failed": null,
- "failure-ignored": null,
- "no-comparison": null,
- "succeeded": null
- },
- "expected-results": {
- "3x3bitmaprect_565.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 16998423976396106083
- ]
- ],
- "bugs": [
- 1578
- ],
- "reviewed-by-human": false
- },
- "3x3bitmaprect_8888.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 2054956815327187963
- ]
- ],
- "bugs": [
- 1578
- ],
- "reviewed-by-human": false
- },
- "aaclip_565.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 6190901827590820995
- ]
- ],
- "ignore-failure": false
- },
- "aaclip_8888.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 14456211900777561488
- ]
- ],
- "ignore-failure": false
- },
- "filterbitmap_checkerboard_192_192_565.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 9917960313903939620
- ]
- ],
- "bugs": [
- 1578
- ],
- "reviewed-by-human": false
- },
- "filterbitmap_checkerboard_192_192_8888.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 9917960313903939620
- ]
- ],
- "bugs": [
- 1578
- ],
- "reviewed-by-human": false
- },
- "filterbitmap_checkerboard_32_2_565.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 16197252621792695154
- ]
- ],
- "bugs": [
- 1578
- ],
- "reviewed-by-human": false
- },
- "filterbitmap_checkerboard_32_2_8888.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 7634650333321761866
- ]
- ],
- "bugs": [
- 1578
- ],
- "reviewed-by-human": false
- },
- "texdata_gpu.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 2736593828543197285
- ]
- ],
- "ignore-failure": false
- }
- }
-}
diff --git a/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json b/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json
deleted file mode 100644
index f3f49bbc3a..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json
+++ /dev/null
@@ -1,145 +0,0 @@
-{
- "actual-results": {
- "failed": null,
- "failure-ignored": null,
- "no-comparison": null,
- "succeeded": null
- },
- "expected-results": {
- "3x3bitmaprect_565.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 16998423976396106083
- ]
- ],
- "bugs": [
- 1578
- ],
- "reviewed-by-human": false
- },
- "3x3bitmaprect_8888.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 2054956815327187963
- ]
- ],
- "bugs": [
- 1578
- ],
- "reviewed-by-human": false
- },
- "3x3bitmaprect_gpu.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 2054956815327187963
- ]
- ],
- "bugs": [
- 1578
- ],
- "reviewed-by-human": false
- },
- "3x3bitmaprect_pdf-mac.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 8518347971308375604
- ]
- ],
- "bugs": [
- 1578
- ],
- "reviewed-by-human": false
- },
- "3x3bitmaprect_pdf-poppler.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 16723580409414313678
- ]
- ],
- "bugs": [
- 1578
- ],
- "reviewed-by-human": false
- },
- "blanket-ignored_565.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 111111111
- ]
- ],
- "ignore-failure": false
- },
- "blanket-ignored_8888.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 111111111
- ]
- ],
- "ignore-failure": false
- },
- "displacement_565.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 4569468668668628191
- ]
- ],
- "ignore-failure": false
- },
- "displacement_8888.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 11401048196735046263
- ]
- ],
- "ignore-failure": false
- },
- "displacement_gpu.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 5698561127291561694
- ]
- ],
- "ignore-failure": false
- },
- "displacement_mesa.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 3844627628059679694
- ]
- ],
- "ignore-failure": false
- },
- "displacement_pdf-mac.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 12901125495691049846
- ]
- ],
- "ignore-failure": false
- },
- "displacement_pdf-poppler.png": {
- "allowed-digests": [
- [
- "bitmap-64bitMD5",
- 16285974094717334658
- ]
- ],
- "bugs": [
- 1578
- ],
- "reviewed-by-human": false
- }
- }
-}
diff --git a/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release-Valgrind/expected-results.json b/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release-Valgrind/expected-results.json
deleted file mode 100644
index a60da4f1db..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release-Valgrind/expected-results.json
+++ /dev/null
@@ -1 +0,0 @@
-This file should not be read by results.py, so its contents don't matter.
diff --git a/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN/expected-results.json b/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN/expected-results.json
deleted file mode 100644
index a60da4f1db..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN/expected-results.json
+++ /dev/null
@@ -1 +0,0 @@
-This file should not be read by results.py, so its contents don't matter.
diff --git a/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-TSAN/expected-results.json b/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-TSAN/expected-results.json
deleted file mode 100644
index a60da4f1db..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-TSAN/expected-results.json
+++ /dev/null
@@ -1 +0,0 @@
-This file should not be read by results.py, so its contents don't matter.
diff --git a/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Win7-ShuttleA-HD2000-x86_64-Debug-Trybot/expected-results.json b/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Win7-ShuttleA-HD2000-x86_64-Debug-Trybot/expected-results.json
deleted file mode 100644
index a60da4f1db..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-expectations/Test-Win7-ShuttleA-HD2000-x86_64-Debug-Trybot/expected-results.json
+++ /dev/null
@@ -1 +0,0 @@
-This file should not be read by results.py, so its contents don't matter.
diff --git a/gm/rebaseline_server/testdata/inputs/gm-expectations/ignored-tests.txt b/gm/rebaseline_server/testdata/inputs/gm-expectations/ignored-tests.txt
deleted file mode 100644
index b14eb96bbf..0000000000
--- a/gm/rebaseline_server/testdata/inputs/gm-expectations/ignored-tests.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-# Failures of any GM tests listed in this file will be ignored [1], as
-# if they had been marked "ignore-failure": true in the per-builder
-# expected-results.json files.
-#
-
-blanket-ignored
-
-# "texdata" tests should NOT be ignored, since the next lines is commented out:
-# texdata
-
diff --git a/gm/rebaseline_server/testdata/inputs/skp-summaries/actuals/summary.json b/gm/rebaseline_server/testdata/inputs/skp-summaries/actuals/summary.json
deleted file mode 100644
index 67e8409117..0000000000
--- a/gm/rebaseline_server/testdata/inputs/skp-summaries/actuals/summary.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "actual-results" : {
- "changed.skp" : {
- "whole-image" : {
- "checksumAlgorithm" : "bitmap-64bitMD5",
- "checksumValue" : 13623922271964399662,
- "comparisonResult" : "no-comparison",
- "filepath" : "changed_skp/bitmap-64bitMD5_13623922271964399662.png"
- }
- },
- "only-in-after.skp" : {
- "whole-image" : {
- "checksumAlgorithm" : "bitmap-64bitMD5",
- "checksumValue" : 2320185040577047131,
- "comparisonResult" : "no-comparison",
- "filepath" : "only-in-after_skp/bitmap-64bitMD5_2320185040577047131.png"
- }
- },
- "unchanged.skp" : {
- "whole-image" : {
- "checksumAlgorithm" : "bitmap-64bitMD5",
- "checksumValue" : 3322248763049618493,
- "comparisonResult" : "no-comparison",
- "filepath" : "unchanged_skp/bitmap-64bitMD5_3322248763049618493.png"
- }
- }
- },
- "header" : {
- "revision" : 1,
- "type" : "ChecksummedImages"
- }
-}
diff --git a/gm/rebaseline_server/testdata/inputs/skp-summaries/expectations/summary.json b/gm/rebaseline_server/testdata/inputs/skp-summaries/expectations/summary.json
deleted file mode 100644
index 9d64d75365..0000000000
--- a/gm/rebaseline_server/testdata/inputs/skp-summaries/expectations/summary.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "expected-results" : {
- "changed.skp" : {
- "whole-image" : {
- "checksumAlgorithm" : "bitmap-64bitMD5",
- "checksumValue" : 3101044995537104462,
- "comparisonResult" : "no-comparison",
- "filepath" : "changed_skp/bitmap-64bitMD5_3101044995537104462.png"
- }
- },
- "only-in-before.skp" : {
- "whole-image" : {
- "checksumAlgorithm" : "bitmap-64bitMD5",
- "checksumValue" : 2320185040577047131,
- "comparisonResult" : "no-comparison",
- "filepath" : "only-in-before_skp/bitmap-64bitMD5_2320185040577047131.png"
- }
- },
- "unchanged.skp" : {
- "whole-image" : {
- "checksumAlgorithm" : "bitmap-64bitMD5",
- "checksumValue" : 3322248763049618493,
- "comparisonResult" : "no-comparison",
- "filepath" : "unchanged_skp/bitmap-64bitMD5_3322248763049618493.png"
- }
- }
- },
- "header" : {
- "revision" : 1,
- "type" : "ChecksummedImages"
- }
-}
diff --git a/gm/rebaseline_server/testdata/outputs/.gitignore b/gm/rebaseline_server/testdata/outputs/.gitignore
deleted file mode 100644
index b369696468..0000000000
--- a/gm/rebaseline_server/testdata/outputs/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-actual/
diff --git a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/3x3bitmaprect.png b/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/3x3bitmaprect.png
deleted file mode 100644
index d3686ff12d..0000000000
--- a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/3x3bitmaprect.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/3x3bitmaprect/16998423976396106083.png
diff --git a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/aaclip.png b/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/aaclip.png
deleted file mode 100644
index 8a01aa825f..0000000000
--- a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/aaclip.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/aaclip/6190901827590820995.png
diff --git a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/bigblurs.png b/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/bigblurs.png
deleted file mode 100644
index 8d0646720a..0000000000
--- a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/bigblurs.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/bigblurs/2422083043229439955.png
diff --git a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/bitmapsource.png b/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/bitmapsource.png
deleted file mode 100644
index d2df08ca3a..0000000000
--- a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/bitmapsource.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/bitmapsource/17503582803589749280.png
diff --git a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_192_192.png b/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_192_192.png
deleted file mode 100644
index 5c91d33e15..0000000000
--- a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_192_192.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/filterbitmap_checkerboard_192_192/4719210487426381700.png
diff --git a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_32_2.png b/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_32_2.png
deleted file mode 100644
index 3c1de492de..0000000000
--- a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_32_2.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/filterbitmap_checkerboard_32_2/15528304435129737588.png
diff --git a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/3x3bitmaprect.png b/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/3x3bitmaprect.png
deleted file mode 100644
index 656275a920..0000000000
--- a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/3x3bitmaprect.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png
diff --git a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/aaclip.png b/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/aaclip.png
deleted file mode 100644
index 371a172ece..0000000000
--- a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/aaclip.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/aaclip/14456211900777561488.png
diff --git a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/bigblurs.png b/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/bigblurs.png
deleted file mode 100644
index 2d78e89be3..0000000000
--- a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/bigblurs.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/bigblurs/17309852422285247848.png
diff --git a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/bitmapsource.png b/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/bitmapsource.png
deleted file mode 100644
index 3c511d5f6a..0000000000
--- a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/bitmapsource.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/bitmapsource/16289727936158057543.png
diff --git a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_192_192.png b/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_192_192.png
deleted file mode 100644
index 9364ccdd8a..0000000000
--- a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_192_192.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/filterbitmap_checkerboard_192_192/3154864687054945306.png
diff --git a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_32_2.png b/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_32_2.png
deleted file mode 100644
index 8760be33fb..0000000000
--- a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_32_2.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/filterbitmap_checkerboard_32_2/712827739969462165.png
diff --git a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/gpu/texdata.png b/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/gpu/texdata.png
deleted file mode 100644
index fee415c72a..0000000000
--- a/gm/rebaseline_server/testdata/outputs/actual/download_actuals_test.DownloadTest.test_fetch/gpu/texdata.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/texdata/3695033638604474475.png
diff --git a/gm/rebaseline_server/testdata/outputs/expected/compare_configs_test.CompareConfigsTest.test_gm/gm.json b/gm/rebaseline_server/testdata/outputs/expected/compare_configs_test.CompareConfigsTest.test_gm/gm.json
deleted file mode 100644
index 048abefd1e..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/compare_configs_test.CompareConfigsTest.test_gm/gm.json
+++ /dev/null
@@ -1,337 +0,0 @@
-{
- "extraColumnHeaders": {
- "builder": {
- "headerText": "builder",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- 7
- ],
- [
- "Test-Builder-We-Have-No-Expectations-File-For",
- 3
- ],
- [
- "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- 4
- ]
- ]
- },
- "config": {
- "headerText": "config",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- "TODO",
- 14
- ]
- ]
- },
- "resultType": {
- "headerText": "resultType",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- "failed",
- 4
- ],
- [
- "no-comparison",
- 8
- ],
- [
- "succeeded",
- 2
- ]
- ]
- },
- "test": {
- "headerText": "test",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- "3x3bitmaprect",
- 3
- ],
- [
- "aaclip",
- 1
- ],
- [
- "bigblurs",
- 3
- ],
- [
- "bitmapsource",
- 1
- ],
- [
- "blanket-ignored",
- 1
- ],
- [
- "displacement",
- 2
- ],
- [
- "filterbitmap_checkerboard_192_192",
- 1
- ],
- [
- "filterbitmap_checkerboard_32_2",
- 1
- ],
- [
- "texdata",
- 1
- ]
- ]
- }
- },
- "extraColumnOrder": [
- "builder",
- "config",
- "resultType",
- "test"
- ],
- "header": {
- "dataHash": "-8474691963189557240",
- "isEditable": false,
- "isExported": true,
- "schemaVersion": 5,
- "timeNextUpdateAvailable": null,
- "timeUpdated": 12345678,
- "type": "all"
- },
- "imagePairs": [
- {
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "TODO",
- "resultType": "no-comparison",
- "test": "texdata"
- },
- "imageAUrl": null,
- "imageBUrl": "bitmap-64bitMD5/texdata/3695033638604474475.png",
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "TODO",
- "resultType": "no-comparison",
- "test": "filterbitmap_checkerboard_32_2"
- },
- "imageAUrl": "bitmap-64bitMD5/filterbitmap_checkerboard_32_2/712827739969462165.png",
- "imageBUrl": null,
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "TODO",
- "resultType": "no-comparison",
- "test": "filterbitmap_checkerboard_192_192"
- },
- "imageAUrl": "bitmap-64bitMD5/filterbitmap_checkerboard_192_192/3154864687054945306.png",
- "imageBUrl": null,
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "TODO",
- "resultType": "no-comparison",
- "test": "bigblurs"
- },
- "imageAUrl": "bitmap-64bitMD5/bigblurs/17309852422285247848.png",
- "imageBUrl": null,
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "TODO",
- "resultType": "no-comparison",
- "test": "bitmapsource"
- },
- "imageAUrl": "bitmap-64bitMD5/bitmapsource/16289727936158057543.png",
- "imageBUrl": null,
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "TODO",
- "resultType": "no-comparison",
- "test": "3x3bitmaprect"
- },
- "imageAUrl": "bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png",
- "imageBUrl": null,
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "TODO",
- "resultType": "no-comparison",
- "test": "aaclip"
- },
- "imageAUrl": "bitmap-64bitMD5/aaclip/14456211900777561488.png",
- "imageBUrl": null,
- "isDifferent": true
- },
- {
- "differenceData": {
- "diffUrl": "bitmap-64bitMD5_displacement_11401048196735046263_png_png-vs-bitmap-64bitMD5_displacement_5698561127291561694_png_png.png",
- "maxDiffPerChannel": [
- 136,
- 68,
- 34
- ],
- "numDifferingPixels": 6081,
- "percentDifferingPixels": 2.4324,
- "perceptualDifference": 1.9172010000000057,
- "whiteDiffUrl": "bitmap-64bitMD5_displacement_11401048196735046263_png_png-vs-bitmap-64bitMD5_displacement_5698561127291561694_png_png.png"
- },
- "extraColumns": {
- "builder": "Test-Builder-We-Have-No-Expectations-File-For",
- "config": "TODO",
- "resultType": "failed",
- "test": "displacement"
- },
- "imageAUrl": "bitmap-64bitMD5/displacement/11401048196735046263.png",
- "imageBUrl": "bitmap-64bitMD5/displacement/5698561127291561694.png",
- "isDifferent": true
- },
- {
- "differenceData": {
- "diffUrl": "bitmap-64bitMD5_bigblurs_17309852422285247848_png_png-vs-bitmap-64bitMD5_bigblurs_1822195599289208664_png_png.png",
- "maxDiffPerChannel": [
- 255,
- 221,
- 221
- ],
- "numDifferingPixels": 50097,
- "percentDifferingPixels": 30.5767822265625,
- "perceptualDifference": 3.391725000000008,
- "whiteDiffUrl": "bitmap-64bitMD5_bigblurs_17309852422285247848_png_png-vs-bitmap-64bitMD5_bigblurs_1822195599289208664_png_png.png"
- },
- "extraColumns": {
- "builder": "Test-Builder-We-Have-No-Expectations-File-For",
- "config": "TODO",
- "resultType": "failed",
- "test": "bigblurs"
- },
- "imageAUrl": "bitmap-64bitMD5/bigblurs/17309852422285247848.png",
- "imageBUrl": "bitmap-64bitMD5/bigblurs/1822195599289208664.png",
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Builder-We-Have-No-Expectations-File-For",
- "config": "TODO",
- "resultType": "succeeded",
- "test": "3x3bitmaprect"
- },
- "imageAUrl": "bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png",
- "imageBUrl": "bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png",
- "isDifferent": false
- },
- {
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "TODO",
- "resultType": "no-comparison",
- "test": "blanket-ignored"
- },
- "imageAUrl": "bitmap-64bitMD5/blanket-ignored/22222222.png",
- "imageBUrl": null,
- "isDifferent": true
- },
- {
- "differenceData": {
- "diffUrl": "bitmap-64bitMD5_displacement_11401048196735046263_png_png-vs-bitmap-64bitMD5_displacement_5698561127291561694_png_png.png",
- "maxDiffPerChannel": [
- 136,
- 68,
- 34
- ],
- "numDifferingPixels": 6081,
- "percentDifferingPixels": 2.4324,
- "perceptualDifference": 1.9172010000000057,
- "whiteDiffUrl": "bitmap-64bitMD5_displacement_11401048196735046263_png_png-vs-bitmap-64bitMD5_displacement_5698561127291561694_png_png.png"
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "TODO",
- "resultType": "failed",
- "test": "displacement"
- },
- "imageAUrl": "bitmap-64bitMD5/displacement/11401048196735046263.png",
- "imageBUrl": "bitmap-64bitMD5/displacement/5698561127291561694.png",
- "isDifferent": true
- },
- {
- "differenceData": {
- "diffUrl": "bitmap-64bitMD5_bigblurs_17309852422285247848_png_png-vs-bitmap-64bitMD5_bigblurs_1822195599289208664_png_png.png",
- "maxDiffPerChannel": [
- 255,
- 221,
- 221
- ],
- "numDifferingPixels": 50097,
- "percentDifferingPixels": 30.5767822265625,
- "perceptualDifference": 3.391725000000008,
- "whiteDiffUrl": "bitmap-64bitMD5_bigblurs_17309852422285247848_png_png-vs-bitmap-64bitMD5_bigblurs_1822195599289208664_png_png.png"
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "TODO",
- "resultType": "failed",
- "test": "bigblurs"
- },
- "imageAUrl": "bitmap-64bitMD5/bigblurs/17309852422285247848.png",
- "imageBUrl": "bitmap-64bitMD5/bigblurs/1822195599289208664.png",
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "TODO",
- "resultType": "succeeded",
- "test": "3x3bitmaprect"
- },
- "imageAUrl": "bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png",
- "imageBUrl": "bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png",
- "isDifferent": false
- }
- ],
- "imageSets": {
- "diffs": {
- "baseUrl": "/static/generated-images/diffs",
- "description": "color difference per channel"
- },
- "imageA": {
- "baseUrl": "http://chromium-skia-gm.commondatastorage.googleapis.com/gm",
- "description": "8888"
- },
- "imageB": {
- "baseUrl": "http://chromium-skia-gm.commondatastorage.googleapis.com/gm",
- "description": "gpu"
- },
- "whiteDiffs": {
- "baseUrl": "/static/generated-images/whitediffs",
- "description": "differing pixels in white"
- }
- }
-} \ No newline at end of file
diff --git a/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_endToEnd/compare_rendered_pictures.json b/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_endToEnd/compare_rendered_pictures.json
deleted file mode 100644
index 1ce3718bc6..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_endToEnd/compare_rendered_pictures.json
+++ /dev/null
@@ -1,237 +0,0 @@
-{
- "extraColumnHeaders": {
- "builderA": {
- "headerText": "builderA",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- null,
- 4
- ]
- ]
- },
- "builderB": {
- "headerText": "builderB",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- null,
- 4
- ]
- ]
- },
- "renderModeA": {
- "headerText": "renderModeA",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- null,
- 4
- ]
- ]
- },
- "renderModeB": {
- "headerText": "renderModeB",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- null,
- 4
- ]
- ]
- },
- "resultType": {
- "headerText": "resultType",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- "failed",
- 1
- ],
- [
- "no-comparison",
- 2
- ],
- [
- "succeeded",
- 1
- ]
- ]
- },
- "sourceSkpFile": {
- "headerText": "sourceSkpFile",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": true,
- "valuesAndCounts": [
- [
- "changed.skp",
- 1
- ],
- [
- "only-in-after.skp",
- 1
- ],
- [
- "only-in-before.skp",
- 1
- ],
- [
- "unchanged.skp",
- 1
- ]
- ]
- },
- "tiledOrWhole": {
- "headerText": "tiledOrWhole",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- "whole",
- 4
- ]
- ]
- },
- "tilenum": {
- "headerText": "tilenum",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": true,
- "valuesAndCounts": [
- [
- "N/A",
- 4
- ]
- ]
- }
- },
- "extraColumnOrder": [
- "resultType",
- "sourceSkpFile",
- "tiledOrWhole",
- "tilenum",
- "builderA",
- "renderModeA",
- "builderB",
- "renderModeB"
- ],
- "header": {
- "dataHash": "-9145196899696949575",
- "isEditable": false,
- "isExported": true,
- "schemaVersion": 5,
- "setA": {
- "dir": [
- "before-patch-fake-dir"
- ],
- "repoRevision": null,
- "section": "actual-results"
- },
- "setB": {
- "dir": [
- "after-patch-fake-dir"
- ],
- "repoRevision": null,
- "section": "actual-results"
- },
- "timeNextUpdateAvailable": null,
- "timeUpdated": 12345678,
- "type": "all"
- },
- "imagePairs": [
- {
- "extraColumns": {
- "builderA": null,
- "builderB": null,
- "renderModeA": null,
- "renderModeB": null,
- "resultType": "failed",
- "sourceSkpFile": "changed.skp",
- "tiledOrWhole": "whole",
- "tilenum": "N/A"
- },
- "imageAUrl": "changed_skp/bitmap-64bitMD5_17527938180154630042.png",
- "imageBUrl": "changed_skp/bitmap-64bitMD5_2314401992566164894.png",
- "isDifferent": true,
- "sourceJsonFile": "./summary.json"
- },
- {
- "extraColumns": {
- "builderA": null,
- "builderB": null,
- "renderModeA": null,
- "renderModeB": null,
- "resultType": "no-comparison",
- "sourceSkpFile": "only-in-after.skp",
- "tiledOrWhole": "whole",
- "tilenum": "N/A"
- },
- "imageAUrl": null,
- "imageBUrl": "only-in-after_skp/bitmap-64bitMD5_6558642089737589931.png",
- "isDifferent": true,
- "sourceJsonFile": "./summary.json"
- },
- {
- "extraColumns": {
- "builderA": null,
- "builderB": null,
- "renderModeA": null,
- "renderModeB": null,
- "resultType": "no-comparison",
- "sourceSkpFile": "only-in-before.skp",
- "tiledOrWhole": "whole",
- "tilenum": "N/A"
- },
- "imageAUrl": "only-in-before_skp/bitmap-64bitMD5_6558642089737589931.png",
- "imageBUrl": null,
- "isDifferent": true,
- "sourceJsonFile": "./summary.json"
- },
- {
- "extraColumns": {
- "builderA": null,
- "builderB": null,
- "renderModeA": null,
- "renderModeB": null,
- "resultType": "succeeded",
- "sourceSkpFile": "unchanged.skp",
- "tiledOrWhole": "whole",
- "tilenum": "N/A"
- },
- "imageAUrl": "unchanged_skp/bitmap-64bitMD5_1094324242976325446.png",
- "imageBUrl": "unchanged_skp/bitmap-64bitMD5_1094324242976325446.png",
- "isDifferent": false,
- "sourceJsonFile": "./summary.json"
- }
- ],
- "imageSets": {
- "diffs": {
- "baseUrl": "/static/generated-images/diffs",
- "description": "color difference per channel"
- },
- "imageA": {
- "baseUrl": "http://storage.cloud.google.com/fakebucket/fake/path",
- "description": "setA"
- },
- "imageB": {
- "baseUrl": "http://storage.cloud.google.com/fakebucket/fake/path",
- "description": "setB"
- },
- "whiteDiffs": {
- "baseUrl": "/static/generated-images/whitediffs",
- "description": "differing pixels in white"
- }
- }
-} \ No newline at end of file
diff --git a/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_endToEnd_withImageBaseGSUrl/compare_rendered_pictures.json b/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_endToEnd_withImageBaseGSUrl/compare_rendered_pictures.json
deleted file mode 100644
index 1026014da5..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_endToEnd_withImageBaseGSUrl/compare_rendered_pictures.json
+++ /dev/null
@@ -1,237 +0,0 @@
-{
- "extraColumnHeaders": {
- "builderA": {
- "headerText": "builderA",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- null,
- 4
- ]
- ]
- },
- "builderB": {
- "headerText": "builderB",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- null,
- 4
- ]
- ]
- },
- "renderModeA": {
- "headerText": "renderModeA",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- null,
- 4
- ]
- ]
- },
- "renderModeB": {
- "headerText": "renderModeB",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- null,
- 4
- ]
- ]
- },
- "resultType": {
- "headerText": "resultType",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- "failed",
- 1
- ],
- [
- "no-comparison",
- 2
- ],
- [
- "succeeded",
- 1
- ]
- ]
- },
- "sourceSkpFile": {
- "headerText": "sourceSkpFile",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": true,
- "valuesAndCounts": [
- [
- "changed.skp",
- 1
- ],
- [
- "only-in-after.skp",
- 1
- ],
- [
- "only-in-before.skp",
- 1
- ],
- [
- "unchanged.skp",
- 1
- ]
- ]
- },
- "tiledOrWhole": {
- "headerText": "tiledOrWhole",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- "whole",
- 4
- ]
- ]
- },
- "tilenum": {
- "headerText": "tilenum",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": true,
- "valuesAndCounts": [
- [
- "N/A",
- 4
- ]
- ]
- }
- },
- "extraColumnOrder": [
- "resultType",
- "sourceSkpFile",
- "tiledOrWhole",
- "tilenum",
- "builderA",
- "renderModeA",
- "builderB",
- "renderModeB"
- ],
- "header": {
- "dataHash": "-9145196899696949575",
- "isEditable": false,
- "isExported": true,
- "schemaVersion": 5,
- "setA": {
- "dir": [
- "before-patch-fake-dir"
- ],
- "repoRevision": null,
- "section": "actual-results"
- },
- "setB": {
- "dir": [
- "after-patch-fake-dir"
- ],
- "repoRevision": null,
- "section": "actual-results"
- },
- "timeNextUpdateAvailable": null,
- "timeUpdated": 12345678,
- "type": "all"
- },
- "imagePairs": [
- {
- "extraColumns": {
- "builderA": null,
- "builderB": null,
- "renderModeA": null,
- "renderModeB": null,
- "resultType": "failed",
- "sourceSkpFile": "changed.skp",
- "tiledOrWhole": "whole",
- "tilenum": "N/A"
- },
- "imageAUrl": "changed_skp/bitmap-64bitMD5_17527938180154630042.png",
- "imageBUrl": "changed_skp/bitmap-64bitMD5_2314401992566164894.png",
- "isDifferent": true,
- "sourceJsonFile": "./summary.json"
- },
- {
- "extraColumns": {
- "builderA": null,
- "builderB": null,
- "renderModeA": null,
- "renderModeB": null,
- "resultType": "no-comparison",
- "sourceSkpFile": "only-in-after.skp",
- "tiledOrWhole": "whole",
- "tilenum": "N/A"
- },
- "imageAUrl": null,
- "imageBUrl": "only-in-after_skp/bitmap-64bitMD5_6558642089737589931.png",
- "isDifferent": true,
- "sourceJsonFile": "./summary.json"
- },
- {
- "extraColumns": {
- "builderA": null,
- "builderB": null,
- "renderModeA": null,
- "renderModeB": null,
- "resultType": "no-comparison",
- "sourceSkpFile": "only-in-before.skp",
- "tiledOrWhole": "whole",
- "tilenum": "N/A"
- },
- "imageAUrl": "only-in-before_skp/bitmap-64bitMD5_6558642089737589931.png",
- "imageBUrl": null,
- "isDifferent": true,
- "sourceJsonFile": "./summary.json"
- },
- {
- "extraColumns": {
- "builderA": null,
- "builderB": null,
- "renderModeA": null,
- "renderModeB": null,
- "resultType": "succeeded",
- "sourceSkpFile": "unchanged.skp",
- "tiledOrWhole": "whole",
- "tilenum": "N/A"
- },
- "imageAUrl": "unchanged_skp/bitmap-64bitMD5_1094324242976325446.png",
- "imageBUrl": "unchanged_skp/bitmap-64bitMD5_1094324242976325446.png",
- "isDifferent": false,
- "sourceJsonFile": "./summary.json"
- }
- ],
- "imageSets": {
- "diffs": {
- "baseUrl": "/static/generated-images/diffs",
- "description": "color difference per channel"
- },
- "imageA": {
- "baseUrl": "http://storage.cloud.google.com/superman/kent-camera/pictures",
- "description": "setA"
- },
- "imageB": {
- "baseUrl": "http://storage.cloud.google.com/batman/batarang/pictures",
- "description": "setB"
- },
- "whiteDiffs": {
- "baseUrl": "/static/generated-images/whitediffs",
- "description": "differing pixels in white"
- }
- }
-} \ No newline at end of file
diff --git a/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_repo_url/compare_rendered_pictures.json b/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_repo_url/compare_rendered_pictures.json
deleted file mode 100644
index 5ee60925ab..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/compare_rendered_pictures_test.CompareRenderedPicturesTest.test_repo_url/compare_rendered_pictures.json
+++ /dev/null
@@ -1,233 +0,0 @@
-{
- "extraColumnHeaders": {
- "builderA": {
- "headerText": "builderA",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- null,
- 4
- ]
- ]
- },
- "builderB": {
- "headerText": "builderB",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- null,
- 4
- ]
- ]
- },
- "renderModeA": {
- "headerText": "renderModeA",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- null,
- 4
- ]
- ]
- },
- "renderModeB": {
- "headerText": "renderModeB",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- null,
- 4
- ]
- ]
- },
- "resultType": {
- "headerText": "resultType",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- "failed",
- 1
- ],
- [
- "no-comparison",
- 2
- ],
- [
- "succeeded",
- 1
- ]
- ]
- },
- "sourceSkpFile": {
- "headerText": "sourceSkpFile",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": true,
- "valuesAndCounts": [
- [
- "changed.skp",
- 1
- ],
- [
- "only-in-after.skp",
- 1
- ],
- [
- "only-in-before.skp",
- 1
- ],
- [
- "unchanged.skp",
- 1
- ]
- ]
- },
- "tiledOrWhole": {
- "headerText": "tiledOrWhole",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- "whole",
- 4
- ]
- ]
- },
- "tilenum": {
- "headerText": "tilenum",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": true,
- "valuesAndCounts": [
- [
- "N/A",
- 4
- ]
- ]
- }
- },
- "extraColumnOrder": [
- "resultType",
- "sourceSkpFile",
- "tiledOrWhole",
- "tilenum",
- "builderA",
- "renderModeA",
- "builderB",
- "renderModeB"
- ],
- "header": {
- "dataHash": "-5707186260478709107",
- "isEditable": false,
- "isExported": true,
- "schemaVersion": 5,
- "setA": {
- "dir": "repo:gm/rebaseline_server/testdata/inputs/skp-summaries/expectations",
- "repoRevision": "fake-repo-revision",
- "section": "expected-results"
- },
- "setB": {
- "dir": "repo:gm/rebaseline_server/testdata/inputs/skp-summaries/actuals",
- "repoRevision": "fake-repo-revision",
- "section": "actual-results"
- },
- "timeNextUpdateAvailable": null,
- "timeUpdated": 12345678,
- "type": "all"
- },
- "imagePairs": [
- {
- "extraColumns": {
- "builderA": null,
- "builderB": null,
- "renderModeA": null,
- "renderModeB": null,
- "resultType": "failed",
- "sourceSkpFile": "changed.skp",
- "tiledOrWhole": "whole",
- "tilenum": "N/A"
- },
- "imageAUrl": "changed_skp/bitmap-64bitMD5_3101044995537104462.png",
- "imageBUrl": "changed_skp/bitmap-64bitMD5_13623922271964399662.png",
- "isDifferent": true,
- "sourceJsonFile": "./summary.json"
- },
- {
- "extraColumns": {
- "builderA": null,
- "builderB": null,
- "renderModeA": null,
- "renderModeB": null,
- "resultType": "no-comparison",
- "sourceSkpFile": "only-in-after.skp",
- "tiledOrWhole": "whole",
- "tilenum": "N/A"
- },
- "imageAUrl": null,
- "imageBUrl": "only-in-after_skp/bitmap-64bitMD5_2320185040577047131.png",
- "isDifferent": true,
- "sourceJsonFile": "./summary.json"
- },
- {
- "extraColumns": {
- "builderA": null,
- "builderB": null,
- "renderModeA": null,
- "renderModeB": null,
- "resultType": "no-comparison",
- "sourceSkpFile": "only-in-before.skp",
- "tiledOrWhole": "whole",
- "tilenum": "N/A"
- },
- "imageAUrl": "only-in-before_skp/bitmap-64bitMD5_2320185040577047131.png",
- "imageBUrl": null,
- "isDifferent": true,
- "sourceJsonFile": "./summary.json"
- },
- {
- "extraColumns": {
- "builderA": null,
- "builderB": null,
- "renderModeA": null,
- "renderModeB": null,
- "resultType": "succeeded",
- "sourceSkpFile": "unchanged.skp",
- "tiledOrWhole": "whole",
- "tilenum": "N/A"
- },
- "imageAUrl": "unchanged_skp/bitmap-64bitMD5_3322248763049618493.png",
- "imageBUrl": "unchanged_skp/bitmap-64bitMD5_3322248763049618493.png",
- "isDifferent": false,
- "sourceJsonFile": "./summary.json"
- }
- ],
- "imageSets": {
- "diffs": {
- "baseUrl": "/static/generated-images/diffs",
- "description": "color difference per channel"
- },
- "imageA": {
- "baseUrl": "http://storage.cloud.google.com/fakebucket/fake/path",
- "description": "expected-results"
- },
- "imageB": {
- "baseUrl": "http://storage.cloud.google.com/fakebucket/fake/path",
- "description": "actual-results"
- },
- "whiteDiffs": {
- "baseUrl": "/static/generated-images/whitediffs",
- "description": "differing pixels in white"
- }
- }
-} \ No newline at end of file
diff --git a/gm/rebaseline_server/testdata/outputs/expected/compare_to_expectations_test.CompareToExpectationsTest.test_gm/gm.json b/gm/rebaseline_server/testdata/outputs/expected/compare_to_expectations_test.CompareToExpectationsTest.test_gm/gm.json
deleted file mode 100644
index 30d2ab983f..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/compare_to_expectations_test.CompareToExpectationsTest.test_gm/gm.json
+++ /dev/null
@@ -1,646 +0,0 @@
-{
- "extraColumnHeaders": {
- "builder": {
- "headerText": "builder",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": true,
- "valuesAndCounts": [
- [
- "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- 13
- ],
- [
- "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- 17
- ]
- ]
- },
- "config": {
- "headerText": "config",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- "565",
- 10
- ],
- [
- "8888",
- 10
- ],
- [
- "gpu",
- 4
- ],
- [
- "pdf-mac",
- 3
- ],
- [
- "pdf-poppler",
- 3
- ]
- ]
- },
- "resultType": {
- "headerText": "resultType",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": false,
- "valuesAndCounts": [
- [
- "failed",
- 1
- ],
- [
- "failure-ignored",
- 6
- ],
- [
- "no-comparison",
- 9
- ],
- [
- "succeeded",
- 14
- ]
- ]
- },
- "test": {
- "headerText": "test",
- "isFilterable": true,
- "isSortable": true,
- "useFreeformFilter": true,
- "valuesAndCounts": [
- [
- "3x3bitmaprect",
- 7
- ],
- [
- "aaclip",
- 2
- ],
- [
- "bigblurs",
- 7
- ],
- [
- "bitmapsource",
- 2
- ],
- [
- "blanket-ignored",
- 2
- ],
- [
- "displacement",
- 5
- ],
- [
- "filterbitmap_checkerboard_192_192",
- 2
- ],
- [
- "filterbitmap_checkerboard_32_2",
- 2
- ],
- [
- "texdata",
- 1
- ]
- ]
- }
- },
- "extraColumnOrder": [
- "resultType",
- "builder",
- "test",
- "config"
- ],
- "header": {
- "dataHash": "6366271140430198826",
- "isEditable": false,
- "isExported": true,
- "schemaVersion": 5,
- "timeNextUpdateAvailable": null,
- "timeUpdated": 12345678,
- "type": "all"
- },
- "imagePairs": [
- {
- "differenceData": {
- "diffUrl": "bitmap-64bitMD5_texdata_2736593828543197285_png_png-vs-bitmap-64bitMD5_texdata_3695033638604474475_png_png.png",
- "maxDiffPerChannel": [
- 128,
- 128,
- 128
- ],
- "numDifferingPixels": 120000,
- "percentDifferingPixels": 75.0,
- "perceptualDifference": 50.122499,
- "whiteDiffUrl": "bitmap-64bitMD5_texdata_2736593828543197285_png_png-vs-bitmap-64bitMD5_texdata_3695033638604474475_png_png.png"
- },
- "expectations": {
- "bugs": null,
- "ignore-failure": false,
- "reviewed-by-human": null
- },
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "gpu",
- "resultType": "failed",
- "test": "texdata"
- },
- "imageAUrl": "bitmap-64bitMD5/texdata/2736593828543197285.png",
- "imageBUrl": "bitmap-64bitMD5/texdata/3695033638604474475.png",
- "isDifferent": true
- },
- {
- "differenceData": {
- "diffUrl": "bitmap-64bitMD5_filterbitmap_checkerboard_192_192_9917960313903939620_png_png-vs-bitmap-64bitMD5_filterbitmap_checkerboard_192_192_4719210487426381700_png_png.png",
- "maxDiffPerChannel": [
- 255,
- 255,
- 255
- ],
- "numDifferingPixels": 765891,
- "percentDifferingPixels": 97.38807678222656,
- "perceptualDifference": 25.256985,
- "whiteDiffUrl": "bitmap-64bitMD5_filterbitmap_checkerboard_192_192_9917960313903939620_png_png-vs-bitmap-64bitMD5_filterbitmap_checkerboard_192_192_4719210487426381700_png_png.png"
- },
- "expectations": {
- "bugs": [
- 1578
- ],
- "ignore-failure": null,
- "reviewed-by-human": false
- },
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "565",
- "resultType": "failure-ignored",
- "test": "filterbitmap_checkerboard_192_192"
- },
- "imageAUrl": "bitmap-64bitMD5/filterbitmap_checkerboard_192_192/9917960313903939620.png",
- "imageBUrl": "bitmap-64bitMD5/filterbitmap_checkerboard_192_192/4719210487426381700.png",
- "isDifferent": true
- },
- {
- "differenceData": {
- "diffUrl": "bitmap-64bitMD5_filterbitmap_checkerboard_192_192_9917960313903939620_png_png-vs-bitmap-64bitMD5_filterbitmap_checkerboard_192_192_3154864687054945306_png_png.png",
- "maxDiffPerChannel": [
- 255,
- 255,
- 255
- ],
- "numDifferingPixels": 422432,
- "percentDifferingPixels": 53.715006510416664,
- "perceptualDifference": 25.120543999999995,
- "whiteDiffUrl": "bitmap-64bitMD5_filterbitmap_checkerboard_192_192_9917960313903939620_png_png-vs-bitmap-64bitMD5_filterbitmap_checkerboard_192_192_3154864687054945306_png_png.png"
- },
- "expectations": {
- "bugs": [
- 1578
- ],
- "ignore-failure": null,
- "reviewed-by-human": false
- },
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "8888",
- "resultType": "failure-ignored",
- "test": "filterbitmap_checkerboard_192_192"
- },
- "imageAUrl": "bitmap-64bitMD5/filterbitmap_checkerboard_192_192/9917960313903939620.png",
- "imageBUrl": "bitmap-64bitMD5/filterbitmap_checkerboard_192_192/3154864687054945306.png",
- "isDifferent": true
- },
- {
- "expectations": {
- "bugs": [
- 1578
- ],
- "ignore-failure": null,
- "reviewed-by-human": false
- },
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "565",
- "resultType": "failure-ignored",
- "test": "filterbitmap_checkerboard_32_2"
- },
- "imageAUrl": "bitmap-64bitMD5/filterbitmap_checkerboard_32_2/16197252621792695154.png",
- "imageBUrl": "bitmap-64bitMD5/filterbitmap_checkerboard_32_2/15528304435129737588.png",
- "isDifferent": true
- },
- {
- "expectations": {
- "bugs": [
- 1578
- ],
- "ignore-failure": null,
- "reviewed-by-human": false
- },
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "8888",
- "resultType": "failure-ignored",
- "test": "filterbitmap_checkerboard_32_2"
- },
- "imageAUrl": "bitmap-64bitMD5/filterbitmap_checkerboard_32_2/7634650333321761866.png",
- "imageBUrl": "bitmap-64bitMD5/filterbitmap_checkerboard_32_2/712827739969462165.png",
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "565",
- "resultType": "no-comparison",
- "test": "bigblurs"
- },
- "imageAUrl": null,
- "imageBUrl": "bitmap-64bitMD5/bigblurs/2422083043229439955.png",
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "8888",
- "resultType": "no-comparison",
- "test": "bigblurs"
- },
- "imageAUrl": null,
- "imageBUrl": "bitmap-64bitMD5/bigblurs/17309852422285247848.png",
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "565",
- "resultType": "no-comparison",
- "test": "bitmapsource"
- },
- "imageAUrl": null,
- "imageBUrl": "bitmap-64bitMD5/bitmapsource/17503582803589749280.png",
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "8888",
- "resultType": "no-comparison",
- "test": "bitmapsource"
- },
- "imageAUrl": null,
- "imageBUrl": "bitmap-64bitMD5/bitmapsource/16289727936158057543.png",
- "isDifferent": true
- },
- {
- "expectations": {
- "bugs": [
- 1578
- ],
- "ignore-failure": null,
- "reviewed-by-human": false
- },
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "565",
- "resultType": "succeeded",
- "test": "3x3bitmaprect"
- },
- "imageAUrl": "bitmap-64bitMD5/3x3bitmaprect/16998423976396106083.png",
- "imageBUrl": "bitmap-64bitMD5/3x3bitmaprect/16998423976396106083.png",
- "isDifferent": false
- },
- {
- "expectations": {
- "bugs": [
- 1578
- ],
- "ignore-failure": null,
- "reviewed-by-human": false
- },
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "8888",
- "resultType": "succeeded",
- "test": "3x3bitmaprect"
- },
- "imageAUrl": "bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png",
- "imageBUrl": "bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png",
- "isDifferent": false
- },
- {
- "expectations": {
- "bugs": null,
- "ignore-failure": false,
- "reviewed-by-human": null
- },
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "565",
- "resultType": "succeeded",
- "test": "aaclip"
- },
- "imageAUrl": "bitmap-64bitMD5/aaclip/6190901827590820995.png",
- "imageBUrl": "bitmap-64bitMD5/aaclip/6190901827590820995.png",
- "isDifferent": false
- },
- {
- "expectations": {
- "bugs": null,
- "ignore-failure": false,
- "reviewed-by-human": null
- },
- "extraColumns": {
- "builder": "Test-Android-GalaxyNexus-SGX540-Arm7-Release",
- "config": "8888",
- "resultType": "succeeded",
- "test": "aaclip"
- },
- "imageAUrl": "bitmap-64bitMD5/aaclip/14456211900777561488.png",
- "imageBUrl": "bitmap-64bitMD5/aaclip/14456211900777561488.png",
- "isDifferent": false
- },
- {
- "expectations": {
- "bugs": null,
- "ignore-failure": false,
- "reviewed-by-human": null
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "565",
- "resultType": "failure-ignored",
- "test": "blanket-ignored"
- },
- "imageAUrl": "bitmap-64bitMD5/blanket-ignored/111111111.png",
- "imageBUrl": "bitmap-64bitMD5/blanket-ignored/22222222.png",
- "isDifferent": true
- },
- {
- "expectations": {
- "bugs": null,
- "ignore-failure": false,
- "reviewed-by-human": null
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "8888",
- "resultType": "failure-ignored",
- "test": "blanket-ignored"
- },
- "imageAUrl": "bitmap-64bitMD5/blanket-ignored/111111111.png",
- "imageBUrl": "bitmap-64bitMD5/blanket-ignored/22222222.png",
- "isDifferent": true
- },
- {
- "expectations": {
- "bugs": null,
- "ignore-failure": false,
- "reviewed-by-human": null
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "565",
- "resultType": "succeeded",
- "test": "displacement"
- },
- "imageAUrl": "bitmap-64bitMD5/displacement/4569468668668628191.png",
- "imageBUrl": "bitmap-64bitMD5/displacement/4569468668668628191.png",
- "isDifferent": false
- },
- {
- "expectations": {
- "bugs": null,
- "ignore-failure": false,
- "reviewed-by-human": null
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "8888",
- "resultType": "succeeded",
- "test": "displacement"
- },
- "imageAUrl": "bitmap-64bitMD5/displacement/11401048196735046263.png",
- "imageBUrl": "bitmap-64bitMD5/displacement/11401048196735046263.png",
- "isDifferent": false
- },
- {
- "expectations": {
- "bugs": null,
- "ignore-failure": false,
- "reviewed-by-human": null
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "gpu",
- "resultType": "succeeded",
- "test": "displacement"
- },
- "imageAUrl": "bitmap-64bitMD5/displacement/5698561127291561694.png",
- "imageBUrl": "bitmap-64bitMD5/displacement/5698561127291561694.png",
- "isDifferent": false
- },
- {
- "expectations": {
- "bugs": null,
- "ignore-failure": false,
- "reviewed-by-human": null
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "pdf-mac",
- "resultType": "succeeded",
- "test": "displacement"
- },
- "imageAUrl": "bitmap-64bitMD5/displacement/12901125495691049846.png",
- "imageBUrl": "bitmap-64bitMD5/displacement/12901125495691049846.png",
- "isDifferent": false
- },
- {
- "expectations": {
- "bugs": [
- 1578
- ],
- "ignore-failure": null,
- "reviewed-by-human": false
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "pdf-poppler",
- "resultType": "succeeded",
- "test": "displacement"
- },
- "imageAUrl": "bitmap-64bitMD5/displacement/16285974094717334658.png",
- "imageBUrl": "bitmap-64bitMD5/displacement/16285974094717334658.png",
- "isDifferent": false
- },
- {
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "565",
- "resultType": "no-comparison",
- "test": "bigblurs"
- },
- "imageAUrl": null,
- "imageBUrl": "bitmap-64bitMD5/bigblurs/14704206703218007573.png",
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "8888",
- "resultType": "no-comparison",
- "test": "bigblurs"
- },
- "imageAUrl": null,
- "imageBUrl": "bitmap-64bitMD5/bigblurs/17309852422285247848.png",
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "gpu",
- "resultType": "no-comparison",
- "test": "bigblurs"
- },
- "imageAUrl": null,
- "imageBUrl": "bitmap-64bitMD5/bigblurs/1822195599289208664.png",
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "pdf-mac",
- "resultType": "no-comparison",
- "test": "bigblurs"
- },
- "imageAUrl": null,
- "imageBUrl": "bitmap-64bitMD5/bigblurs/16171608477794909861.png",
- "isDifferent": true
- },
- {
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "pdf-poppler",
- "resultType": "no-comparison",
- "test": "bigblurs"
- },
- "imageAUrl": null,
- "imageBUrl": "bitmap-64bitMD5/bigblurs/6539050160610613353.png",
- "isDifferent": true
- },
- {
- "expectations": {
- "bugs": [
- 1578
- ],
- "ignore-failure": null,
- "reviewed-by-human": false
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "565",
- "resultType": "succeeded",
- "test": "3x3bitmaprect"
- },
- "imageAUrl": "bitmap-64bitMD5/3x3bitmaprect/16998423976396106083.png",
- "imageBUrl": "bitmap-64bitMD5/3x3bitmaprect/16998423976396106083.png",
- "isDifferent": false
- },
- {
- "expectations": {
- "bugs": [
- 1578
- ],
- "ignore-failure": null,
- "reviewed-by-human": false
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "8888",
- "resultType": "succeeded",
- "test": "3x3bitmaprect"
- },
- "imageAUrl": "bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png",
- "imageBUrl": "bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png",
- "isDifferent": false
- },
- {
- "expectations": {
- "bugs": [
- 1578
- ],
- "ignore-failure": null,
- "reviewed-by-human": false
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "gpu",
- "resultType": "succeeded",
- "test": "3x3bitmaprect"
- },
- "imageAUrl": "bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png",
- "imageBUrl": "bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png",
- "isDifferent": false
- },
- {
- "expectations": {
- "bugs": [
- 1578
- ],
- "ignore-failure": null,
- "reviewed-by-human": false
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "pdf-mac",
- "resultType": "succeeded",
- "test": "3x3bitmaprect"
- },
- "imageAUrl": "bitmap-64bitMD5/3x3bitmaprect/8518347971308375604.png",
- "imageBUrl": "bitmap-64bitMD5/3x3bitmaprect/8518347971308375604.png",
- "isDifferent": false
- },
- {
- "expectations": {
- "bugs": [
- 1578
- ],
- "ignore-failure": null,
- "reviewed-by-human": false
- },
- "extraColumns": {
- "builder": "Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug",
- "config": "pdf-poppler",
- "resultType": "succeeded",
- "test": "3x3bitmaprect"
- },
- "imageAUrl": "bitmap-64bitMD5/3x3bitmaprect/16723580409414313678.png",
- "imageBUrl": "bitmap-64bitMD5/3x3bitmaprect/16723580409414313678.png",
- "isDifferent": false
- }
- ],
- "imageSets": {
- "diffs": {
- "baseUrl": "/static/generated-images/diffs",
- "description": "color difference per channel"
- },
- "imageA": {
- "baseUrl": "http://chromium-skia-gm.commondatastorage.googleapis.com/gm",
- "description": "expected image"
- },
- "imageB": {
- "baseUrl": "http://chromium-skia-gm.commondatastorage.googleapis.com/gm",
- "description": "actual image"
- },
- "whiteDiffs": {
- "baseUrl": "/static/generated-images/whitediffs",
- "description": "differing pixels in white"
- }
- }
-} \ No newline at end of file
diff --git a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/3x3bitmaprect.png b/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/3x3bitmaprect.png
deleted file mode 100644
index d3686ff12d..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/3x3bitmaprect.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/3x3bitmaprect/16998423976396106083.png
diff --git a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/aaclip.png b/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/aaclip.png
deleted file mode 100644
index 8a01aa825f..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/aaclip.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/aaclip/6190901827590820995.png
diff --git a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/bigblurs.png b/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/bigblurs.png
deleted file mode 100644
index 8d0646720a..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/bigblurs.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/bigblurs/2422083043229439955.png
diff --git a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/bitmapsource.png b/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/bitmapsource.png
deleted file mode 100644
index d2df08ca3a..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/bitmapsource.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/bitmapsource/17503582803589749280.png
diff --git a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_192_192.png b/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_192_192.png
deleted file mode 100644
index 5c91d33e15..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_192_192.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/filterbitmap_checkerboard_192_192/4719210487426381700.png
diff --git a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_32_2.png b/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_32_2.png
deleted file mode 100644
index 3c1de492de..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/565/filterbitmap_checkerboard_32_2.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/filterbitmap_checkerboard_32_2/15528304435129737588.png
diff --git a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/3x3bitmaprect.png b/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/3x3bitmaprect.png
deleted file mode 100644
index 656275a920..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/3x3bitmaprect.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/3x3bitmaprect/2054956815327187963.png
diff --git a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/aaclip.png b/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/aaclip.png
deleted file mode 100644
index 371a172ece..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/aaclip.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/aaclip/14456211900777561488.png
diff --git a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/bigblurs.png b/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/bigblurs.png
deleted file mode 100644
index 2d78e89be3..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/bigblurs.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/bigblurs/17309852422285247848.png
diff --git a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/bitmapsource.png b/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/bitmapsource.png
deleted file mode 100644
index 3c511d5f6a..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/bitmapsource.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/bitmapsource/16289727936158057543.png
diff --git a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_192_192.png b/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_192_192.png
deleted file mode 100644
index 9364ccdd8a..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_192_192.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/filterbitmap_checkerboard_192_192/3154864687054945306.png
diff --git a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_32_2.png b/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_32_2.png
deleted file mode 100644
index 8760be33fb..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/8888/filterbitmap_checkerboard_32_2.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/filterbitmap_checkerboard_32_2/712827739969462165.png
diff --git a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/gpu/texdata.png b/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/gpu/texdata.png
deleted file mode 100644
index fee415c72a..0000000000
--- a/gm/rebaseline_server/testdata/outputs/expected/download_actuals_test.DownloadTest.test_fetch/gpu/texdata.png
+++ /dev/null
@@ -1 +0,0 @@
-contents of bitmap-64bitMD5/texdata/3695033638604474475.png
diff --git a/gm/rebaseline_server/writable_expectations.py b/gm/rebaseline_server/writable_expectations.py
deleted file mode 100644
index 09b9cf7689..0000000000
--- a/gm/rebaseline_server/writable_expectations.py
+++ /dev/null
@@ -1,183 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Expectations on local disk that we can modify.
-"""
-
-# System-level imports
-import logging
-import os
-import re
-
-# Must fix up PYTHONPATH before importing from within Skia
-import rs_fixpypath # pylint: disable=W0611
-
-# Imports from within Skia
-from py.utils import git_utils
-import compare_rendered_pictures
-import gm_json
-import imagepair
-import results
-
-FILEPATH_RE = re.compile('.+/' + gm_json.IMAGE_FILENAME_PATTERN)
-
-SKIA_REPO = os.path.abspath(os.path.join(
- os.path.dirname(__file__), os.pardir, os.pardir, '.git'))
-
-
-class WritableExpectations(git_utils.NewGitCheckout):
- """Expectations on local disk that we can modify."""
-
- def __init__(self, set_descriptions):
- """Creates a sandbox on local disk containing writable expectations.
-
- You must use the 'with' statement to create this object in such a way that
- it cleans up after itself:
-
- with WritableExpectations(*args) as writable_expectations:
- # make modifications
- # use the modified results
- # the sandbox on local disk is automatically cleaned up here
-
- Args:
- set_descriptions: SET_DESCRIPTIONS dict describing the set we want to
- update expectations within; this tells us the subdirectory within the
- Skia repo where we keep these expectations, and the commithash at
- which the user evaluated new baselines.
- """
- file_section = set_descriptions[results.KEY__SET_DESCRIPTIONS__SECTION]
- assert file_section == gm_json.JSONKEY_EXPECTEDRESULTS
-
- source_dir = _unicode_to_ascii(
- set_descriptions[results.KEY__SET_DESCRIPTIONS__DIR])
- assert source_dir.startswith(compare_rendered_pictures.REPO_URL_PREFIX)
- repo_subdir = source_dir[len(compare_rendered_pictures.REPO_URL_PREFIX):]
- repo_revision = _unicode_to_ascii(
- set_descriptions[results.KEY__SET_DESCRIPTIONS__REPO_REVISION])
-
- logging.info('Creating a writable Skia checkout at revision "%s"...' %
- repo_revision)
- super(WritableExpectations, self).__init__(
- repository=SKIA_REPO, commit=repo_revision, subdir=repo_subdir)
-
- def modify(self, modifications):
- """Modify the contents of the checkout, using modifications from the UI.
-
- Args:
- modifications: data[KEY__LIVE_EDITS__MODIFICATIONS] coming back from the
- rebaseline_server UI frontend
- """
- logging.info('Reading in dicts from writable Skia checkout in %s ...' %
- self.root)
- dicts = results.BaseComparisons.read_dicts_from_root(self.root)
-
- # Make sure we have expected-results sections in all our output dicts.
- for pathname, adict in dicts.iteritems():
- if not adict:
- adict = {
- # TODO(stephana): These values should be defined as constants
- # somewhere, to be kept in sync between this file and
- # compare_rendered_pictures.py.
- gm_json.JSONKEY_HEADER: {
- gm_json.JSONKEY_HEADER_TYPE: 'ChecksummedImages',
- gm_json.JSONKEY_HEADER_REVISION: 1,
- }
- }
- if not adict.get(gm_json.JSONKEY_EXPECTEDRESULTS, None):
- adict[gm_json.JSONKEY_EXPECTEDRESULTS] = {}
- dicts[pathname] = adict
-
- for modification in modifications:
- expectations = modification[imagepair.KEY__IMAGEPAIRS__EXPECTATIONS]
- _add_image_info_to_expectations(
- expectations=expectations,
- filepath=modification[imagepair.KEY__IMAGEPAIRS__IMAGE_B_URL])
- extra_columns = modification[imagepair.KEY__IMAGEPAIRS__EXTRACOLUMNS]
- dictname = modification[imagepair.KEY__IMAGEPAIRS__SOURCE_JSON_FILE]
- dict_to_modify = dicts[dictname][gm_json.JSONKEY_EXPECTEDRESULTS]
- test_name = extra_columns[compare_rendered_pictures.COLUMN__SOURCE_SKP]
- test_record = dict_to_modify.get(test_name, {})
- if (extra_columns[compare_rendered_pictures.COLUMN__TILED_OR_WHOLE] ==
- compare_rendered_pictures.COLUMN__TILED_OR_WHOLE__TILED):
- test_tiles_list = test_record.get(
- gm_json.JSONKEY_SOURCE_TILEDIMAGES, [])
- tilenum = int(extra_columns[compare_rendered_pictures.COLUMN__TILENUM])
- _replace_list_item(test_tiles_list, tilenum, expectations)
- test_record[gm_json.JSONKEY_SOURCE_TILEDIMAGES] = test_tiles_list
- else:
- test_record[gm_json.JSONKEY_SOURCE_WHOLEIMAGE] = expectations
- dict_to_modify[test_name] = test_record
-
- # Write the modified files back to disk.
- self._write_dicts_to_root(meta_dict=dicts, root=self.root)
-
- def get_diffs(self):
- """Return patchfile describing any modifications to this checkout."""
- return self._run_in_git_root(args=[git_utils.GIT, 'diff'])
-
- @staticmethod
- def _write_dicts_to_root(meta_dict, root):
- """Write out multiple dictionaries in JSON format.
-
- Args:
- meta_dict: a builder-keyed meta-dictionary containing all the JSON
- dictionaries we want to write out
- root: path to root of directory tree within which to write files
- """
- if not os.path.isdir(root):
- raise IOError('no directory found at path %s' % root)
-
- for rel_path in meta_dict.keys():
- full_path = os.path.join(root, rel_path)
- gm_json.WriteToFile(meta_dict[rel_path], full_path)
-
-
-def _unicode_to_ascii(unicode_string):
- """Returns the plain ASCII form of a unicode string.
-
- TODO(stephana): We created this because we get unicode strings out of the
- JSON file, while the git filenames and revision tags are plain ASCII.
- There may be a better way to handle this... maybe set the JSON util to just
- return ASCII strings?
- """
- return unicode_string.encode('ascii', 'ignore')
-
-
-def _replace_list_item(a_list, index, value):
- """Replaces value at index "index" within a_list.
-
- Args:
- a_list: a list
- index: index indicating which item in a_list to replace
- value: value to set a_list[index] to
-
- If a_list does not contain this index, it will be extended with None entries
- to that length.
- """
- length = len(a_list)
- while index >= length:
- a_list.append(None)
- length += 1
- a_list[index] = value
-
-
-def _add_image_info_to_expectations(expectations, filepath):
- """Add JSONKEY_IMAGE_* info to an existing expectations dictionary.
-
- TODO(stephana): This assumes that the checksumAlgorithm and checksumValue
- can be derived from the filepath, which is currently true but may not always
- be true.
-
- Args:
- expectations: the expectations dict to augment
- filepath: relative path to the image file
- """
- (checksum_algorithm, checksum_value) = FILEPATH_RE.match(filepath).groups()
- expectations[gm_json.JSONKEY_IMAGE_CHECKSUMALGORITHM] = checksum_algorithm
- expectations[gm_json.JSONKEY_IMAGE_CHECKSUMVALUE] = checksum_value
- expectations[gm_json.JSONKEY_IMAGE_FILEPATH] = filepath
diff --git a/gm/rename_config.py b/gm/rename_config.py
deleted file mode 100755
index d1c6d568a7..0000000000
--- a/gm/rename_config.py
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/usr/bin/python
-# Copyright (c) 2014 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.
-
-"""Utility to rename a config in some subset of our GM expectation files.
-
-Created for http://skbug.com/2752 ('split existing "gpu" GM results into "gl"
-and "gles"')
-
-Run with -h to see usage.
-
-Example command lines:
- rename_config.py gpu gles '.*Android.*'
-
-TODO(epoger): Once https://codereview.chromium.org/397103003/ is committed,
-we should add a unittest. Until then, we can test this as follows:
-
-OLD=expectations/gm && NEW=/tmp/expectations && \
- rm -rf $NEW && \
- cp -a $OLD $NEW && \
- gm/rename_config.py msaa4 gles-msaa4 '.*Android.*' \
- --expectations-root $NEW && \
- diff --recursive $OLD $NEW
-"""
-__author__ = 'Elliot Poger'
-
-import argparse
-import os
-import re
-
-import gm_json
-
-DEFAULT_EXPECTATIONS_ROOT = os.path.join(
- os.path.dirname(__file__), os.pardir, 'expectations', 'gm')
-IMAGE_FILENAME_RE = re.compile(gm_json.IMAGE_FILENAME_PATTERN)
-
-
-class Renamer(object):
-
- def __init__(self, args):
- """
- Params:
- args: the Namespace object generated by argparse.parse_args()
- """
- self._args = args
-
- def run(self):
- """Perform all the subsitutions."""
- for path in self._get_file_list():
- self._rename_config(path=path,
- old=self._args.old_config_name,
- new=self._args.new_config_name)
-
- def _rename_config(self, path, old, new):
- """Renames all instances of a config within a GM expectations file.
-
- Params:
- path: path to file which will be modified in place
- old: old config name
- new: new config name
- """
- dic = gm_json.LoadFromFile(file_path=path)
- expected_results = dic[gm_json.JSONKEY_EXPECTEDRESULTS]
- orig_keys = expected_results.keys()
- for key in orig_keys:
- result = expected_results.pop(key)
- (testname, config) = IMAGE_FILENAME_RE.match(key).groups()
- if config == old:
- config = new
- key = '%s_%s.png' % (testname, config)
- expected_results[key] = result
- gm_json.WriteToFile(json_dict=dic, file_path=path)
-
- def _get_file_list(self):
- """Returns the list of files we want to operate on (the complete path
- to each file)."""
- root = self._args.expectations_root
- regex = re.compile(self._args.builder_name_pattern)
- return [os.path.join(root, builder, 'expected-results.json')
- for builder in os.listdir(root)
- if regex.match(builder)]
-
-
-def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('old_config_name',
- help=('Config name we want to replace.'))
- parser.add_argument('new_config_name',
- help=('Config name we want to replace the old one with.'))
- parser.add_argument('builder_name_pattern',
- help=('Regex pattern describing which builders we want '
- 'to make the substitution for; \'.*\' to perform '
- 'the replacement on all builders.'))
- parser.add_argument('--expectations-root',
- default=DEFAULT_EXPECTATIONS_ROOT,
- help=('Root of the GM expectations dir; defaults to '
- '%(default)s'))
- args = parser.parse_args()
- renamer = Renamer(args)
- renamer.run()
-
-if __name__ == '__main__':
- main()
diff --git a/gm/test_all.py b/gm/test_all.py
deleted file mode 100755
index 282ec85732..0000000000
--- a/gm/test_all.py
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/python
-
-"""
-Copyright 2014 Google Inc.
-
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-
-Run all unittests within this directory tree, recursing into subdirectories.
-"""
-
-import os
-import unittest
-
-
-def main():
- suite = unittest.TestLoader().discover(os.path.dirname(__file__),
- pattern='*_test.py')
- results = unittest.TextTestRunner(verbosity=2).run(suite)
- print repr(results)
- if not results.wasSuccessful():
- raise Exception('failed one or more unittests')
-
-if __name__ == '__main__':
- main()
diff --git a/gm/tests/.gitignore b/gm/tests/.gitignore
deleted file mode 100644
index 6b9a1e9dda..0000000000
--- a/gm/tests/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-inputs/
diff --git a/gm/tests/outputs/.gitignore b/gm/tests/outputs/.gitignore
deleted file mode 100644
index f532248c04..0000000000
--- a/gm/tests/outputs/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*/output-actual/
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/json-summary.txt b/gm/tests/outputs/add-config-pdf/output-expected/json-summary.txt
deleted file mode 100644
index a341d6a459..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/json-summary.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "actual-results" : {
- "failed" : null,
- "failure-ignored" : null,
- "no-comparison" : {
- "pdf-poppler/selftest1.png" : [ "bitmap-64bitMD5", 1149339852105949057 ]
- },
- "succeeded" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- }
- },
- "expected-results" : {
- "565/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 12927999507540085554 ]
- ],
- "ignore-failure" : false
- },
- "8888/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 1209453360120438698 ]
- ],
- "ignore-failure" : false
- },
- "pdf-poppler/selftest1.png" : {
- "allowed-digests" : null,
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/pdf-poppler/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/pdf-poppler/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/pdf-poppler/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/pdf/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/pdf/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/mismatchPath/pdf/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/pdf-poppler/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/pdf-poppler/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/pdf-poppler/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/pdf-poppler/selftest1.png b/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/pdf-poppler/selftest1.png
deleted file mode 100644
index b644e4ded7..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/pdf-poppler/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/add-config-pdf/output-actual/missingExpectationsPath/pdf-poppler/selftest1.png]
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/pdf/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/pdf/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/missingExpectationsPath/pdf/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/return_value b/gm/tests/outputs/add-config-pdf/output-expected/return_value
deleted file mode 100644
index 573541ac97..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/writePath/565/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/add-config-pdf/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index 57ced63a8b..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/add-config-pdf/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/add-config-pdf/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index da67a30059..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/add-config-pdf/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/writePath/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf-poppler/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf-poppler/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf-poppler/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf-poppler/selftest1.png b/gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf-poppler/selftest1.png
deleted file mode 100644
index 052f1a98fb..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf-poppler/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/add-config-pdf/output-actual/writePath/pdf-poppler/selftest1.png]
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf/bogusfile b/gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf/selftest1.pdf b/gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf/selftest1.pdf
deleted file mode 100644
index acca03ba40..0000000000
--- a/gm/tests/outputs/add-config-pdf/output-expected/writePath/pdf/selftest1.pdf
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/add-config-pdf/output-actual/writePath/pdf/selftest1.pdf]
diff --git a/gm/tests/outputs/checksum-based-filenames/output-expected/json-summary.txt b/gm/tests/outputs/checksum-based-filenames/output-expected/json-summary.txt
deleted file mode 100644
index b3e2a8150f..0000000000
--- a/gm/tests/outputs/checksum-based-filenames/output-expected/json-summary.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "actual-results" : {
- "failed" : {
- "selftest1_565.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "selftest1_8888.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- },
- "failure-ignored" : null,
- "no-comparison" : null,
- "succeeded" : null
- },
- "expected-results" : {
- "selftest1_565.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 8863920166200910451 ]
- ],
- "ignore-failure" : false
- },
- "selftest1_8888.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 13451349865803053525 ]
- ],
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/checksum-based-filenames/output-expected/mismatchPath/bitmap-64bitMD5_selftest1_1209453360120438698.png b/gm/tests/outputs/checksum-based-filenames/output-expected/mismatchPath/bitmap-64bitMD5_selftest1_1209453360120438698.png
deleted file mode 100644
index bd5820f02e..0000000000
--- a/gm/tests/outputs/checksum-based-filenames/output-expected/mismatchPath/bitmap-64bitMD5_selftest1_1209453360120438698.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/checksum-based-filenames/output-actual/mismatchPath/bitmap-64bitMD5_selftest1_1209453360120438698.png]
diff --git a/gm/tests/outputs/checksum-based-filenames/output-expected/mismatchPath/bitmap-64bitMD5_selftest1_12927999507540085554.png b/gm/tests/outputs/checksum-based-filenames/output-expected/mismatchPath/bitmap-64bitMD5_selftest1_12927999507540085554.png
deleted file mode 100644
index b1ab39e5bc..0000000000
--- a/gm/tests/outputs/checksum-based-filenames/output-expected/mismatchPath/bitmap-64bitMD5_selftest1_12927999507540085554.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/checksum-based-filenames/output-actual/mismatchPath/bitmap-64bitMD5_selftest1_12927999507540085554.png]
diff --git a/gm/tests/outputs/checksum-based-filenames/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/checksum-based-filenames/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/checksum-based-filenames/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/checksum-based-filenames/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/checksum-based-filenames/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/checksum-based-filenames/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/checksum-based-filenames/output-expected/return_value b/gm/tests/outputs/checksum-based-filenames/output-expected/return_value
deleted file mode 100644
index ace9d03621..0000000000
--- a/gm/tests/outputs/checksum-based-filenames/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-255
diff --git a/gm/tests/outputs/checksum-based-filenames/output-expected/writePath/bitmap-64bitMD5_selftest1_1209453360120438698.png b/gm/tests/outputs/checksum-based-filenames/output-expected/writePath/bitmap-64bitMD5_selftest1_1209453360120438698.png
deleted file mode 100644
index e13581c69f..0000000000
--- a/gm/tests/outputs/checksum-based-filenames/output-expected/writePath/bitmap-64bitMD5_selftest1_1209453360120438698.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/checksum-based-filenames/output-actual/writePath/bitmap-64bitMD5_selftest1_1209453360120438698.png]
diff --git a/gm/tests/outputs/checksum-based-filenames/output-expected/writePath/bitmap-64bitMD5_selftest1_12927999507540085554.png b/gm/tests/outputs/checksum-based-filenames/output-expected/writePath/bitmap-64bitMD5_selftest1_12927999507540085554.png
deleted file mode 100644
index 0a719f7670..0000000000
--- a/gm/tests/outputs/checksum-based-filenames/output-expected/writePath/bitmap-64bitMD5_selftest1_12927999507540085554.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/checksum-based-filenames/output-actual/writePath/bitmap-64bitMD5_selftest1_12927999507540085554.png]
diff --git a/gm/tests/outputs/checksum-based-filenames/output-expected/writePath/bogusfile b/gm/tests/outputs/checksum-based-filenames/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/checksum-based-filenames/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/json-summary.txt
deleted file mode 100644
index 7832eb0234..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/json-summary.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "actual-results" : {
- "failed" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- },
- "failure-ignored" : null,
- "no-comparison" : null,
- "succeeded" : null
- },
- "expected-results" : {
- "565/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 8863920166200910451 ]
- ],
- "ignore-failure" : false
- },
- "8888/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 13451349865803053525 ]
- ],
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/565/selftest1.png b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/565/selftest1.png
deleted file mode 100644
index 4d6827c728..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-different-pixels-images/output-actual/mismatchPath/565/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/8888/selftest1.png b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/8888/selftest1.png
deleted file mode 100644
index 6784b25dfc..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-different-pixels-images/output-actual/mismatchPath/8888/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/return_value b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/return_value
deleted file mode 100644
index ace9d03621..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-255
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/565/bogusfile b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index b3464d03ce..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-different-pixels-images/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index db19da55c5..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-different-pixels-images/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/bogusfile b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/json-summary.txt
deleted file mode 100644
index 7832eb0234..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/json-summary.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "actual-results" : {
- "failed" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- },
- "failure-ignored" : null,
- "no-comparison" : null,
- "succeeded" : null
- },
- "expected-results" : {
- "565/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 8863920166200910451 ]
- ],
- "ignore-failure" : false
- },
- "8888/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 13451349865803053525 ]
- ],
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/565/selftest1.png b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/565/selftest1.png
deleted file mode 100644
index f89763b33f..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-different-pixels-json/output-actual/mismatchPath/565/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/8888/selftest1.png b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/8888/selftest1.png
deleted file mode 100644
index e80f342a65..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-different-pixels-json/output-actual/mismatchPath/8888/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/return_value b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/return_value
deleted file mode 100644
index ace9d03621..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-255
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/565/bogusfile b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index cde22a6caa..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-different-pixels-json/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index a9e26cf922..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-different-pixels-json/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/bogusfile b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-empty-dir/output-expected/json-summary.txt
deleted file mode 100644
index 69d2050981..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/json-summary.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "actual-results" : {
- "failed" : null,
- "failure-ignored" : null,
- "no-comparison" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "565/selftest2.png" : [ "bitmap-64bitMD5", 8863920166200910451 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ],
- "8888/selftest2.png" : [ "bitmap-64bitMD5", 13451349865803053525 ]
- },
- "succeeded" : null
- },
- "expected-results" : {
- "565/selftest1.png" : {
- "allowed-digests" : null,
- "ignore-failure" : true
- },
- "565/selftest2.png" : {
- "allowed-digests" : null,
- "ignore-failure" : false
- },
- "8888/selftest1.png" : {
- "allowed-digests" : null,
- "ignore-failure" : true
- },
- "8888/selftest2.png" : {
- "allowed-digests" : null,
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/compared-against-empty-dir/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/compared-against-empty-dir/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/compared-against-empty-dir/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/565/selftest1.png b/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/565/selftest1.png
deleted file mode 100644
index 57f48edbcd..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-empty-dir/output-actual/missingExpectationsPath/565/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/565/selftest2.png b/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/565/selftest2.png
deleted file mode 100644
index 0e1a13bb6a..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/565/selftest2.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-empty-dir/output-actual/missingExpectationsPath/565/selftest2.png]
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/8888/selftest1.png b/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/8888/selftest1.png
deleted file mode 100644
index 9abe3e8913..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-empty-dir/output-actual/missingExpectationsPath/8888/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/8888/selftest2.png b/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/8888/selftest2.png
deleted file mode 100644
index 3f0282d3e6..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/8888/selftest2.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-empty-dir/output-actual/missingExpectationsPath/8888/selftest2.png]
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/return_value b/gm/tests/outputs/compared-against-empty-dir/output-expected/return_value
deleted file mode 100644
index 573541ac97..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/565/bogusfile b/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index 6fd4126d10..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-empty-dir/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/565/selftest2.png b/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/565/selftest2.png
deleted file mode 100644
index 5ef2f452b3..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/565/selftest2.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-empty-dir/output-actual/writePath/565/selftest2.png]
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index 8d82f51f6e..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-empty-dir/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/8888/selftest2.png b/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/8888/selftest2.png
deleted file mode 100644
index 9abe14053b..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/8888/selftest2.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-empty-dir/output-actual/writePath/8888/selftest2.png]
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/bogusfile b/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/json-summary.txt
deleted file mode 100644
index fad1ffe5bd..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/json-summary.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "actual-results" : {
- "failed" : null,
- "failure-ignored" : null,
- "no-comparison" : null,
- "succeeded" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- }
- },
- "expected-results" : {
- "565/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 12927999507540085554 ]
- ],
- "ignore-failure" : false
- },
- "8888/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 1209453360120438698 ]
- ],
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/return_value b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/return_value
deleted file mode 100644
index 573541ac97..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/565/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index be0614f1c7..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-identical-bytes-images/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index 6575039622..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-identical-bytes-images/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/json-summary.txt
deleted file mode 100644
index fad1ffe5bd..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/json-summary.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "actual-results" : {
- "failed" : null,
- "failure-ignored" : null,
- "no-comparison" : null,
- "succeeded" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- }
- },
- "expected-results" : {
- "565/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 12927999507540085554 ]
- ],
- "ignore-failure" : false
- },
- "8888/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 1209453360120438698 ]
- ],
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/return_value b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/return_value
deleted file mode 100644
index 573541ac97..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/565/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index 31853e30cd..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-identical-bytes-json/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index ee80ce2e71..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-identical-bytes-json/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/bogusfile b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/json-summary.txt
deleted file mode 100644
index fad1ffe5bd..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/json-summary.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "actual-results" : {
- "failed" : null,
- "failure-ignored" : null,
- "no-comparison" : null,
- "succeeded" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- }
- },
- "expected-results" : {
- "565/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 12927999507540085554 ]
- ],
- "ignore-failure" : false
- },
- "8888/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 1209453360120438698 ]
- ],
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/return_value b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/return_value
deleted file mode 100644
index 573541ac97..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/565/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index 8961f2bfd0..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-identical-pixels-images/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index 19b3ba30ad..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-identical-pixels-images/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/json-summary.txt
deleted file mode 100644
index fad1ffe5bd..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/json-summary.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "actual-results" : {
- "failed" : null,
- "failure-ignored" : null,
- "no-comparison" : null,
- "succeeded" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- }
- },
- "expected-results" : {
- "565/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 12927999507540085554 ]
- ],
- "ignore-failure" : false
- },
- "8888/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 1209453360120438698 ]
- ],
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/return_value b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/return_value
deleted file mode 100644
index 573541ac97..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/565/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index 357c3f97d7..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-identical-pixels-json/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index 1da34ea9d4..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/compared-against-identical-pixels-json/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/bogusfile b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/compared-against-nonexistent-dir/output-expected/return_value b/gm/tests/outputs/compared-against-nonexistent-dir/output-expected/return_value
deleted file mode 100644
index ace9d03621..0000000000
--- a/gm/tests/outputs/compared-against-nonexistent-dir/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-255
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/json-summary.txt b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/json-summary.txt
deleted file mode 100644
index 7832eb0234..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/json-summary.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "actual-results" : {
- "failed" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- },
- "failure-ignored" : null,
- "no-comparison" : null,
- "succeeded" : null
- },
- "expected-results" : {
- "565/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 8863920166200910451 ]
- ],
- "ignore-failure" : false
- },
- "8888/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 13451349865803053525 ]
- ],
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/565/selftest1.png b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/565/selftest1.png
deleted file mode 100644
index 95247f83b8..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignore-expectations-mismatch/output-actual/mismatchPath/565/selftest1.png]
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/8888/selftest1.png b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/8888/selftest1.png
deleted file mode 100644
index 73c78418da..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignore-expectations-mismatch/output-actual/mismatchPath/8888/selftest1.png]
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/return_value b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/return_value
deleted file mode 100644
index 573541ac97..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/565/bogusfile b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index 5b86addaea..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignore-expectations-mismatch/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index b33ea833ac..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignore-expectations-mismatch/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/bogusfile b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/json-summary.txt b/gm/tests/outputs/ignoring-one-test/output-expected/json-summary.txt
deleted file mode 100644
index 1b667830ad..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/json-summary.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "actual-results" : {
- "failed" : {
- "565/selftest2.png" : [ "bitmap-64bitMD5", 8863920166200910451 ],
- "8888/selftest2.png" : [ "bitmap-64bitMD5", 13451349865803053525 ]
- },
- "failure-ignored" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- },
- "no-comparison" : null,
- "succeeded" : null
- },
- "expected-results" : {
- "565/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 8863920166200910451 ]
- ],
- "ignore-failure" : true
- },
- "565/selftest2.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 12927999507540085554 ]
- ],
- "ignore-failure" : false
- },
- "8888/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 13451349865803053525 ]
- ],
- "ignore-failure" : true
- },
- "8888/selftest2.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 1209453360120438698 ]
- ],
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/565/selftest1.png b/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/565/selftest1.png
deleted file mode 100644
index c93c6886b8..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignoring-one-test/output-actual/mismatchPath/565/selftest1.png]
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/565/selftest2.png b/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/565/selftest2.png
deleted file mode 100644
index dab977ad2b..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/565/selftest2.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignoring-one-test/output-actual/mismatchPath/565/selftest2.png]
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/8888/selftest1.png b/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/8888/selftest1.png
deleted file mode 100644
index 1ce89fe6d4..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignoring-one-test/output-actual/mismatchPath/8888/selftest1.png]
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/8888/selftest2.png b/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/8888/selftest2.png
deleted file mode 100644
index 882a446881..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/8888/selftest2.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignoring-one-test/output-actual/mismatchPath/8888/selftest2.png]
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/ignoring-one-test/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/ignoring-one-test/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/ignoring-one-test/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/return_value b/gm/tests/outputs/ignoring-one-test/output-expected/return_value
deleted file mode 100644
index ace9d03621..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-255
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/565/bogusfile b/gm/tests/outputs/ignoring-one-test/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/ignoring-one-test/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index 0e665b884e..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignoring-one-test/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/565/selftest2.png b/gm/tests/outputs/ignoring-one-test/output-expected/writePath/565/selftest2.png
deleted file mode 100644
index b11088fd90..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/565/selftest2.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignoring-one-test/output-actual/writePath/565/selftest2.png]
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/ignoring-one-test/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/ignoring-one-test/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index 5ea72babc7..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignoring-one-test/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/8888/selftest2.png b/gm/tests/outputs/ignoring-one-test/output-expected/writePath/8888/selftest2.png
deleted file mode 100644
index 3eeb0084e9..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/8888/selftest2.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignoring-one-test/output-actual/writePath/8888/selftest2.png]
diff --git a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/bogusfile b/gm/tests/outputs/ignoring-one-test/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-one-test/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/json-summary.txt b/gm/tests/outputs/ignoring-some-failures/output-expected/json-summary.txt
deleted file mode 100644
index b152d6d035..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/json-summary.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "actual-results" : {
- "failed" : {
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- },
- "failure-ignored" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ]
- },
- "no-comparison" : null,
- "succeeded" : null
- },
- "expected-results" : {
- "565/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 8863920166200910451 ]
- ],
- "ignore-failure" : true
- },
- "8888/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 13451349865803053525 ]
- ],
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/565/selftest1.png b/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/565/selftest1.png
deleted file mode 100644
index 5a30830f5a..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignoring-some-failures/output-actual/mismatchPath/565/selftest1.png]
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/8888/selftest1.png b/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/8888/selftest1.png
deleted file mode 100644
index 734abd0f49..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignoring-some-failures/output-actual/mismatchPath/8888/selftest1.png]
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/ignoring-some-failures/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/ignoring-some-failures/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/ignoring-some-failures/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/return_value b/gm/tests/outputs/ignoring-some-failures/output-expected/return_value
deleted file mode 100644
index ace9d03621..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-255
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/565/bogusfile b/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index 4bc8ce56b4..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignoring-some-failures/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index f7f6539d50..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/ignoring-some-failures/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/bogusfile b/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/ignoring-some-failures/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/json-summary.txt b/gm/tests/outputs/intentionally-skipped-tests/output-expected/json-summary.txt
deleted file mode 100644
index f6cd87b8dd..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/json-summary.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "actual-results" : {
- "failed" : null,
- "failure-ignored" : null,
- "no-comparison" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "565/selftest2.png" : [ "bitmap-64bitMD5", 8863920166200910451 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ],
- "8888/selftest2.png" : [ "bitmap-64bitMD5", 13451349865803053525 ]
- },
- "succeeded" : null
- },
- "expected-results" : null
-}
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/intentionally-skipped-tests/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/intentionally-skipped-tests/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/intentionally-skipped-tests/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/intentionally-skipped-tests/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/intentionally-skipped-tests/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/intentionally-skipped-tests/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/return_value b/gm/tests/outputs/intentionally-skipped-tests/output-expected/return_value
deleted file mode 100644
index 573541ac97..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/565/bogusfile b/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index fd1af59fce..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/intentionally-skipped-tests/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/565/selftest2.png b/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/565/selftest2.png
deleted file mode 100644
index 44bbef7e17..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/565/selftest2.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/intentionally-skipped-tests/output-actual/writePath/565/selftest2.png]
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index a322ded4f6..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/intentionally-skipped-tests/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/8888/selftest2.png b/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/8888/selftest2.png
deleted file mode 100644
index c56ee69561..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/8888/selftest2.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/intentionally-skipped-tests/output-actual/writePath/8888/selftest2.png]
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/bogusfile b/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/no-hierarchy/output-expected/json-summary.txt b/gm/tests/outputs/no-hierarchy/output-expected/json-summary.txt
deleted file mode 100644
index b3e2a8150f..0000000000
--- a/gm/tests/outputs/no-hierarchy/output-expected/json-summary.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "actual-results" : {
- "failed" : {
- "selftest1_565.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "selftest1_8888.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- },
- "failure-ignored" : null,
- "no-comparison" : null,
- "succeeded" : null
- },
- "expected-results" : {
- "selftest1_565.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 8863920166200910451 ]
- ],
- "ignore-failure" : false
- },
- "selftest1_8888.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 13451349865803053525 ]
- ],
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/no-hierarchy/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/no-hierarchy/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/no-hierarchy/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/no-hierarchy/output-expected/mismatchPath/selftest1_565.png b/gm/tests/outputs/no-hierarchy/output-expected/mismatchPath/selftest1_565.png
deleted file mode 100644
index 16040c53c0..0000000000
--- a/gm/tests/outputs/no-hierarchy/output-expected/mismatchPath/selftest1_565.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/no-hierarchy/output-actual/mismatchPath/selftest1_565.png]
diff --git a/gm/tests/outputs/no-hierarchy/output-expected/mismatchPath/selftest1_8888.png b/gm/tests/outputs/no-hierarchy/output-expected/mismatchPath/selftest1_8888.png
deleted file mode 100644
index 4d506f8619..0000000000
--- a/gm/tests/outputs/no-hierarchy/output-expected/mismatchPath/selftest1_8888.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/no-hierarchy/output-actual/mismatchPath/selftest1_8888.png]
diff --git a/gm/tests/outputs/no-hierarchy/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/no-hierarchy/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/no-hierarchy/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/no-hierarchy/output-expected/return_value b/gm/tests/outputs/no-hierarchy/output-expected/return_value
deleted file mode 100644
index ace9d03621..0000000000
--- a/gm/tests/outputs/no-hierarchy/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-255
diff --git a/gm/tests/outputs/no-hierarchy/output-expected/writePath/bogusfile b/gm/tests/outputs/no-hierarchy/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/no-hierarchy/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/no-hierarchy/output-expected/writePath/selftest1_565.png b/gm/tests/outputs/no-hierarchy/output-expected/writePath/selftest1_565.png
deleted file mode 100644
index ddb053f75b..0000000000
--- a/gm/tests/outputs/no-hierarchy/output-expected/writePath/selftest1_565.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/no-hierarchy/output-actual/writePath/selftest1_565.png]
diff --git a/gm/tests/outputs/no-hierarchy/output-expected/writePath/selftest1_8888.png b/gm/tests/outputs/no-hierarchy/output-expected/writePath/selftest1_8888.png
deleted file mode 100644
index 1bf8130365..0000000000
--- a/gm/tests/outputs/no-hierarchy/output-expected/writePath/selftest1_8888.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/no-hierarchy/output-actual/writePath/selftest1_8888.png]
diff --git a/gm/tests/outputs/no-readpath/output-expected/json-summary.txt b/gm/tests/outputs/no-readpath/output-expected/json-summary.txt
deleted file mode 100644
index 006516eda6..0000000000
--- a/gm/tests/outputs/no-readpath/output-expected/json-summary.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "actual-results" : {
- "failed" : null,
- "failure-ignored" : null,
- "no-comparison" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- },
- "succeeded" : null
- },
- "expected-results" : null
-}
diff --git a/gm/tests/outputs/no-readpath/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/no-readpath/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/no-readpath/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/no-readpath/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/no-readpath/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/no-readpath/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/no-readpath/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/no-readpath/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/no-readpath/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/no-readpath/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/no-readpath/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/no-readpath/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/no-readpath/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/no-readpath/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/no-readpath/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/no-readpath/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/no-readpath/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/no-readpath/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/no-readpath/output-expected/return_value b/gm/tests/outputs/no-readpath/output-expected/return_value
deleted file mode 100644
index 573541ac97..0000000000
--- a/gm/tests/outputs/no-readpath/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/gm/tests/outputs/no-readpath/output-expected/writePath/565/bogusfile b/gm/tests/outputs/no-readpath/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/no-readpath/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/no-readpath/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/no-readpath/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index 2943f0a91c..0000000000
--- a/gm/tests/outputs/no-readpath/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/no-readpath/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/no-readpath/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/no-readpath/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/no-readpath/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/no-readpath/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/no-readpath/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index 50a0c247ae..0000000000
--- a/gm/tests/outputs/no-readpath/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/no-readpath/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/no-readpath/output-expected/writePath/bogusfile b/gm/tests/outputs/no-readpath/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/no-readpath/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/nonverbose/output-expected/json-summary.txt b/gm/tests/outputs/nonverbose/output-expected/json-summary.txt
deleted file mode 100644
index 57aee04201..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/json-summary.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "actual-results" : {
- "failed" : null,
- "failure-ignored" : null,
- "no-comparison" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- },
- "succeeded" : null
- },
- "expected-results" : {
- "565/selftest1.png" : {
- "allowed-digests" : null,
- "ignore-failure" : false
- },
- "8888/selftest1.png" : {
- "allowed-digests" : null,
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/nonverbose/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/nonverbose/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/nonverbose/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/nonverbose/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/nonverbose/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/nonverbose/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/565/selftest1.png b/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/565/selftest1.png
deleted file mode 100644
index a8ef872350..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/nonverbose/output-actual/missingExpectationsPath/565/selftest1.png]
diff --git a/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/8888/selftest1.png b/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/8888/selftest1.png
deleted file mode 100644
index 9132f60667..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/nonverbose/output-actual/missingExpectationsPath/8888/selftest1.png]
diff --git a/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/nonverbose/output-expected/return_value b/gm/tests/outputs/nonverbose/output-expected/return_value
deleted file mode 100644
index 573541ac97..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/gm/tests/outputs/nonverbose/output-expected/writePath/565/bogusfile b/gm/tests/outputs/nonverbose/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/nonverbose/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/nonverbose/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index 6b9d422388..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/nonverbose/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/nonverbose/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/nonverbose/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/nonverbose/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/nonverbose/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index 4f04a60380..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/nonverbose/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/nonverbose/output-expected/writePath/bogusfile b/gm/tests/outputs/nonverbose/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/nonverbose/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/json-summary.txt b/gm/tests/outputs/pipe-playback-failure/output-expected/json-summary.txt
deleted file mode 100644
index ebe8b592b0..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/json-summary.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "actual-results" : {
- "failed" : {
- "565/selftest1-pipe.png" : [ "bitmap-64bitMD5", 6140979239232854774 ],
- "8888/selftest1-pipe.png" : [ "bitmap-64bitMD5", 6140979239232854774 ]
- },
- "failure-ignored" : null,
- "no-comparison" : null,
- "succeeded" : {
- "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
- "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
- }
- },
- "expected-results" : {
- "565/selftest1-pipe.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 12927999507540085554 ]
- ],
- "ignore-failure" : false
- },
- "565/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 12927999507540085554 ]
- ],
- "ignore-failure" : false
- },
- "8888/selftest1-pipe.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 1209453360120438698 ]
- ],
- "ignore-failure" : false
- },
- "8888/selftest1.png" : {
- "allowed-digests" : [
- [ "bitmap-64bitMD5", 1209453360120438698 ]
- ],
- "ignore-failure" : false
- }
- }
-}
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/565/bogusfile b/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/565/selftest1-pipe.png b/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/565/selftest1-pipe.png
deleted file mode 100644
index 6e665c4e55..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/565/selftest1-pipe.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/pipe-playback-failure/output-actual/mismatchPath/565/selftest1-pipe.png]
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/8888/bogusfile b/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/8888/selftest1-pipe.png b/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/8888/selftest1-pipe.png
deleted file mode 100644
index 0426b8ce9d..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/8888/selftest1-pipe.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/pipe-playback-failure/output-actual/mismatchPath/8888/selftest1-pipe.png]
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/bogusfile b/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/mismatchPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/missingExpectationsPath/565/bogusfile b/gm/tests/outputs/pipe-playback-failure/output-expected/missingExpectationsPath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/missingExpectationsPath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/missingExpectationsPath/8888/bogusfile b/gm/tests/outputs/pipe-playback-failure/output-expected/missingExpectationsPath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/missingExpectationsPath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/missingExpectationsPath/bogusfile b/gm/tests/outputs/pipe-playback-failure/output-expected/missingExpectationsPath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/missingExpectationsPath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/return_value b/gm/tests/outputs/pipe-playback-failure/output-expected/return_value
deleted file mode 100644
index ace9d03621..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/return_value
+++ /dev/null
@@ -1 +0,0 @@
-255
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/565/bogusfile b/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/565/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/565/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/565/selftest1.png b/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/565/selftest1.png
deleted file mode 100644
index 5fec2967aa..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/565/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/pipe-playback-failure/output-actual/writePath/565/selftest1.png]
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/8888/bogusfile b/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/8888/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/8888/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/8888/selftest1.png b/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/8888/selftest1.png
deleted file mode 100644
index 975f68fcb2..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/8888/selftest1.png
+++ /dev/null
@@ -1 +0,0 @@
-[contents of gm/tests/outputs/pipe-playback-failure/output-actual/writePath/8888/selftest1.png]
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/bogusfile b/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/bogusfile
deleted file mode 100644
index d86cd5bdd8..0000000000
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/writePath/bogusfile
+++ /dev/null
@@ -1 +0,0 @@
-Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories.
diff --git a/gm/tests/rebaseline.sh b/gm/tests/rebaseline.sh
deleted file mode 100755
index 608e66791a..0000000000
--- a/gm/tests/rebaseline.sh
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/bin/bash
-
-# Rebaseline the outputs/*/output-expected/ subdirectories used by the
-# gm self-tests.
-# Use with caution: are you sure the new results are actually correct?
-#
-# TODO: currently, this must be run on Linux to generate baselines that match
-# the ones on the housekeeper bot (which runs on Linux... see
-# http://70.32.156.51:10117/builders/Skia_PerCommit_House_Keeping/builds/1417/steps/RunGmSelfTests/logs/stdio )
-# See https://code.google.com/p/skia/issues/detail?id=677
-# ('make tools/tests/run.sh work cross-platform')
-
-function replace_expected_with_actual {
- # Delete all the expected output files
- EXPECTED_FILES=$(find outputs/*/output-expected -type f | grep -v /\.svn/)
- for EXPECTED_FILE in $EXPECTED_FILES; do
- rm $EXPECTED_FILE
- done
-
- # Copy all the actual output files into the "expected" directories,
- # creating new subdirs as we go.
- ACTUAL_FILES=$(find outputs/*/output-actual -type f | grep -v /\.svn/)
- for ACTUAL_FILE in $ACTUAL_FILES; do
- EXPECTED_FILE=${ACTUAL_FILE//actual/expected}
- mkdir -p $(dirname $EXPECTED_FILE)
- cp $ACTUAL_FILE $EXPECTED_FILE
- done
-}
-
-function svn_add_new_files {
- # Delete all the "actual" directories, so we can svn-add any new "expected"
- # directories without adding the "actual" ones.
- rm -rf outputs/*/output-actual
- FILES=$(svn stat outputs/* | grep ^\? | awk '{print $2}')
- for FILE in $FILES; do
- svn add $FILE
- done
- FILES=$(svn stat outputs/*/output-expected | grep ^\? | awk '{print $2}')
- for FILE in $FILES; do
- svn add $FILE
- done
-}
-
-function svn_delete_old_files {
- FILES=$(svn stat outputs/*/output-expected | grep ^\! | awk '{print $2}')
- for FILE in $FILES; do
- svn rm $FILE
- done
- FILES=$(svn stat outputs/* | grep ^\! | awk '{print $2}')
- for FILE in $FILES; do
- svn rm $FILE
- done
-}
-
-
-# cd into the gm self-test dir
-cd $(dirname $0)
-
-./run.sh
-SELFTEST_RESULT=$?
-echo
-if [ "$SELFTEST_RESULT" != "0" ]; then
- replace_expected_with_actual
- svn_add_new_files
- svn_delete_old_files
- echo "Rebaseline completed. If you run run.sh now, it should succeed."
-else
- echo "Self-tests succeeded, nothing to rebaseline."
-fi
-exit $SELFTEST_RESULT
-
diff --git a/gm/tests/run.sh b/gm/tests/run.sh
deleted file mode 100755
index 52ed6f309f..0000000000
--- a/gm/tests/run.sh
+++ /dev/null
@@ -1,277 +0,0 @@
-#!/bin/bash
-
-# Self-tests for gm, based on tools/tests/run.sh
-#
-# These tests are run by the Skia_PerCommit_House_Keeping bot at every commit,
-# so make sure that they still pass when you make changes to gm!
-#
-# To generate new baselines when gm behavior changes, run gm/tests/rebaseline.sh
-#
-# TODO: because this is written as a shell script (instead of, say, Python)
-# it only runs on Linux and Mac.
-# See https://code.google.com/p/skia/issues/detail?id=677
-# ('make tools/tests/run.sh work cross-platform')
-# Ideally, these tests should pass on all development platforms...
-# otherwise, how can developers be expected to test them before committing a
-# change?
-
-# cd into .../trunk so all the paths will work
-cd $(dirname $0)/../..
-
-# TODO(epoger): make it look in Release and/or Debug
-GM_BINARY=out/Debug/gm
-
-OUTPUT_ACTUAL_SUBDIR=output-actual
-OUTPUT_EXPECTED_SUBDIR=output-expected
-CONFIGS="--config 8888 565"
-
-ENCOUNTERED_ANY_ERRORS=0
-
-# Compare contents of all files within directories $1 and $2,
-# EXCEPT for any dotfiles.
-# If there are any differences, a description is written to stdout and
-# we exit with a nonzero return value.
-# Otherwise, we write nothing to stdout and return.
-function compare_directories {
- if [ $# != 2 ]; then
- echo "compare_directories requires exactly 2 parameters, got $#"
- exit 1
- fi
- diff -r --exclude=.* $1 $2
- if [ $? != 0 ]; then
- echo "failed in: compare_directories $1 $2"
- ENCOUNTERED_ANY_ERRORS=1
- fi
-}
-
-# Run a command, and validate that it succeeds (returns 0).
-function assert_passes {
- COMMAND="$1"
- echo
- echo "assert_passes $COMMAND ..."
- $COMMAND
- if [ $? != 0 ]; then
- echo "This command was supposed to pass, but failed: [$COMMAND]"
- ENCOUNTERED_ANY_ERRORS=1
- fi
-}
-
-# Run a command, and validate that it fails (returns nonzero).
-function assert_fails {
- COMMAND="$1"
- echo
- echo "assert_fails $COMMAND ..."
- $COMMAND
- if [ $? == 0 ]; then
- echo "This command was supposed to fail, but passed: [$COMMAND]"
- ENCOUNTERED_ANY_ERRORS=1
- fi
-}
-
-# Run gm...
-# - with the arguments in $1
-# - writing json summary into $2/$OUTPUT_ACTUAL_SUBDIR/json-summary.txt
-# - writing return value into $2/$OUTPUT_ACTUAL_SUBDIR/return_value
-# Then compare all of those against $2/$OUTPUT_EXPECTED_SUBDIR .
-function gm_test {
- if [ $# != 2 ]; then
- echo "gm_test requires exactly 2 parameters, got $#"
- exit 1
- fi
- GM_ARGS="$1"
- ACTUAL_OUTPUT_DIR="$2/$OUTPUT_ACTUAL_SUBDIR"
- EXPECTED_OUTPUT_DIR="$2/$OUTPUT_EXPECTED_SUBDIR"
- JSON_SUMMARY_FILE="$ACTUAL_OUTPUT_DIR/json-summary.txt"
-
- rm -rf $ACTUAL_OUTPUT_DIR
- mkdir -p $ACTUAL_OUTPUT_DIR
-
- COMMAND="$GM_BINARY $GM_ARGS --writeJsonSummaryPath $JSON_SUMMARY_FILE --writePath $ACTUAL_OUTPUT_DIR/writePath --mismatchPath $ACTUAL_OUTPUT_DIR/mismatchPath --missingExpectationsPath $ACTUAL_OUTPUT_DIR/missingExpectationsPath"
-
- $COMMAND
- echo $? >$ACTUAL_OUTPUT_DIR/return_value
-
- # Replace image file contents with just the filename, for two reasons:
- # 1. Image file encoding may vary by platform
- # 2. https://code.google.com/p/chromium/issues/detail?id=169600
- # ('gcl/upload.py fail to upload binary files to rietveld')
- for IMAGEFILE in $(find $ACTUAL_OUTPUT_DIR -name \*.png); do
- echo "[contents of $IMAGEFILE]" >$IMAGEFILE
- done
- for IMAGEFILE in $(find $ACTUAL_OUTPUT_DIR -name \*.pdf); do
- echo "[contents of $IMAGEFILE]" >$IMAGEFILE
- done
-
- # Add a file to any empty subdirectories.
- for DIR in $(find $ACTUAL_OUTPUT_DIR -mindepth 1 -type d); do
- echo "Created additional file to make sure directory isn't empty, because self-test cannot handle empty directories." >$DIR/bogusfile
- done
-
- compare_directories $EXPECTED_OUTPUT_DIR $ACTUAL_OUTPUT_DIR
-}
-
-# Swap contents of two files at paths $1 and $2.
-function swap_files {
- if [ $# != 2 ]; then
- echo "swap_files requires exactly 2 parameters, got $#"
- exit 1
- fi
- mv "$1" "$1.tmp"
- mv "$2" "$1"
- mv "$1.tmp" "$2"
-}
-
-# Create input dir (at path $1) with expectations (both image and json)
-# that gm will match or mismatch as appropriate.
-#
-# We used to check these files into SVN, but then we needed to rebaseline them
-# when our drawing changed at all... so, as proposed in
-# http://code.google.com/p/skia/issues/detail?id=1068 , we generate them
-# new each time.
-function create_inputs_dir {
- if [ $# != 1 ]; then
- echo "create_inputs_dir requires exactly 1 parameter, got $#"
- exit 1
- fi
- INPUTS_DIR="$1"
- IMAGES_DIR=$INPUTS_DIR/images
- JSON_DIR=$INPUTS_DIR/json
- mkdir -p $IMAGES_DIR $JSON_DIR
-
- THIS_IMAGE_DIR=$IMAGES_DIR/identical-bytes
- mkdir -p $THIS_IMAGE_DIR
- # Run GM to write out the images actually generated.
- $GM_BINARY --hierarchy --match selftest1 $CONFIGS -w $THIS_IMAGE_DIR
- # Run GM again to read in those images and write them out as a JSON summary.
- $GM_BINARY --hierarchy --match selftest1 $CONFIGS -r $THIS_IMAGE_DIR \
- --writeJsonSummaryPath $JSON_DIR/identical-bytes.json
-
- THIS_IMAGE_DIR=$IMAGES_DIR/identical-pixels
- mkdir -p $THIS_IMAGE_DIR
- $GM_BINARY --hierarchy --match selftest1 $CONFIGS -w $THIS_IMAGE_DIR
- echo "more bytes that do not change the image pixels" \
- >> $THIS_IMAGE_DIR/8888/selftest1.png
- echo "more bytes that do not change the image pixels" \
- >> $THIS_IMAGE_DIR/565/selftest1.png
- $GM_BINARY --hierarchy --match selftest1 $CONFIGS -r $THIS_IMAGE_DIR \
- --writeJsonSummaryPath $JSON_DIR/identical-pixels.json
-
- THIS_IMAGE_DIR=$IMAGES_DIR/different-pixels
- mkdir -p $THIS_IMAGE_DIR
- $GM_BINARY --hierarchy --match selftest $CONFIGS -w $THIS_IMAGE_DIR
- swap_files $THIS_IMAGE_DIR/8888/selftest2.png $THIS_IMAGE_DIR/8888/selftest1.png
- swap_files $THIS_IMAGE_DIR/565/selftest2.png $THIS_IMAGE_DIR/565/selftest1.png
- $GM_BINARY --hierarchy --match selftest $CONFIGS -r $THIS_IMAGE_DIR \
- --writeJsonSummaryPath $JSON_DIR/different-pixels.json
-
- # Create another JSON expectations file which is identical to
- # different-pixels.json, but in which the *first* ignore-failure is changed
- # from false to true.
- OLD='"ignore-failure" : false'
- NEW='"ignore-failure" : true'
- sed -e "0,/$OLD/{s/$OLD/$NEW/}" $JSON_DIR/different-pixels.json \
- >$JSON_DIR/different-pixels-ignore-some-failures.json
-
- THIS_IMAGE_DIR=$IMAGES_DIR/different-pixels-no-hierarchy
- mkdir -p $THIS_IMAGE_DIR
- $GM_BINARY --match selftest2 $CONFIGS -w $THIS_IMAGE_DIR
- mv $THIS_IMAGE_DIR/selftest2_8888.png $THIS_IMAGE_DIR/selftest1_8888.png
- mv $THIS_IMAGE_DIR/selftest2_565.png $THIS_IMAGE_DIR/selftest1_565.png
- $GM_BINARY --match selftest1 $CONFIGS -r $THIS_IMAGE_DIR \
- --writeJsonSummaryPath $JSON_DIR/different-pixels-no-hierarchy.json
-
- mkdir -p $IMAGES_DIR/empty-dir
-
- echo "# Comment line" >$GM_IGNORE_FAILURES_FILE
- echo "" >>$GM_IGNORE_FAILURES_FILE
- echo "# ignore any runs of the 'selftest1' test" >>$GM_IGNORE_FAILURES_FILE
- echo "selftest1" >>$GM_IGNORE_FAILURES_FILE
- echo "" >>$GM_IGNORE_FAILURES_FILE
- echo "# make sure we don't do partial matches (should NOT ignore 'selftest2' runs)" >>$GM_IGNORE_FAILURES_FILE
- echo "selftest" >>$GM_IGNORE_FAILURES_FILE
-}
-
-GM_TESTDIR=gm/tests
-GM_INPUTS=$GM_TESTDIR/inputs
-GM_OUTPUTS=$GM_TESTDIR/outputs
-GM_TEMPFILES=$GM_TESTDIR/tempfiles
-GM_IGNORE_FAILURES_FILE=$GM_INPUTS/ignored-tests.txt
-
-create_inputs_dir $GM_INPUTS
-
-# Compare generated image against an input image file with identical bytes.
-gm_test "--verbose --hierarchy --match selftest1 $CONFIGS -r $GM_INPUTS/images/identical-bytes" "$GM_OUTPUTS/compared-against-identical-bytes-images"
-gm_test "--verbose --hierarchy --match selftest1 $CONFIGS -r $GM_INPUTS/json/identical-bytes.json" "$GM_OUTPUTS/compared-against-identical-bytes-json"
-
-# Compare generated image against an input image file with identical pixels but different PNG encoding.
-gm_test "--verbose --hierarchy --match selftest1 $CONFIGS -r $GM_INPUTS/images/identical-pixels" "$GM_OUTPUTS/compared-against-identical-pixels-images"
-gm_test "--verbose --hierarchy --match selftest1 $CONFIGS -r $GM_INPUTS/json/identical-pixels.json" "$GM_OUTPUTS/compared-against-identical-pixels-json"
-
-# Compare generated image against an input image file with different pixels.
-gm_test "--verbose --hierarchy --match selftest1 $CONFIGS -r $GM_INPUTS/images/different-pixels" "$GM_OUTPUTS/compared-against-different-pixels-images"
-gm_test "--verbose --hierarchy --match selftest1 $CONFIGS -r $GM_INPUTS/json/different-pixels.json" "$GM_OUTPUTS/compared-against-different-pixels-json"
-
-# Exercise --ignoreFailuresFile flag.
-# This should run two GM tests: selftest1 and selftest2.
-# Failures in selftest1 should be ignored, but failures in selftest2 should not.
-gm_test "--verbose --hierarchy --match selftest --ignoreFailuresFile $GM_IGNORE_FAILURES_FILE $CONFIGS -r $GM_INPUTS/json/different-pixels.json" "$GM_OUTPUTS/ignoring-one-test"
-
-# Compare different pixels, but with a SUBSET of the expectations marked as
-# ignore-failure.
-gm_test "--verbose --hierarchy --match selftest1 $CONFIGS -r $GM_INPUTS/json/different-pixels-ignore-some-failures.json" "$GM_OUTPUTS/ignoring-some-failures"
-
-# Compare generated image against an empty "expected image" dir.
-# Even the tests that have been marked as ignore-failure (selftest1) should
-# show up as no-comparison.
-gm_test "--verbose --hierarchy --match selftest --ignoreFailuresFile $GM_IGNORE_FAILURES_FILE $CONFIGS -r $GM_INPUTS/images/empty-dir" "$GM_OUTPUTS/compared-against-empty-dir"
-
-# Compare generated image against a nonexistent "expected image" dir.
-gm_test "--verbose --hierarchy --match selftest1 $CONFIGS -r ../path/to/nowhere" "$GM_OUTPUTS/compared-against-nonexistent-dir"
-
-# Compare generated image against an empty "expected image" dir, but NOT in verbose mode.
-gm_test "--hierarchy --match selftest1 $CONFIGS -r $GM_INPUTS/images/empty-dir" "$GM_OUTPUTS/nonverbose"
-
-# Add pdf to the list of configs.
-gm_test "--verbose --hierarchy --match selftest1 $CONFIGS pdf -r $GM_INPUTS/json/identical-bytes.json" "$GM_OUTPUTS/add-config-pdf"
-
-# Test what happens if run without -r (no expected-results.json to compare
-# against).
-gm_test "--verbose --hierarchy --match selftest1 $CONFIGS" "$GM_OUTPUTS/no-readpath"
-
-# Test what happens if a subset of the renderModes fail (e.g. pipe)
-gm_test "--pipe --simulatePipePlaybackFailure --verbose --hierarchy --match selftest1 $CONFIGS -r $GM_INPUTS/json/identical-pixels.json" "$GM_OUTPUTS/pipe-playback-failure"
-
-# Confirm that IntentionallySkipped tests are recorded as such.
-gm_test "--verbose --hierarchy --match selftest1 selftest2 $CONFIGS" "$GM_OUTPUTS/intentionally-skipped-tests"
-
-# Ignore some error types (including ExpectationsMismatch)
-gm_test "--ignoreErrorTypes ExpectationsMismatch NoGpuContext --verbose --hierarchy --match selftest1 $CONFIGS -r $GM_INPUTS/json/different-pixels.json" "$GM_OUTPUTS/ignore-expectations-mismatch"
-
-# Test non-hierarchical mode.
-gm_test "--verbose --match selftest1 $CONFIGS -r $GM_INPUTS/json/different-pixels-no-hierarchy.json" "$GM_OUTPUTS/no-hierarchy"
-
-# Try writing out actual images using checksum-based filenames, like we do when
-# uploading to Google Storage.
-gm_test "--verbose --writeChecksumBasedFilenames --match selftest1 $CONFIGS -r $GM_INPUTS/json/different-pixels-no-hierarchy.json" "$GM_OUTPUTS/checksum-based-filenames"
-
-# Exercise display_json_results.py
-PASSING_CASES="compared-against-identical-bytes-json compared-against-identical-pixels-json"
-FAILING_CASES="compared-against-different-pixels-json"
-for CASE in $PASSING_CASES; do
- assert_passes "python gm/display_json_results.py $GM_OUTPUTS/$CASE/$OUTPUT_EXPECTED_SUBDIR/json-summary.txt"
-done
-for CASE in $FAILING_CASES; do
- assert_fails "python gm/display_json_results.py $GM_OUTPUTS/$CASE/$OUTPUT_EXPECTED_SUBDIR/json-summary.txt"
-done
-
-# Exercise all Python unittests.
-assert_passes "python gm/test_all.py"
-
-echo
-if [ $ENCOUNTERED_ANY_ERRORS == 0 ]; then
- echo "All tests passed."
- exit 0
-else
- echo "Some tests failed."
- exit 1
-fi