| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  | #!/usr/bin/env python3 | 
					
						
							|  |  |  | # Apache License, Version 2.0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import argparse | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  | import glob | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  | import pathlib | 
					
						
							| 
									
										
										
										
											2017-08-19 12:09:28 +02:00
										 |  |  | import shlex | 
					
						
							| 
									
										
										
										
											2016-06-14 00:39:49 +02:00
										 |  |  | import shutil | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  | import subprocess | 
					
						
							|  |  |  | import sys | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  | import time | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  | import tempfile | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  | class COLORS_ANSI: | 
					
						
							|  |  |  |     RED = '\033[00;31m' | 
					
						
							|  |  |  |     GREEN = '\033[00;32m' | 
					
						
							|  |  |  |     ENDC = '\033[0m' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class COLORS_DUMMY: | 
					
						
							|  |  |  |     RED = '' | 
					
						
							|  |  |  |     GREEN = '' | 
					
						
							|  |  |  |     ENDC = '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | COLORS = COLORS_DUMMY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  | def print_message(message, type=None, status=''): | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |     if type == 'SUCCESS': | 
					
						
							|  |  |  |         print(COLORS.GREEN, end="") | 
					
						
							|  |  |  |     elif type == 'FAILURE': | 
					
						
							|  |  |  |         print(COLORS.RED, end="") | 
					
						
							|  |  |  |     status_text = ... | 
					
						
							|  |  |  |     if status == 'RUN': | 
					
						
							|  |  |  |         status_text = " RUN      " | 
					
						
							|  |  |  |     elif status == 'OK': | 
					
						
							|  |  |  |         status_text = "       OK " | 
					
						
							|  |  |  |     elif status == 'PASSED': | 
					
						
							|  |  |  |         status_text = "  PASSED  " | 
					
						
							|  |  |  |     elif status == 'FAILED': | 
					
						
							|  |  |  |         status_text = "  FAILED  " | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         status_text = status | 
					
						
							|  |  |  |     print("[{}]" . format(status_text), end="") | 
					
						
							|  |  |  |     print(COLORS.ENDC, end="") | 
					
						
							|  |  |  |     print(" {}" . format(message)) | 
					
						
							|  |  |  |     sys.stdout.flush() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  | def render_file(filepath): | 
					
						
							| 
									
										
										
										
											2017-02-10 14:52:54 +01:00
										 |  |  |     dirname = os.path.dirname(filepath) | 
					
						
							|  |  |  |     basedir = os.path.dirname(dirname) | 
					
						
							|  |  |  |     subject = os.path.basename(dirname) | 
					
						
							| 
									
										
										
										
											2017-08-19 12:09:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     custom_args = os.getenv('CYCLESTEST_ARGS') | 
					
						
							|  |  |  |     custom_args = shlex.split(custom_args) if custom_args else [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # OSL and GPU examples | 
					
						
							|  |  |  |     # custom_args += ["--python-expr", "import bpy; bpy.context.scene.cycles.shading_system = True"] | 
					
						
							|  |  |  |     # custom_args += ["--python-expr", "import bpy; bpy.context.scene.cycles.device = 'GPU'"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-10 14:52:54 +01:00
										 |  |  |     if subject == 'opengl': | 
					
						
							| 
									
										
										
										
											2017-08-19 12:09:28 +02:00
										 |  |  |         command = [ | 
					
						
							| 
									
										
										
										
											2017-02-10 14:52:54 +01:00
										 |  |  |             BLENDER, | 
					
						
							|  |  |  |             "--window-geometry", "0", "0", "1", "1", | 
					
						
							|  |  |  |             "-noaudio", | 
					
						
							|  |  |  |             "--factory-startup", | 
					
						
							|  |  |  |             "--enable-autoexec", | 
					
						
							|  |  |  |             filepath, | 
					
						
							| 
									
										
										
										
											2017-08-19 12:09:28 +02:00
										 |  |  |             "-E", "CYCLES"] | 
					
						
							|  |  |  |         command += custom_args | 
					
						
							|  |  |  |         command += [ | 
					
						
							| 
									
										
										
										
											2017-02-10 14:52:54 +01:00
										 |  |  |             "-o", TEMP_FILE_MASK, | 
					
						
							|  |  |  |             "-F", "PNG", | 
					
						
							|  |  |  |             '--python', os.path.join(basedir, | 
					
						
							|  |  |  |                                      "util", | 
					
						
							| 
									
										
										
										
											2017-08-19 12:09:28 +02:00
										 |  |  |                                      "render_opengl.py")] | 
					
						
							| 
									
										
										
										
											2017-02-10 14:52:54 +01:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2017-08-19 12:09:28 +02:00
										 |  |  |         command = [ | 
					
						
							| 
									
										
										
										
											2017-02-10 14:52:54 +01:00
										 |  |  |             BLENDER, | 
					
						
							|  |  |  |             "--background", | 
					
						
							|  |  |  |             "-noaudio", | 
					
						
							|  |  |  |             "--factory-startup", | 
					
						
							|  |  |  |             "--enable-autoexec", | 
					
						
							|  |  |  |             filepath, | 
					
						
							| 
									
										
										
										
											2017-08-19 12:09:28 +02:00
										 |  |  |             "-E", "CYCLES"] | 
					
						
							|  |  |  |         command += custom_args | 
					
						
							|  |  |  |         command += [ | 
					
						
							| 
									
										
										
										
											2017-02-10 14:52:54 +01:00
										 |  |  |             "-o", TEMP_FILE_MASK, | 
					
						
							|  |  |  |             "-F", "PNG", | 
					
						
							| 
									
										
										
										
											2017-08-19 12:09:28 +02:00
										 |  |  |             "-f", "1"] | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     try: | 
					
						
							|  |  |  |         output = subprocess.check_output(command) | 
					
						
							|  |  |  |         if VERBOSE: | 
					
						
							|  |  |  |             print(output.decode("utf-8")) | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  |     except subprocess.CalledProcessError as e: | 
					
						
							|  |  |  |         if os.path.exists(TEMP_FILE): | 
					
						
							|  |  |  |             os.remove(TEMP_FILE) | 
					
						
							|  |  |  |         if VERBOSE: | 
					
						
							|  |  |  |             print(e.output.decode("utf-8")) | 
					
						
							|  |  |  |         if b"Error: engine not found" in e.output: | 
					
						
							|  |  |  |             return "NO_CYCLES" | 
					
						
							|  |  |  |         elif b"blender probably wont start" in e.output: | 
					
						
							|  |  |  |             return "NO_START" | 
					
						
							|  |  |  |         return "CRASH" | 
					
						
							| 
									
										
										
										
											2016-09-10 22:55:28 +02:00
										 |  |  |     except BaseException as e: | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |         if os.path.exists(TEMP_FILE): | 
					
						
							|  |  |  |             os.remove(TEMP_FILE) | 
					
						
							|  |  |  |         if VERBOSE: | 
					
						
							| 
									
										
										
										
											2016-09-10 22:55:28 +02:00
										 |  |  |             print(e) | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |         return "CRASH" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def test_get_name(filepath): | 
					
						
							|  |  |  |     filename = os.path.basename(filepath) | 
					
						
							|  |  |  |     return os.path.splitext(filename)[0] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  | def test_get_images(filepath): | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     testname = test_get_name(filepath) | 
					
						
							|  |  |  |     dirpath = os.path.dirname(filepath) | 
					
						
							| 
									
										
										
										
											2017-08-18 00:37:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     old_dirpath = os.path.join(dirpath, "reference_renders") | 
					
						
							|  |  |  |     old_img = os.path.join(old_dirpath, testname + ".png") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ref_dirpath = os.path.join(OUTDIR, os.path.basename(dirpath), "ref") | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     ref_img = os.path.join(ref_dirpath, testname + ".png") | 
					
						
							| 
									
										
										
										
											2017-08-18 00:37:45 +02:00
										 |  |  |     if not os.path.exists(ref_dirpath): | 
					
						
							|  |  |  |         os.makedirs(ref_dirpath) | 
					
						
							|  |  |  |     if os.path.exists(old_img): | 
					
						
							|  |  |  |         shutil.copy(old_img, ref_img) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     new_dirpath = os.path.join(OUTDIR, os.path.basename(dirpath)) | 
					
						
							|  |  |  |     if not os.path.exists(new_dirpath): | 
					
						
							|  |  |  |         os.makedirs(new_dirpath) | 
					
						
							|  |  |  |     new_img = os.path.join(new_dirpath, testname + ".png") | 
					
						
							| 
									
										
										
										
											2017-08-18 00:37:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     diff_dirpath = os.path.join(OUTDIR, os.path.basename(dirpath), "diff") | 
					
						
							|  |  |  |     if not os.path.exists(diff_dirpath): | 
					
						
							|  |  |  |         os.makedirs(diff_dirpath) | 
					
						
							|  |  |  |     diff_img = os.path.join(diff_dirpath, testname + ".diff.png") | 
					
						
							| 
									
										
										
										
											2017-08-18 00:37:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     return ref_img, new_img, diff_img | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Report: | 
					
						
							|  |  |  |     def __init__(self, testname): | 
					
						
							|  |  |  |         self.failed_tests = "" | 
					
						
							|  |  |  |         self.passed_tests = "" | 
					
						
							|  |  |  |         self.testname = testname | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def output(self): | 
					
						
							|  |  |  |         # write intermediate data for single test | 
					
						
							|  |  |  |         outdir = os.path.join(OUTDIR, self.testname) | 
					
						
							| 
									
										
										
										
											2017-08-25 17:17:49 -06:00
										 |  |  |         if not os.path.exists(outdir): | 
					
						
							|  |  |  |             os.makedirs(outdir) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |         f = open(os.path.join(outdir, "failed.data"), "w") | 
					
						
							|  |  |  |         f.write(self.failed_tests) | 
					
						
							|  |  |  |         f.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         f = open(os.path.join(outdir, "passed.data"), "w") | 
					
						
							|  |  |  |         f.write(self.passed_tests) | 
					
						
							|  |  |  |         f.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # gather intermediate data for all tests | 
					
						
							|  |  |  |         failed_data = sorted(glob.glob(os.path.join(OUTDIR, "*/failed.data"))) | 
					
						
							|  |  |  |         passed_data = sorted(glob.glob(os.path.join(OUTDIR, "*/passed.data"))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         failed_tests = "" | 
					
						
							|  |  |  |         passed_tests = "" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for filename in failed_data: | 
					
						
							|  |  |  |             failed_tests += open(os.path.join(OUTDIR, filename), "r").read() | 
					
						
							|  |  |  |         for filename in passed_data: | 
					
						
							|  |  |  |             passed_tests += open(os.path.join(OUTDIR, filename), "r").read() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # write html for all tests | 
					
						
							|  |  |  |         self.html = """
 | 
					
						
							|  |  |  | <html> | 
					
						
							|  |  |  | <head> | 
					
						
							|  |  |  |     <title>Cycles Test Report</title> | 
					
						
							|  |  |  |     <style> | 
					
						
							| 
									
										
										
										
											2017-08-18 00:37:45 +02:00
										 |  |  |         img {{ image-rendering: pixelated; width: 256px; background-color: #000; }} | 
					
						
							| 
									
										
										
										
											2017-08-11 09:34:34 +02:00
										 |  |  |         img.render {{ | 
					
						
							|  |  |  |             background-color: #fff; | 
					
						
							|  |  |  |             background-image: | 
					
						
							|  |  |  |               -moz-linear-gradient(45deg, #eee 25%, transparent 25%), | 
					
						
							|  |  |  |               -moz-linear-gradient(-45deg, #eee 25%, transparent 25%), | 
					
						
							|  |  |  |               -moz-linear-gradient(45deg, transparent 75%, #eee 75%), | 
					
						
							|  |  |  |               -moz-linear-gradient(-45deg, transparent 75%, #eee 75%); | 
					
						
							|  |  |  |             background-image: | 
					
						
							|  |  |  |               -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, #eee), color-stop(.25, transparent)), | 
					
						
							|  |  |  |               -webkit-gradient(linear, 0 0, 100% 100%, color-stop(.25, #eee), color-stop(.25, transparent)), | 
					
						
							|  |  |  |               -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.75, transparent), color-stop(.75, #eee)), | 
					
						
							|  |  |  |               -webkit-gradient(linear, 0 0, 100% 100%, color-stop(.75, transparent), color-stop(.75, #eee)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             -moz-background-size:50px 50px; | 
					
						
							|  |  |  |             background-size:50px 50px; | 
					
						
							|  |  |  |             -webkit-background-size:50px 51px; /* override value for shitty webkit */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             background-position:0 0, 25px 0, 25px -25px, 0px 25px; | 
					
						
							|  |  |  |         }} | 
					
						
							| 
									
										
										
										
											2017-08-18 00:37:45 +02:00
										 |  |  |         table td:first-child {{ width: 256px; }} | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     </style> | 
					
						
							|  |  |  |     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css"> | 
					
						
							|  |  |  | </head> | 
					
						
							|  |  |  | <body> | 
					
						
							|  |  |  |     <div class="container"> | 
					
						
							|  |  |  |         <br/> | 
					
						
							|  |  |  |         <h1>Cycles Test Report</h1> | 
					
						
							|  |  |  |         <br/> | 
					
						
							|  |  |  |         <table class="table table-striped"> | 
					
						
							|  |  |  |             <thead class="thead-default"> | 
					
						
							|  |  |  |                 <tr><th>Name</th><th>New</th><th>Reference</th><th>Diff</th> | 
					
						
							|  |  |  |             </thead> | 
					
						
							|  |  |  |             {}{} | 
					
						
							|  |  |  |         </table> | 
					
						
							|  |  |  |         <br/> | 
					
						
							|  |  |  |     </div> | 
					
						
							|  |  |  | </body> | 
					
						
							|  |  |  | </html> | 
					
						
							|  |  |  |             """ . format(failed_tests, passed_tests)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         filepath = os.path.join(OUTDIR, "report.html") | 
					
						
							|  |  |  |         f = open(filepath, "w") | 
					
						
							|  |  |  |         f.write(self.html) | 
					
						
							|  |  |  |         f.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         print_message("Report saved to: " + pathlib.Path(filepath).as_uri()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 00:37:45 +02:00
										 |  |  |     def relative_url(self, filepath): | 
					
						
							|  |  |  |         relpath = os.path.relpath(filepath, OUTDIR) | 
					
						
							|  |  |  |         return pathlib.Path(relpath).as_posix() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     def add_test(self, filepath, error): | 
					
						
							|  |  |  |         name = test_get_name(filepath) | 
					
						
							| 
									
										
										
										
											2017-08-18 00:37:45 +02:00
										 |  |  |         name = name.replace('_', ' ') | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ref_img, new_img, diff_img = test_get_images(filepath) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         status = error if error else "" | 
					
						
							|  |  |  |         style = """ style="background-color: #f99;" """ if error else "" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 00:37:45 +02:00
										 |  |  |         new_url = self.relative_url(new_img) | 
					
						
							|  |  |  |         ref_url = self.relative_url(ref_img) | 
					
						
							|  |  |  |         diff_url = self.relative_url(diff_img) | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         test_html = """
 | 
					
						
							|  |  |  |             <tr{}> | 
					
						
							|  |  |  |                 <td><b>{}</b><br/>{}<br/>{}</td> | 
					
						
							| 
									
										
										
										
											2017-08-11 09:34:34 +02:00
										 |  |  |                 <td><img src="{}" onmouseover="this.src='{}';" onmouseout="this.src='{}';" class="render"></td> | 
					
						
							|  |  |  |                 <td><img src="{}" onmouseover="this.src='{}';" onmouseout="this.src='{}';" class="render"></td> | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |                 <td><img src="{}"></td> | 
					
						
							|  |  |  |             </tr>""" . format(style, name, self.testname, status,
 | 
					
						
							|  |  |  |                               new_url, ref_url, new_url, | 
					
						
							|  |  |  |                               ref_url, new_url, ref_url, | 
					
						
							|  |  |  |                               diff_url) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if error: | 
					
						
							|  |  |  |             self.failed_tests += test_html | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.passed_tests += test_html | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def verify_output(report, filepath): | 
					
						
							|  |  |  |     ref_img, new_img, diff_img = test_get_images(filepath) | 
					
						
							| 
									
										
										
										
											2017-08-11 00:38:39 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # copy new image | 
					
						
							|  |  |  |     if os.path.exists(new_img): | 
					
						
							|  |  |  |         os.remove(new_img) | 
					
						
							|  |  |  |     if os.path.exists(TEMP_FILE): | 
					
						
							|  |  |  |         shutil.copy(TEMP_FILE, new_img) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     if not os.path.exists(ref_img): | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # diff test with threshold | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     command = ( | 
					
						
							|  |  |  |         IDIFF, | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |         "-fail", "0.016", | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |         "-failpercent", "1", | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |         ref_img, | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |         TEMP_FILE, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         subprocess.check_output(command) | 
					
						
							| 
									
										
										
										
											2016-07-29 02:04:45 +02:00
										 |  |  |         failed = False | 
					
						
							| 
									
										
										
										
											2015-01-30 15:13:09 +05:00
										 |  |  |     except subprocess.CalledProcessError as e: | 
					
						
							|  |  |  |         if VERBOSE: | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |             print_message(e.output.decode("utf-8")) | 
					
						
							| 
									
										
										
										
											2016-07-29 02:04:45 +02:00
										 |  |  |         failed = e.returncode != 1 | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # generate diff image | 
					
						
							|  |  |  |     command = ( | 
					
						
							|  |  |  |         IDIFF, | 
					
						
							|  |  |  |         "-o", diff_img, | 
					
						
							|  |  |  |         "-abs", "-scale", "16", | 
					
						
							|  |  |  |         ref_img, | 
					
						
							|  |  |  |         TEMP_FILE | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         subprocess.check_output(command) | 
					
						
							|  |  |  |     except subprocess.CalledProcessError as e: | 
					
						
							|  |  |  |         if VERBOSE: | 
					
						
							|  |  |  |             print_message(e.output.decode("utf-8")) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-29 02:04:45 +02:00
										 |  |  |     return not failed | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  | def run_test(report, filepath): | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     testname = test_get_name(filepath) | 
					
						
							|  |  |  |     spacer = "." * (32 - len(testname)) | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     print_message(testname, 'SUCCESS', 'RUN') | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |     time_start = time.time() | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     error = render_file(filepath) | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |     status = "FAIL" | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     if not error: | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |         if not verify_output(report, filepath): | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |             error = "VERIFY" | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |     time_end = time.time() | 
					
						
							|  |  |  |     elapsed_ms = int((time_end - time_start) * 1000) | 
					
						
							|  |  |  |     if not error: | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |         print_message("{} ({} ms)" . format(testname, elapsed_ms), | 
					
						
							|  |  |  |                       'SUCCESS', 'OK') | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |     else: | 
					
						
							|  |  |  |         if error == "NO_CYCLES": | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |             print_message("Can't perform tests because Cycles failed to load!") | 
					
						
							|  |  |  |             return error | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |         elif error == "NO_START": | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |             print_message('Can not perform tests because blender fails to start.', | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |                   'Make sure INSTALL target was run.') | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |             return error | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |         elif error == 'VERIFY': | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |             print_message("Rendered result is different from reference image") | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |             print_message("Unknown error %r" % error) | 
					
						
							|  |  |  |         print_message("{} ({} ms)" . format(testname, elapsed_ms), | 
					
						
							|  |  |  |                       'FAILURE', 'FAILED') | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     return error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  | def blend_list(path): | 
					
						
							|  |  |  |     for dirpath, dirnames, filenames in os.walk(path): | 
					
						
							|  |  |  |         for filename in filenames: | 
					
						
							|  |  |  |             if filename.lower().endswith(".blend"): | 
					
						
							|  |  |  |                 filepath = os.path.join(dirpath, filename) | 
					
						
							|  |  |  |                 yield filepath | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def run_all_tests(dirpath): | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |     passed_tests = [] | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     failed_tests = [] | 
					
						
							|  |  |  |     all_files = list(blend_list(dirpath)) | 
					
						
							|  |  |  |     all_files.sort() | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     report = Report(os.path.basename(dirpath)) | 
					
						
							|  |  |  |     print_message("Running {} tests from 1 test case." . | 
					
						
							|  |  |  |                   format(len(all_files)), | 
					
						
							|  |  |  |                   'SUCCESS', "==========") | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |     time_start = time.time() | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     for filepath in all_files: | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |         error = run_test(report, filepath) | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |         testname = test_get_name(filepath) | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |         if error: | 
					
						
							|  |  |  |             if error == "NO_CYCLES": | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  |             elif error == "NO_START": | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  |             failed_tests.append(testname) | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |         else: | 
					
						
							|  |  |  |             passed_tests.append(testname) | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |         report.add_test(filepath, error) | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |     time_end = time.time() | 
					
						
							|  |  |  |     elapsed_ms = int((time_end - time_start) * 1000) | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     print_message("") | 
					
						
							|  |  |  |     print_message("{} tests from 1 test case ran. ({} ms total)" . | 
					
						
							|  |  |  |                   format(len(all_files), elapsed_ms), | 
					
						
							|  |  |  |                   'SUCCESS', "==========") | 
					
						
							|  |  |  |     print_message("{} tests." . | 
					
						
							|  |  |  |                   format(len(passed_tests)), | 
					
						
							|  |  |  |                   'SUCCESS', 'PASSED') | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     if failed_tests: | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |         print_message("{} tests, listed below:" . | 
					
						
							|  |  |  |                      format(len(failed_tests)), | 
					
						
							|  |  |  |                      'FAILURE', 'FAILED') | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |         failed_tests.sort() | 
					
						
							|  |  |  |         for test in failed_tests: | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |             print_message("{}" . format(test), 'FAILURE', "FAILED") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     report.output() | 
					
						
							|  |  |  |     return not bool(failed_tests) | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def create_argparse(): | 
					
						
							|  |  |  |     parser = argparse.ArgumentParser() | 
					
						
							|  |  |  |     parser.add_argument("-blender", nargs="+") | 
					
						
							|  |  |  |     parser.add_argument("-testdir", nargs=1) | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     parser.add_argument("-outdir", nargs=1) | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     parser.add_argument("-idiff", nargs=1) | 
					
						
							|  |  |  |     return parser | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def main(): | 
					
						
							|  |  |  |     parser = create_argparse() | 
					
						
							|  |  |  |     args = parser.parse_args() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |     global COLORS | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     global BLENDER, TESTDIR, IDIFF, OUTDIR | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     global TEMP_FILE, TEMP_FILE_MASK, TEST_SCRIPT | 
					
						
							|  |  |  |     global VERBOSE | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-12 09:45:04 +01:00
										 |  |  |     if os.environ.get("CYCLESTEST_COLOR") is not None: | 
					
						
							|  |  |  |         COLORS = COLORS_ANSI | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     BLENDER = args.blender[0] | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     TESTDIR = args.testdir[0] | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  |     IDIFF = args.idiff[0] | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     OUTDIR = args.outdir[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not os.path.exists(OUTDIR): | 
					
						
							|  |  |  |         os.makedirs(OUTDIR) | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     TEMP = tempfile.mkdtemp() | 
					
						
							|  |  |  |     TEMP_FILE_MASK = os.path.join(TEMP, "test") | 
					
						
							|  |  |  |     TEMP_FILE = TEMP_FILE_MASK + "0001.png" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TEST_SCRIPT = os.path.join(os.path.dirname(__file__), "runtime_check.py") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VERBOSE = os.environ.get("BLENDER_VERBOSE") is not None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-03 16:41:50 +02:00
										 |  |  |     ok = run_all_tests(TESTDIR) | 
					
						
							| 
									
										
										
										
											2015-01-22 15:53:49 +05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Cleanup temp files and folders | 
					
						
							|  |  |  |     if os.path.exists(TEMP_FILE): | 
					
						
							|  |  |  |         os.remove(TEMP_FILE) | 
					
						
							|  |  |  |     os.rmdir(TEMP) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.exit(not ok) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     main() |