From b7c2a04e54972eb129967bf3ed799ce470fd4724 Mon Sep 17 00:00:00 2001 From: Minghao Li Date: Sun, 26 Nov 2023 15:22:31 +0800 Subject: [PATCH 1/4] Create 2 separate log files for XCTest test process logs and test output --- tidevice/__main__.py | 16 ++++++++++++++++ tidevice/_device.py | 20 ++++++++++++++++++++ tidevice/_proto.py | 2 ++ 3 files changed, 38 insertions(+) diff --git a/tidevice/__main__.py b/tidevice/__main__.py index 0e725e0..63c8303 100644 --- a/tidevice/__main__.py +++ b/tidevice/__main__.py @@ -251,6 +251,20 @@ def cmd_xcuitest(args: argparse.Namespace): if args.debug: setup_logger(LOG.xcuitest, level=logging.DEBUG) + if args.log_dir: + level = logging.DEBUG if args.debug else logging.INFO + # Use the default formatter that is a no-op formatter. + setup_logger( + LOG.xcuitest_test_process_log, + logfile=os.path.join(args.log_dir, 'xctest_test_process.log'), + level=level, + formatter=logging.Formatter()) + setup_logger( + LOG.xcuitest_test_output, + logfile=os.path.join(args.log_dir, 'xctest_test_output.log'), + level=level, + formatter=logging.Formatter()) + d = _udid2device(args.udid) env = {} for kv in args.env or []: @@ -861,6 +875,8 @@ def cmd_test(args: argparse.Namespace): help="set command line args to target app with a comma-separated list of strings"), dict(args=['--tests-to-run'], help="specify a set of test classes or test methods to run, format: a comma-separated list of Test-Class-Name[/Test-Method-Name]"), + dict(args=['--log_dir'], + help='The directory to put XCUITest log files. If not specified, it will not generate log files.'), ], help="run XCTest (XCUITest)"), dict( diff --git a/tidevice/_device.py b/tidevice/_device.py index d3eae20..5fab030 100644 --- a/tidevice/_device.py +++ b/tidevice/_device.py @@ -46,6 +46,8 @@ from .session import Session logger = logging.getLogger(__name__) +xctest_test_process_logger = logging.getLogger(LOG.xcuitest_test_process_log) +xctest_test_output_logger = logging.getLogger(LOG.xcuitest_test_output) def pil_imread(data: Union[str, pathlib.Path, bytes, bytearray]) -> Image.Image: @@ -939,6 +941,10 @@ def _callback(m: DTXMessage): if method == 'outputReceived:fromProcess:atTime:': # logger.info("Output: %s", args[0].strip()) logger.debug("logProcess: %s", args[0].rstrip()) + # XCTestOutputBarrier is just ouput separators, no need to + # print them in the logs. + if args[0].rstrip() != 'XCTestOutputBarrier': + xctest_test_output_logger.debug('%s', args[0].rstrip()) # In low iOS versions, 'Using singleton test manager' may not be printed... mark wda launch status = True if server url has been printed if "ServerURLHere" in args[0]: logger.info("%s", args[0].rstrip()) @@ -947,6 +953,13 @@ def _callback(m: DTXMessage): def _log_message_callback(m: DTXMessage): identifier, args = m.result logger.debug("logConsole: %s", args) + if isinstance(args, (tuple, list)): + for msg in args: + msg = msg.rstrip() if isinstance(msg, str) else msg + xctest_test_process_logger.debug('%s', msg) + else: + xctest_test_process_logger.debug('%s', args) + conn.register_callback("_XCT_logDebugMessage:", _log_message_callback) conn.register_callback(Event.NOTIFICATION, _callback) @@ -1059,6 +1072,13 @@ def _show_log_message(m: DTXMessage): logger.info("Test runner ready detected") _start_executing() + if isinstance(m.result[1], (tuple, list)): + for msg in m.result[1]: + msg = msg.rstrip() if isinstance(msg, str) else msg + xctest_test_process_logger.debug('%s', msg) + else: + xctest_test_process_logger.debug('%s', m.result[1]) + test_results = [] test_results_lock = threading.Lock() diff --git a/tidevice/_proto.py b/tidevice/_proto.py index 685f9b2..6372789 100644 --- a/tidevice/_proto.py +++ b/tidevice/_proto.py @@ -17,6 +17,8 @@ class LOG(str, enum.Enum): root = "tidevice" xcuitest = "tidevice.xctest" + xcuitest_test_process_log = "tidevice.xctest.test_process_log" + xcuitest_test_output = "tidevice.xctest.test_output" socket = "tidevice.socket" From e044173532f66a1b4195cb4b754070f455410752 Mon Sep 17 00:00:00 2001 From: Minghao Li Date: Sun, 26 Nov 2023 15:42:29 +0800 Subject: [PATCH 2/4] fix format --- tidevice/__main__.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tidevice/__main__.py b/tidevice/__main__.py index 63c8303..e3a716e 100644 --- a/tidevice/__main__.py +++ b/tidevice/__main__.py @@ -252,18 +252,17 @@ def cmd_xcuitest(args: argparse.Namespace): setup_logger(LOG.xcuitest, level=logging.DEBUG) if args.log_dir: + logger.info('XCTest log directory: %s', args.log_dir) level = logging.DEBUG if args.debug else logging.INFO # Use the default formatter that is a no-op formatter. - setup_logger( - LOG.xcuitest_test_process_log, - logfile=os.path.join(args.log_dir, 'xctest_test_process.log'), - level=level, - formatter=logging.Formatter()) - setup_logger( - LOG.xcuitest_test_output, - logfile=os.path.join(args.log_dir, 'xctest_test_output.log'), - level=level, - formatter=logging.Formatter()) + setup_logger(LOG.xcuitest_test_process_log, + logfile=os.path.join(args.log_dir, 'xctest_test_process.log'), + level=level, + formatter=logging.Formatter()) + setup_logger(LOG.xcuitest_test_output, + logfile=os.path.join(args.log_dir, 'xctest_test_output.log'), + level=level, + formatter=logging.Formatter()) d = _udid2device(args.udid) env = {} From 59b056850721b311ba8f503eb245cbc0d9a12034 Mon Sep 17 00:00:00 2001 From: Minghao Li Date: Sun, 26 Nov 2023 21:11:51 +0800 Subject: [PATCH 3/4] expose command args so that users can set log file paths --- tidevice/__main__.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/tidevice/__main__.py b/tidevice/__main__.py index e3a716e..92dbbec 100644 --- a/tidevice/__main__.py +++ b/tidevice/__main__.py @@ -248,20 +248,23 @@ def cmd_xcuitest(args: argparse.Namespace): """ Run XCTest required WDA installed. """ - if args.debug: - setup_logger(LOG.xcuitest, level=logging.DEBUG) + log_level = logging.DEBUG if args.debug else logging.INFO + setup_logger(LOG.xcuitest, level=log_level) - if args.log_dir: - logger.info('XCTest log directory: %s', args.log_dir) - level = logging.DEBUG if args.debug else logging.INFO + if args.test_process_log_path: + logger.info('XCUITest test process log file path: %s', args.test_process_log_path) # Use the default formatter that is a no-op formatter. setup_logger(LOG.xcuitest_test_process_log, - logfile=os.path.join(args.log_dir, 'xctest_test_process.log'), - level=level, + logfile=args.test_process_log_path, + level=log_level, formatter=logging.Formatter()) + + if args.test_output_path: + logger.info('XCUITest test output file path: %s', args.test_output_path) + # Use the default formatter that is a no-op formatter. setup_logger(LOG.xcuitest_test_output, - logfile=os.path.join(args.log_dir, 'xctest_test_output.log'), - level=level, + logfile=args.test_output_path, + level=log_level, formatter=logging.Formatter()) d = _udid2device(args.udid) @@ -874,8 +877,10 @@ def cmd_test(args: argparse.Namespace): help="set command line args to target app with a comma-separated list of strings"), dict(args=['--tests-to-run'], help="specify a set of test classes or test methods to run, format: a comma-separated list of Test-Class-Name[/Test-Method-Name]"), - dict(args=['--log_dir'], - help='The directory to put XCUITest log files. If not specified, it will not generate log files.'), + dict(args=['--test_process_log_path'], + help='The file path to store XCUITest test process logs. By default they are not stored to a file.'), + dict(args=['--test_output_path'], + help='The file path to store XCUITest test output, e.g. UI activity summaries. By default they are not stored to a file.'), ], help="run XCTest (XCUITest)"), dict( From 307319236bfcf2a3672c128f9ed65833de9b3212 Mon Sep 17 00:00:00 2001 From: Minghao Li Date: Sun, 26 Nov 2023 21:29:52 +0800 Subject: [PATCH 4/4] disbale the newly added logger to print message to console. --- tidevice/__main__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tidevice/__main__.py b/tidevice/__main__.py index 92dbbec..66efc4f 100644 --- a/tidevice/__main__.py +++ b/tidevice/__main__.py @@ -256,6 +256,7 @@ def cmd_xcuitest(args: argparse.Namespace): # Use the default formatter that is a no-op formatter. setup_logger(LOG.xcuitest_test_process_log, logfile=args.test_process_log_path, + disableStderrLogger=True, # Disable console logging. level=log_level, formatter=logging.Formatter()) @@ -264,6 +265,7 @@ def cmd_xcuitest(args: argparse.Namespace): # Use the default formatter that is a no-op formatter. setup_logger(LOG.xcuitest_test_output, logfile=args.test_output_path, + disableStderrLogger=True, # Disable console logging. level=log_level, formatter=logging.Formatter())