Skip to content
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

feat: Add 'simulatorLogLevel' capability #2479

Merged
merged 2 commits into from
Oct 17, 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
1 change: 1 addition & 0 deletions docs/reference/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ about capabilities, refer to the [Appium documentation](https://appium.io/docs/e
|`appium:autoFillPasswords`| It allows you to turn on/off autofill passwords function when text field is foccused. Works only with iOS16.4+ simulators | `true` |
|`appium:permissions`| Allows to set permissions for the specified application bundle on Simulator only. The capability value is expected to be a valid JSON string with `{"<bundleId1>": {"<serviceName1>": "<serviceStatus1>", ...}, ...}` format. Since Xcode SDK 11.4 Apple provides native APIs to interact with application settings. Check the output of `xcrun simctl privacy booted` command to get the list of available permission names. Use `yes`, `no` and `unset` as values in order to `grant`, `revoke` or `reset` the corresponding permission. Below Xcode SDK 11.4 it is required that `applesimutils` package is installed and available in PATH. The list of available service names and statuses can be found at https://github.com/wix/AppleSimulatorUtils. | `{"com.apple.mobilecal": {"calendar": "YES"}}` |
|`appium:iosSimulatorLogsPredicate`|Set the `--predicate` flag in the ios simulator logs|`'process != "locationd" AND process != "DTServiceHub"' AND process != "mobileassetd"`|
|`appium:simulatorLogLevel`|Allows to customize the minimum log level for logs collected from simulators. Possible values are `default` (the default value), `info` and `debug`| `debug` |
|`appium:simulatorPasteboardAutomaticSync`| Handle the `-PasteboardAutomaticSync` flag when simulator process launches. It could improve launching simulator performance not to sync pasteboard with the system when this value is `off`. `on` forces the flag enabled. `system` does not provide the flag to the launching command. `on`, `off`, or `system` is available. They are case insensitive. Defaults to `off` | `system` |
|`appium:simulatorDevicesSetPath`| This capability allows to set an alternative path to the simulator devices set in case you have multiple sets deployed on your local system. Such feature could be useful if you, for example, would like to save disk space on the main system volume. | `/MyVolume/Devices` |
|`appium:safariGlobalPreferences`| Allows changing of Mobile Safari's preferences at the session startup. Check the documentation on arguments of [mobile: updateSafariPreferences](./execute-methods.md#mobile-updatesafaripreferences) extension to get more details on the value type requirements. Only available on real devices since driver version 7.9.0. A new Safari instance must be launched upon test startup for this capability to take effect on real devices. | `{ ShowTabBar: 0, WarnAboutFraudulentWebsites: 0 }` |
Expand Down
1 change: 1 addition & 0 deletions lib/commands/log.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ export default {
sim: /** @type {import('appium-ios-simulator').Simulator} */ (this.device),
showLogs: this.opts.showIOSLog,
iosSimulatorLogsPredicate: this.opts.iosSimulatorLogsPredicate,
simulatorLogLevel: this.opts.simulatorLogLevel,
log: this.log,
}),
{
Expand Down
3 changes: 3 additions & 0 deletions lib/desired-caps.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,9 @@ const desiredCapConstraints = /** @type {const} */ ({
iosSimulatorLogsPredicate: {
isString: true,
},
simulatorLogLevel: {
isString: true,
},
appPushTimeout: {
isNumber: true,
},
Expand Down
33 changes: 28 additions & 5 deletions lib/device-log/ios-simulator-log.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
import _ from 'lodash';
import {SubProcess, exec} from 'teen_process';
import {util} from 'appium/support';
import { LineConsumingLog } from './line-consuming-log';
import type { Simulator } from 'appium-ios-simulator';
import type { AppiumLogger } from '@appium/types';

const EXECVP_ERROR_PATTERN = /execvp\(\)/;
const LOG_STREAMING_PROCESS_NAME_PATTERN = /^com\.apple\.xpc\.launchd\.oneshot\.0x[0-f]+\.log$/;

const START_TIMEOUT = 10000;

export interface IOSSimulatorLogOptions {
sim: Simulator;
showLogs?: boolean;
iosSimulatorLogsPredicate?: string;
simulatorLogLevel?: string;
log: AppiumLogger;
}

export class IOSSimulatorLog extends LineConsumingLog {
private readonly sim: Simulator;
private readonly showLogs: boolean;
private readonly predicate?: string;
private readonly logLevel?: string;
private proc: SubProcess | null;

constructor(opts: IOSSimulatorLogOptions) {
super({log: opts.log});
this.sim = opts.sim;
this.showLogs = !!opts.showLogs;
this.predicate = opts.iosSimulatorLogsPredicate;
this.logLevel = opts.simulatorLogLevel;
this.proc = null;
}

Expand All @@ -41,13 +46,14 @@ export class IOSSimulatorLog extends LineConsumingLog {
if (this.predicate) {
spawnArgs.push('--predicate', this.predicate);
}
if (this.logLevel) {
spawnArgs.push('--level', this.logLevel);
}
this.log.debug(
`Starting log capture for iOS Simulator with udid '${this.sim.udid}' ` + `using simctl`,
`Starting log capture for iOS Simulator with udid '${this.sim.udid}' ` +
`via simctl using the following arguments '${util.quote(spawnArgs)}'`
);
try {
// cleanup existing listeners if the previous session has not been terminated properly
await exec('pkill', ['-f', [this.sim.udid, ...spawnArgs].join(' ')]);
} catch (ign) {}
await this.cleanupObsoleteLogStreams();
try {
this.proc = await this.sim.simctl.spawnSubProcess(spawnArgs);
await this.finishStartingLogCapture();
Expand Down Expand Up @@ -112,6 +118,23 @@ export class IOSSimulatorLog extends LineConsumingLog {
};
await this.proc.start(startDetector, START_TIMEOUT);
}

private async cleanupObsoleteLogStreams(): Promise<void> {
const processes = await this.sim.ps();
const pids = processes
.filter(({name}) => LOG_STREAMING_PROCESS_NAME_PATTERN.test(name))
.map(({pid}) => pid);
if (_.isEmpty(pids)) {
return;
}
try {
await exec('kill', pids.map(String));
} catch (e) {
this.log.warn(
`Cound not terminate one or more obsolete log streams: ${e.stderr || e.message}`
);
}
}
}

export default IOSSimulatorLog;
Loading