Skip to content

Commit

Permalink
feat: adb logcat is using --pid argument by default
Browse files Browse the repository at this point in the history
  • Loading branch information
noomorph committed May 21, 2018
1 parent e3edd5e commit 8eaae6b
Show file tree
Hide file tree
Showing 13 changed files with 183 additions and 69 deletions.
2 changes: 1 addition & 1 deletion detox/src/Detox.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class Detox {
this.artifactsManager = new ArtifactsManager({
artifactCapabilities: deviceDriver.getArtifactCapabilities({
deviceId: this.device.id,
bundleId: this.device.bundleId,
processId: this.device.processId,
}),
});

Expand Down
4 changes: 2 additions & 2 deletions detox/src/artifacts/log/android/ADBLogcatRecorder.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ class ADBLogcatRecorder extends Recorder {
super(config);

this.adb = config.adb;
this.bundleId = config.bundleId;
this.deviceId = config.deviceId;
this.processId = config.processId;
this._logsCounter = 0;
}

createRecording() {
return new ADBLogcatRecording({
adb: this.adb,
bundleId: this.bundleId,
processId: this.processId,
deviceId: this.deviceId,
pathToLogOnDevice: this._generatePathOnDevice(),
});
Expand Down
6 changes: 3 additions & 3 deletions detox/src/artifacts/log/android/ADBLogcatRecorder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ describe(ADBLogcatRecorder, () => {
it('should create recording', () => {
const artifactsRegistry = { registerArtifact: jest.fn() };
const adb = {};
const bundleId = 'bundle';
const processId = 1083;
const deviceId = 'device';

const recorder = new ADBLogcatRecorder({
artifactsRegistry,
adb,
bundleId,
deviceId,
processId,
});

const recording = recorder.record();
expect(artifactsRegistry.registerArtifact).toHaveBeenCalledWith(recording);
expect(recording.adb).toBe(adb);
expect(recording.bundleId).toBe(bundleId);
expect(recording.deviceId).toBe(deviceId);
expect(recording.processId).toBe(processId);
});
});

33 changes: 26 additions & 7 deletions detox/src/artifacts/log/android/ADBLogcatRecording.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ const fs = require('fs-extra');
const RecordingArtifact = require('../../core/artifact/RecordingArtifact');
const ensureExtension = require('../../../utils/ensureExtension');
const interruptProcess = require('../../../utils/interruptProcess');
const {spawn} = require('child-process-promise');
const sleep = require('../../../utils/sleep');

class ADBLogcatRecording extends RecordingArtifact {
constructor({
adb,
bundleId,
deviceId,
pathToLogOnDevice,
processId,
}) {
super();

this.adb = adb;
this.bundleId = bundleId;
this.deviceId = deviceId;
this.pathToLogOnDevice = pathToLogOnDevice;
this.processId = processId;
this.processPromise = null;
}

Expand All @@ -25,31 +25,50 @@ class ADBLogcatRecording extends RecordingArtifact {

this.processPromise = this.adb.logcat(this.deviceId, {
file: this.pathToLogOnDevice,
pid: this.processId,
time: now,
});

await this.adb.waitForFileRecording(this.deviceId, this.pathToLogOnDevice, false);
await this._waitUntilLogFileIsCreated();
}

async doStop() {
if (this.processPromise) {
await interruptProcess(this.processPromise, 'SIGTERM');
await interruptProcess(this.processPromise);
}
}

async doSave(artifactPath) {
const logArtifactPath = ensureExtension(artifactPath, '.log');

await fs.ensureFile(logArtifactPath);
await this.adb.waitForFileRelease(this.deviceId, this.pathToLogOnDevice);
await this._waitWhileLogIsOpenedByLogcat();
await this.adb.pull(this.deviceId, this.pathToLogOnDevice, logArtifactPath);
await this.adb.rm(this.deviceId, this.pathToLogOnDevice);
}

async doDiscard() {
await this.adb.waitForFileRelease(this.deviceId, this.pathToLogOnDevice);
await this._waitWhileLogIsOpenedByLogcat();
await this.adb.rm(this.deviceId, this.pathToLogOnDevice);
}

async _waitUntilLogFileIsCreated() {
let size;

do {
size = await this.adb.getFileSize(this.deviceId, this.pathToLogOnDevice);
await sleep(100);
} while (size === -1);
}

async _waitWhileLogIsOpenedByLogcat() {
let isFileOpen;

do {
isFileOpen = await this.adb.isFileOpen(this.deviceId, this.pathToLogOnDevice);
await sleep(500);
} while (isFileOpen);
}
}

module.exports = ADBLogcatRecording;
22 changes: 20 additions & 2 deletions detox/src/artifacts/video/android/ADBVideoRecording.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,30 @@ class ADBVideoRecording extends RecordingArtifact {

async _delayWhileVideoFileIsEmpty() {
await sleep(300); // wait while video is most likely empty
await this.adb.waitForFileRecording(this.deviceId, this.pathToVideoOnDevice);
await this._waitForFileRecording();
}

async _delayWhileVideoFileIsBusy() {
await this.waitWhileVideoIsMostLikelyBusy;
await this.adb.waitForFileRelease(this.deviceId, this.pathToVideoOnDevice);
await this._waitForFileRelease();
}

async _waitForFileRecording() {
let size;

do {
size = await this.adb.getFileSize(this.deviceId, this.pathToVideoOnDevice);
await sleep(100);
} while (size < 1);
}

async _waitForFileRelease() {
let isFileOpen;

do {
isFileOpen = await this.adb.isFileOpen(this.deviceId, this.pathToVideoOnDevice);
await sleep(500);
} while (isFileOpen);
}
}

Expand Down
27 changes: 23 additions & 4 deletions detox/src/devices/AndroidDriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const ADB = require('./android/ADB');
const AAPT = require('./android/AAPT');
const APKPath = require('./android/APKPath');
const DeviceDriverBase = require('./DeviceDriverBase');
const sleep = require('../utils/sleep');

const ADBLogcatRecorder = require('../artifacts/log/android/ADBLogcatRecorder');
const ADBScreenshotter = require('../artifacts/screenshot/android/ADBScreenshotter');
Expand All @@ -26,15 +27,15 @@ class AndroidDriver extends DeviceDriverBase {
this.aapt = new AAPT();
}

getArtifactCapabilities({ deviceId, bundleId }) {
getArtifactCapabilities({ deviceId, processId }) {
const adb = this.adb;

return {
log: (config) => new ADBLogcatRecorder({
...config,
adb,
deviceId,
bundleId,
processId,
}),
screenshot: (config) => new ADBScreenshotter({
...config,
Expand Down Expand Up @@ -95,7 +96,7 @@ class AndroidDriver extends DeviceDriverBase {
if (this.instrumentationProcess) {
const call = invoke.call(invoke.Android.Class("com.wix.detox.Detox"), 'launchMainActivity');
await this.invocationManager.execute(call);
return this.instrumentationProcess.pid;
return this._queryPID(deviceId, bundleId);
}

const testRunner = await this.adb.getInstrumentationRunner(deviceId, bundleId);
Expand All @@ -116,7 +117,25 @@ class AndroidDriver extends DeviceDriverBase {
this.terminateInstrumentation();
});

return this.instrumentationProcess.pid;
return this._queryPID(deviceId, bundleId);
}

async _queryPID(deviceId, bundleId, waitAtStart = true) {
if (waitAtStart) {
await sleep(500);
}

for (let attempts = 5; attempts > 0; attempts--) {
const PID = await this.adb.pidof(deviceId, bundleId);

This comment was marked as resolved.

Copy link
@rotemmiz

rotemmiz May 21, 2018

Member

pid, not PID


if (PID > 0) {
return PID;
}

await sleep(1000);
}

return NaN;
}

async deliverPayload(params) {
Expand Down
4 changes: 2 additions & 2 deletions detox/src/devices/Device.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ class Device {
return this._deviceId;
}

get bundleId() {
return this._bundleId;
get processId() {
return this._processes[this._bundleId];
}

async prepare(params = {}) {
Expand Down
7 changes: 4 additions & 3 deletions detox/src/devices/Device.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,12 @@ describe('Device', () => {
expect(device.id).toBe('mockDeviceId');
});

it('should provide device.bundleId', async () => {
it('should provide device.processId', async () => {
device = validDevice();
device.deviceDriver.getBundleIdFromBinary.mockReturnValue('test.bundle');
await device.prepare();
expect(device.bundleId).toBe('test.bundle');
device.deviceDriver.launch.mockReturnValue('fakeId');
await device.prepare({ launchApp: true });
expect(device.processId).toBe('fakeId');
});

it(`prepare() with when reuse is enabled should not uninstall and install`, async () => {
Expand Down
25 changes: 23 additions & 2 deletions detox/src/devices/EmulatorDriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ const _ = require('lodash');
const path = require('path');
const Emulator = require('./android/Emulator');
const EmulatorTelnet = require('./android/EmulatorTelnet');
const DetoxRuntimeError = require('../errors/DetoxRuntimeError');
const Environment = require('../utils/environment');
const sleep = require('../utils/sleep');
const AndroidDriver = require('./AndroidDriver');
const ini = require('ini');
const fs = require('fs');
Expand Down Expand Up @@ -35,7 +37,7 @@ class EmulatorDriver extends AndroidDriver {

async boot(deviceId) {
await this.emulator.boot(deviceId);
await this.adb.waitForBootComplete(deviceId);
await this._waitForBootToComplete(deviceId);
}

async acquireFreeDevice(name) {
Expand Down Expand Up @@ -70,11 +72,30 @@ class EmulatorDriver extends AndroidDriver {
throw new Error(`Got more than one device corresponding to the name: ${name}`);
}

await this.adb.waitForBootComplete(adbName);
await this._waitForBootToComplete(adbName);
await this.adb.unlockScreen(adbName);
return adbName;
}

async _waitForBootToComplete(deviceId) {
const start = Date.now();
const maxTimeToBoot = 10 * 60 * 1000;

while (Date.now() - start < maxTimeToBoot) {
const isBootComplete = await this.adb.isBootComplete(deviceId);

if (isBootComplete) {
return;
}

sleep(2000);
}

throw new DetoxRuntimeError({
message: `Failed to wait enough time for boot to complete on device: ${deviceId}`,
});
}

async shutdown(deviceId) {
const port = _.split(deviceId, '-')[1];
const telnet = new EmulatorTelnet();
Expand Down
Loading

0 comments on commit 8eaae6b

Please sign in to comment.