Skip to content

[3.13] gh-127845: Minor improvements to iOS test runner script (GH-127846) #127892

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -2084,7 +2084,7 @@ testios:
$(PYTHON_FOR_BUILD) $(srcdir)/iOS/testbed clone --framework $(PYTHONFRAMEWORKPREFIX) "$(XCFOLDER)"

# Run the testbed project
$(PYTHON_FOR_BUILD) "$(XCFOLDER)" run -- test -uall --single-process --rerun -W
$(PYTHON_FOR_BUILD) "$(XCFOLDER)" run --verbose -- test -uall --single-process --rerun -W

# Like test, but using --slow-ci which enables all test resources and use
# longer timeout. Run an optional pybuildbot.identify script to include
Expand Down
66 changes: 48 additions & 18 deletions iOS/testbed/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,12 @@ async def log_stream_task(initial_devices):
else:
suppress_dupes = False
sys.stdout.write(line)
sys.stdout.flush()


async def xcode_test(location, simulator):
async def xcode_test(location, simulator, verbose):
# Run the test suite on the named simulator
print("Starting xcodebuild...")
args = [
"xcodebuild",
"test",
Expand All @@ -159,13 +161,17 @@ async def xcode_test(location, simulator):
"-derivedDataPath",
str(location / "DerivedData"),
]
if not verbose:
args += ["-quiet"]

async with async_process(
*args,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
) as process:
while line := (await process.stdout.readline()).decode(*DECODE_ARGS):
sys.stdout.write(line)
sys.stdout.flush()

status = await asyncio.wait_for(process.wait(), timeout=1)
exit(status)
Expand All @@ -182,7 +188,9 @@ def clone_testbed(
sys.exit(10)

if framework is None:
if not (source / "Python.xcframework/ios-arm64_x86_64-simulator/bin").is_dir():
if not (
source / "Python.xcframework/ios-arm64_x86_64-simulator/bin"
).is_dir():
print(
f"The testbed being cloned ({source}) does not contain "
f"a simulator framework. Re-run with --framework"
Expand All @@ -202,33 +210,48 @@ def clone_testbed(
)
sys.exit(13)

print("Cloning testbed project...")
shutil.copytree(source, target)
print("Cloning testbed project:")
print(f" Cloning {source}...", end="", flush=True)
shutil.copytree(source, target, symlinks=True)
print(" done")

if framework is not None:
if framework.suffix == ".xcframework":
print("Installing XCFramework...")
xc_framework_path = target / "Python.xcframework"
shutil.rmtree(xc_framework_path)
shutil.copytree(framework, xc_framework_path)
print(" Installing XCFramework...", end="", flush=True)
xc_framework_path = (target / "Python.xcframework").resolve()
if xc_framework_path.is_dir():
shutil.rmtree(xc_framework_path)
else:
xc_framework_path.unlink()
xc_framework_path.symlink_to(
framework.relative_to(xc_framework_path.parent, walk_up=True)
)
print(" done")
else:
print("Installing simulator Framework...")
print(" Installing simulator framework...", end="", flush=True)
sim_framework_path = (
target / "Python.xcframework" / "ios-arm64_x86_64-simulator"
).resolve()
if sim_framework_path.is_dir():
shutil.rmtree(sim_framework_path)
else:
sim_framework_path.unlink()
sim_framework_path.symlink_to(
framework.relative_to(sim_framework_path.parent, walk_up=True)
)
shutil.rmtree(sim_framework_path)
shutil.copytree(framework, sim_framework_path)
print(" done")
else:
print("Using pre-existing iOS framework.")
print(" Using pre-existing iOS framework.")

for app_src in apps:
print(f"Installing app {app_src.name!r}...")
print(f" Installing app {app_src.name!r}...", end="", flush=True)
app_target = target / f"iOSTestbed/app/{app_src.name}"
if app_target.is_dir():
shutil.rmtree(app_target)
shutil.copytree(app_src, app_target)
print(" done")

print(f"Testbed project created in {target}")
print(f"Successfully cloned testbed: {target.resolve()}")


def update_plist(testbed_path, args):
Expand All @@ -243,10 +266,11 @@ def update_plist(testbed_path, args):
plistlib.dump(info, f)


async def run_testbed(simulator: str, args: list[str]):
async def run_testbed(simulator: str, args: list[str], verbose: bool=False):
location = Path(__file__).parent
print("Updating plist...")
print("Updating plist...", end="", flush=True)
update_plist(location, args)
print(" done.")

# Get the list of devices that are booted at the start of the test run.
# The simulator started by the test suite will be detected as the new
Expand All @@ -256,7 +280,7 @@ async def run_testbed(simulator: str, args: list[str]):
try:
async with asyncio.TaskGroup() as tg:
tg.create_task(log_stream_task(initial_devices))
tg.create_task(xcode_test(location, simulator))
tg.create_task(xcode_test(location, simulator=simulator, verbose=verbose))
except* MySystemExit as e:
raise SystemExit(*e.exceptions[0].args) from None
except* subprocess.CalledProcessError as e:
Expand Down Expand Up @@ -315,6 +339,11 @@ def main():
default="iPhone SE (3rd Generation)",
help="The name of the simulator to use (default: 'iPhone SE (3rd Generation)')",
)
run.add_argument(
"-v", "--verbose",
action="store_true",
help="Enable verbose output",
)

try:
pos = sys.argv.index("--")
Expand All @@ -330,7 +359,7 @@ def main():
clone_testbed(
source=Path(__file__).parent,
target=Path(context.location),
framework=Path(context.framework) if context.framework else None,
framework=Path(context.framework).resolve() if context.framework else None,
apps=[Path(app) for app in context.apps],
)
elif context.subcommand == "run":
Expand All @@ -348,6 +377,7 @@ def main():
asyncio.run(
run_testbed(
simulator=context.simulator,
verbose=context.verbose,
args=test_args,
)
)
Expand Down
5 changes: 4 additions & 1 deletion iOS/testbed/iOSTestbedTests/iOSTestbedTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ - (void)testPython {

NSString *resourcePath = [[NSBundle mainBundle] resourcePath];

// Disable all color, as the Xcode log can't display color
// Set some other common environment indicators to disable color, as the
// Xcode log can't display color. Stdout will report that it is *not* a
// TTY.
setenv("NO_COLOR", "1", true);
setenv("PY_COLORS", "0", true);

// Arguments to pass into the test suite runner.
// argv[0] must identify the process; any subsequent arg
Expand Down
Loading