9494import glob
9595import os
9696import platform
97+ import stat
9798import shutil
9899import subprocess
99100import time
145146 _IOS : "iOS" ,
146147 _WINDOWS : "Win64" ,
147148 _MACOS : "OSXUniversal" ,
148- _LINUX : "Linux64"
149+ _LINUX : "Linux64" ,
150+ _PLAYMODE : "Playmode"
149151}
150152
151153_SUPPORTED_PLATFORMS = (
264266 " c can be a combination of digits and letters." )
265267
266268
269+ @attr .s (frozen = False , eq = False )
270+ class Test (object ):
271+ """Holds data related to the testing of one testapp."""
272+ testapp_path = attr .ib ()
273+ logs = attr .ib ()
274+
275+
267276def main (argv ):
268277 del argv # Unused.
269278
@@ -286,6 +295,7 @@ def main(argv):
286295 platforms = validate_platforms (FLAGS .platforms )
287296
288297 output_root = os .path .join (root_output_dir , "testapps" )
298+ playmode_tests = []
289299 failures = []
290300 for version in unity_versions :
291301 runtime = get_runtime (version , FLAGS .force_latest_runtime )
@@ -329,14 +339,17 @@ def main(argv):
329339 if p == _DESKTOP : # e.g. 'Desktop' -> 'OSXUniversal'
330340 p = get_desktop_platform ()
331341 if p == _PLAYMODE :
332- perform_in_editor_tests (dir_helper )
342+ logs = perform_in_editor_tests (dir_helper )
343+ playmode_tests .append (Test (testapp_path = dir_helper .unity_project_dir , logs = logs ))
333344 else :
334345 build_testapp (
335346 dir_helper = dir_helper ,
336347 api_config = api_config ,
337348 ios_config = ios_config ,
338349 target = _BUILD_TARGET [p ])
339350 except (subprocess .SubprocessError , RuntimeError ) as e :
351+ if p == _PLAYMODE :
352+ playmode_tests .append (Test (testapp_path = dir_helper .unity_project_dir , logs = str (e )))
340353 failures .append (
341354 Failure (
342355 testapp = testapp ,
@@ -350,20 +363,32 @@ def main(argv):
350363 logging .info (f .read ())
351364 # Free up space by removing unneeded Unity directory.
352365 if FLAGS .ci :
353- shutil . rmtree (dir_helper .unity_project_dir )
366+ _rm_dir_safe (dir_helper .unity_project_dir )
354367 else :
355- shutil . rmtree (os .path .join (dir_helper .unity_project_dir , "Library" ))
368+ _rm_dir_safe (os .path .join (dir_helper .unity_project_dir , "Library" ))
356369 logging .info ("END %s" , build_desc )
357370
358- _collect_integration_tests (config , testapps , root_output_dir , output_dir , FLAGS .artifact_name )
359-
360- return _summarize_results (
361- testapps = testapps ,
362- platforms = platforms ,
363- versions = unity_versions ,
364- failures = failures ,
365- output_dir = root_output_dir ,
366- artifact_name = FLAGS .artifact_name )
371+ playmode_passes = True
372+ build_passes = True
373+ if _PLAYMODE in platforms :
374+ platforms .remove (_PLAYMODE )
375+ playmode_passes = test_validation .summarize_test_results (
376+ playmode_tests ,
377+ test_validation .UNITY ,
378+ root_output_dir ,
379+ file_name = "test-results-" + FLAGS .artifact_name + ".log" )
380+
381+ if platforms :
382+ _collect_integration_tests (config , testapps , root_output_dir , output_dir , FLAGS .artifact_name )
383+ build_passes = _summarize_build_results (
384+ testapps = testapps ,
385+ platforms = platforms ,
386+ versions = unity_versions ,
387+ failures = failures ,
388+ output_dir = root_output_dir ,
389+ artifact_name = FLAGS .artifact_name )
390+
391+ return (playmode_passes and build_passes )
367392
368393
369394def setup_unity_project (dir_helper , setup_options ):
@@ -531,7 +556,7 @@ def perform_in_editor_tests(dir_helper, retry_on_license_check=True):
531556 dir_helper .unity_path ,
532557 dir_helper .unity_project_dir ,
533558 shared_args = ["-batchmode" , "-nographics" , "-accept-apiupdate" ])
534- log = dir_helper .make_log_path ("editor_tests " )
559+ log = dir_helper .make_log_path ("build_Playmode " )
535560 arg_builder .set_log_file (log )
536561 run_args = arg_builder .get_args_for_method ("InEditorRunner.EditorRun" )
537562 dir_helper .copy_editor_script ("InEditorRunner.cs" )
@@ -554,7 +579,7 @@ def perform_in_editor_tests(dir_helper, retry_on_license_check=True):
554579 open_process .kill ()
555580 logging .info ("Finished running playmode tests" )
556581
557- results = test_validation .validate_results_unity (text )
582+ results = test_validation .validate_results (text , test_validation . UNITY )
558583 if results .complete :
559584 if results .passes and not results .fails : # Success
560585 logging .info (results .summary )
@@ -564,6 +589,8 @@ def perform_in_editor_tests(dir_helper, retry_on_license_check=True):
564589 raise RuntimeError (
565590 "Tests did not finish running. Log tail:\n " + results .summary )
566591
592+ return text
593+
567594
568595def run_xcodebuild (dir_helper , ios_config , device_type ):
569596 """Uses xcode project generated by Unity to build an iOS binary."""
@@ -619,7 +646,7 @@ def _collect_integration_tests(config, testapps, root_output_dir, output_dir, ar
619646 artifact_path = os .path .join (root_output_dir , testapps_artifact_dir )
620647 logging .info ("Collecting artifacts to: %s" , artifact_path )
621648 try :
622- shutil . rmtree (artifact_path )
649+ _rm_dir_safe (artifact_path )
623650 except OSError as e :
624651 logging .warning ("Failed to remove directory:\n %s" , e .strerror )
625652
@@ -647,7 +674,7 @@ def _collect_integration_tests_platform(config, testapps, artifact_path, testapp
647674 break
648675
649676
650- def _summarize_results (testapps , platforms , versions , failures , output_dir , artifact_name ):
677+ def _summarize_build_results (testapps , platforms , versions , failures , output_dir , artifact_name ):
651678 """Logs a readable summary of the results of the build."""
652679 file_name = "build-results-" + artifact_name + ".log"
653680 summary = []
@@ -956,6 +983,24 @@ def update_unity_versions(version_path_map, log=logging.error):
956983 return valid_versions
957984
958985
986+ def _handle_readonly_file (func , path , excinfo ):
987+ """Function passed into shutil.rmtree to handle Access Denied error"""
988+ os .chmod (path , stat .S_IWRITE )
989+ func (path ) # will re-throw if a different error occurrs
990+
991+
992+ def _rm_dir_safe (directory_path ):
993+ """Removes directory at given path. No error if dir doesn't exist."""
994+ logging .info ("Deleting %s..." , directory_path )
995+ try :
996+ shutil .rmtree (directory_path , onerror = _handle_readonly_file )
997+ except OSError as e :
998+ # There are two known cases where this can happen:
999+ # The directory doesn't exist (FileNotFoundError)
1000+ # A file in the directory is open in another process (PermissionError)
1001+ logging .warning ("Failed to remove directory:\n %s" , e .strerror )
1002+
1003+
9591004def _fix_path (path ):
9601005 """Expands ~, normalizes slashes, and converts relative paths to absolute."""
9611006 if not path :
0 commit comments