Skip to content

Conversation

@imurchie
Copy link
Contributor

We currently use the technique of looking at the ios logs (sim or device) and waiting for the marker that WDA writes on startup. This means we need to open and manage the logs, make sure we are looking at the right entries, etc. It is all fraught, as the issue tracker can attest.

This PR strips out all log handling, and instead pings the WDA server until it gets a valid status back, or times out. This is possible since (A) on simulators the WDA server is always on localhost, and (B) on real devices we use iproxy, which maps the request over USB, so we also end up talking to localhost. In neither case do we need to actual server url, which is the only information that is available in the logs but not the status.

Tests are faster, and locally work without issue.

Two new caps are introduced:

  • useNewWDA - forces uninstall of WDA before launch. This clears up some problems with hanging processes and "too many instances running" errors.
  • wdaLaunchTimeout - ms to wait trying to connect.

@mykola-mokhnach Can you try this out for your setup?

}
await exec('/bin/bash', ['Scripts/bootstrap.sh', '-d'], {cwd: this.bootstrapPath});
} catch (err) {
log.warn('Carthage not found. Install using `brew install carthage`');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

if (!agentUrl) {
log.errorAndThrow(new Error('No url detected from WebDriverAgent'));
try {
let {stdout} = await exec('curl', curlArgs);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Executing terminal commands is usually slower than using built-in instruments. How about sending HEAD http request with timeout to the WDA URL and checking the response code?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, why don't we use request-promise instead of curl?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't get it to work when I was originally trying. It would always return a blank response, while I could use the terminal to curl to it no problem.

I'll give it another shot.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about something similar to this example:
http://stackoverflow.com/questions/5922842/getting-http-headers-with-node-js

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reasons unknown, request-promise is working now. I must have done something wrong that I couldn't see before.

}
return (async () => {
try {
await this.iproxy.start(5000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably, we can move the timeout value to a separate constant?

resolve();
} catch (err) {
log.error(`Error starting iproxy: '${err.message}'`);
reject('Unable to start iproxy. Is it installed?');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we show the expected iproxy path in the error message

this.url = url.parse(agentUrl);

this.url.hostname = 'localhost';
this.url = url.parse(`http://localhost:8100`);
Copy link
Contributor

@mykola-mokhnach mykola-mokhnach Dec 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can the URL be moved to a constant?

Copy link
Member

@jlipps jlipps left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to all of @mykola-mokhnach's comments, and added my own. Great approach.

if (!agentUrl) {
log.errorAndThrow(new Error('No url detected from WebDriverAgent'));
try {
let {stdout} = await exec('curl', curlArgs);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, why don't we use request-promise instead of curl?

resolve();
} catch (err) {
log.error(`Error starting iproxy: '${err.message}'`);
reject('Unable to start iproxy. Is it installed?');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably a good practice to reject with an Error instead of a string?

} catch (err) {
let msg = `Unable to start WebDriverAgent: ${err}`;
log.error(msg);
reject(msg);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably a good idea to reject with an error instead of a string?

if (!await fs.hasAccess(`${this.bootstrapPath}/Carthage`)) {
log.debug('Running WebDriverAgent bootstrap script to install dependencies');
} else {
log.debug('Running WebDriverAgent bootstrap script to update dependencies');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need to execute carthage again?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This, I think, should fix the errors with certain dependencies not being there. I'm happy to not do this, and make people manually do it when problems arise.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imurchie is this only a problem when people are running appium from source and receive wda updates?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jlipps No. I think it is mostly a problem of people upgrading on top of an older version. As in, just doing an npm install without npm uninstall.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then it would be better to just ask them to do this action manually in an error message. Otherwise executing carthage for each WDA build may greatly slow down automated tests.

@imurchie
Copy link
Contributor Author

All comments addressed in code.

|`preventWDAAttachments`|Sets read only permissons to Attachments subfolder of WebDriverAgent root inside Xcode's DerivedData. This is necessary to prevent XCTest framework from creating tons of unnecessary screenshots and logs, which are impossible to shutdown using programming interfaces provided by Apple.|Setting the capability to `true` will set Posix permissions of the folder to `555` and `false` will reset them back to `755`|
|`webDriverAgentUrl`|If provided, Appium will connect to an existing WebDriverAgent instance at this URL instead of starting a new one.|e.g., `http://localhost:8100`|

|`useNewWDA`|If `true`, forces uninstall of any existing WebDriverAgent app on device. This can provide stability in some situations. Defaults to `false`.|e.g., `true`|
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be useful to give at least one example of such situation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll work on documenting an example. I don't have the details of the problem right now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this require manual git pull of webdriveragent source into the wedriveragent under the xcuittestdriver node module ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. It just uninstalls the app from the device on session creation.

},
wdaLocalPort: {
isNumber: true
isNumber: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are no trailing commas for other parameters. Do we follow any rule on this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we have a rule, per se. And this one is not doing anything (since we won't be adding to the object).

lib/driver.js Outdated
try {
await this.wda.launch(sessionId, realDevice);
} catch (err) {
if (tries > 2) throw err;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this magic number might be moved to constants

const AGENT_STARTED_REGEX = /ServerURLHere->(.*)<-ServerURLHere/;
const REAL_DEVICE_LOGGER_PATH = 'idevicesyslog';
const WDA_BUNDLE_ID = 'com.apple.test.WebDriverAgentRunner-Runner';
const WDA_LAUNCH_TIMEOUT = 60 * 1000;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

await this.deviceLogs.start(startDetector);
log.info(`WebDriverAgent started at url '${agentUrl}'`);
});
let startupTime = Date.now() - startTime;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one recommends to use process.hrtime for such purpose instead of Date()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shortly said - process.hrtime has been initially designed to measure intervals with maximum possible precision. And Date is a general class to represent calendar dates in apps.

Copy link
Member

@jlipps jlipps left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one small remark then LGTM

let msg = `Unable to start WebDriverAgent: ${err}`;
log.error(msg);
reject(new Error(msg));
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure what this return is doing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a whole lot. There must have been something after the catch block at one point.

@jlipps
Copy link
Member

jlipps commented Dec 21, 2016

(I resolved conflicts using the GitHub UI. Pretty cool.)

package.json Outdated
"lodash": "^4.0.0",
"node-simctl": "^3.1.0",
"request": "^2.79.0",
"request-promise": "^2.0.1",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imurchie request-promise is at version 4.1.1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird. That was just the result of npm -S request-promise, so it should have gotten the latest.

@imurchie
Copy link
Contributor Author

@jlipps: So, the GitHub UI conflict resolver isn't so good. Alas.

@imurchie imurchie merged commit 95886f1 into master Dec 22, 2016
@imurchie imurchie deleted the isaac-real-device branch December 22, 2016 13:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants