Skip to content

fix: Test command runs tests twice and often fails on Android #3786

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 3 commits into from
Aug 2, 2018
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
7 changes: 0 additions & 7 deletions lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,6 @@ class ItunesConnectApplicationTypesClass implements IiTunesConnectApplicationTyp
}

export const ItunesConnectApplicationTypes = new ItunesConnectApplicationTypesClass();
export class LiveSyncPaths {
static SYNC_DIR_NAME = "sync";
static REMOVEDSYNC_DIR_NAME = "removedsync";
static FULLSYNC_DIR_NAME = "fullsync";
static IOS_DEVICE_PROJECT_ROOT_PATH = "Library/Application Support/LiveSync";
static IOS_DEVICE_SYNC_ZIP_PATH = "Library/Application Support/LiveSync/sync.zip";
}
export const ANGULAR_NAME = "angular";
export const TYPESCRIPT_NAME = "typescript";
export const BUILD_OUTPUT_EVENT_NAME = "buildOutput";
Expand Down
5 changes: 3 additions & 2 deletions lib/device-path-provider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { fromWindowsRelativePathToUnix } from "./common/helpers";
import { APP_FOLDER_NAME, LiveSyncPaths } from "./constants";
import { APP_FOLDER_NAME } from "./constants";
import { LiveSyncPaths } from "./common/constants";
import { AndroidDeviceLiveSyncService } from "./services/livesync/android-device-livesync-service";
import * as path from "path";

Expand All @@ -23,7 +24,7 @@ export class DevicePathProvider implements IDevicePathProvider {
projectRoot = path.join(projectRoot, APP_FOLDER_NAME);
}
} else if (this.$mobileHelper.isAndroidPlatform(device.deviceInfo.platform)) {
projectRoot = `/data/local/tmp/${options.appIdentifier}`;
projectRoot = `${LiveSyncPaths.ANDROID_TMP_DIR_NAME}/${options.appIdentifier}`;
if (!options.getDirname) {
const deviceLiveSyncService = this.$injector.resolve<AndroidDeviceLiveSyncService>(AndroidDeviceLiveSyncService, { device });
const hashService = deviceLiveSyncService.getDeviceHashService(options.appIdentifier);
Expand Down
10 changes: 6 additions & 4 deletions lib/services/android-debug-service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { sleep } from "../common/helpers";
import { DebugServiceBase } from "./debug-service-base";
import { LiveSyncPaths } from "../common/constants";

export class AndroidDebugService extends DebugServiceBase implements IPlatformDebugService {
private _packageName: string;
Expand Down Expand Up @@ -158,22 +159,23 @@ export class AndroidDebugService extends DebugServiceBase implements IPlatformDe
await this.device.applicationManager.stopApplication(appData);

if (debugOptions.debugBrk) {
await this.device.adb.executeShellCommand([`cat /dev/null > /data/local/tmp/${appData.appId}-debugbreak`]);
await this.device.adb.executeShellCommand([`cat /dev/null > ${LiveSyncPaths.ANDROID_TMP_DIR_NAME}/${appData.appId}-debugbreak`]);
}

await this.device.adb.executeShellCommand([`cat /dev/null > /data/local/tmp/${appData.appId}-debugger-started`]);
await this.device.adb.executeShellCommand([`cat /dev/null > ${LiveSyncPaths.ANDROID_TMP_DIR_NAME}/${appData.appId}-debugger-started`]);

await this.device.applicationManager.startApplication(appData);

await this.waitForDebugger(appData.appId);
}

private async waitForDebugger(packageName: String): Promise<void> {
const waitText: string = `0 /data/local/tmp/${packageName}-debugger-started`;
const debuggerStartedFilePath = `${LiveSyncPaths.ANDROID_TMP_DIR_NAME}/${packageName}-debugger-started`;
const waitText: string = `0 ${debuggerStartedFilePath}`;
let maxWait = 12;
let debuggerStarted: boolean = false;
while (maxWait > 0 && !debuggerStarted) {
const forwardsResult = await this.device.adb.executeShellCommand(["ls", "-s", `/data/local/tmp/${packageName}-debugger-started`]);
const forwardsResult = await this.device.adb.executeShellCommand(["ls", "-s", debuggerStartedFilePath]);

maxWait--;

Expand Down
4 changes: 2 additions & 2 deletions lib/services/android-project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as semver from "semver";
import * as projectServiceBaseLib from "./platform-project-service-base";
import { DeviceAndroidDebugBridge } from "../common/mobile/android/device-android-debug-bridge";
import { attachAwaitDetach, isRecommendedAarFile } from "../common/helpers";
import { Configurations } from "../common/constants";
import { Configurations, LiveSyncPaths } from "../common/constants";
import { SpawnOptions } from "child_process";

export class AndroidProjectService extends projectServiceBaseLib.PlatformProjectServiceBase implements IPlatformProjectService {
Expand Down Expand Up @@ -631,7 +631,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject

public async cleanDeviceTempFolder(deviceIdentifier: string, projectData: IProjectData): Promise<void> {
const adb = this.$injector.resolve(DeviceAndroidDebugBridge, { identifier: deviceIdentifier });
const deviceRootPath = `/data/local/tmp/${projectData.projectId}`;
const deviceRootPath = `${LiveSyncPaths.ANDROID_TMP_DIR_NAME}/${projectData.projectId}`;
await adb.executeShellCommand(["rm", "-rf", deviceRootPath]);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/services/livesync/android-device-livesync-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { DeviceAndroidDebugBridge } from "../../common/mobile/android/device-and
import { AndroidDeviceHashService } from "../../common/mobile/android/android-device-hash-service";
import { DeviceLiveSyncServiceBase } from "./device-livesync-service-base";
import * as helpers from "../../common/helpers";
import { LiveSyncPaths } from "../../constants";
import { LiveSyncPaths } from "../../common/constants";
import { cache } from "../../common/decorators";
import * as path from "path";
import * as net from "net";
Expand Down
39 changes: 26 additions & 13 deletions lib/services/livesync/android-device-livesync-sockets-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { DeviceAndroidDebugBridge } from "../../common/mobile/android/device-and
import { AndroidDeviceHashService } from "../../common/mobile/android/android-device-hash-service";
import { DeviceLiveSyncServiceBase } from "./device-livesync-service-base";
import { APP_FOLDER_NAME } from "../../constants";
import { LiveSyncPaths } from "../../common/constants";
import { AndroidLivesyncTool } from "./android-livesync-tool";
import * as path from "path";
import * as temp from "temp";

export class AndroidDeviceSocketsLiveSyncService extends DeviceLiveSyncServiceBase implements IAndroidNativeScriptDeviceLiveSyncService, INativeScriptDeviceLiveSyncService {
private livesyncTool: IAndroidLivesyncTool;
Expand All @@ -17,54 +19,65 @@ export class AndroidDeviceSocketsLiveSyncService extends DeviceLiveSyncServiceBa
private $logger: ILogger,
protected device: Mobile.IAndroidDevice,
private $options: ICommonOptions,
private $processService: IProcessService) {
private $processService: IProcessService,
private $fs: IFileSystem) {
super($platformsData, device);
this.livesyncTool = this.$injector.resolve(AndroidLivesyncTool);
}

public async beforeLiveSyncAction(deviceAppData: Mobile.IDeviceAppData): Promise<void> {
const platformData = this.$platformsData.getPlatformData(deviceAppData.platform, this.data);
const projectFilesPath = path.join(platformData.appDestinationDirectoryPath, APP_FOLDER_NAME);
const pathToLiveSyncFile = temp.path({ prefix: "livesync" });
this.$fs.writeFile(pathToLiveSyncFile, "");
await this.device.fileSystem.putFile(pathToLiveSyncFile, this.getPathToLiveSyncFileOnDevice(deviceAppData.appIdentifier), deviceAppData.appIdentifier);
await this.device.applicationManager.startApplication({ appId: deviceAppData.appIdentifier, projectName: this.data.projectName });
await this.connectLivesyncTool(projectFilesPath, this.data.projectId);
}

private getPathToLiveSyncFileOnDevice(appIdentifier: string): string {
return `${LiveSyncPaths.ANDROID_TMP_DIR_NAME}/${appIdentifier}-livesync-in-progress`;
}

public async finalizeSync(liveSyncInfo: ILiveSyncResultInfo) {
await this.doSync(liveSyncInfo);
}

private async doSync(liveSyncInfo: ILiveSyncResultInfo, {doRefresh = false}: {doRefresh?: boolean} = {}): Promise<IAndroidLivesyncSyncOperationResult> {
private async doSync(liveSyncInfo: ILiveSyncResultInfo, { doRefresh = false }: { doRefresh?: boolean } = {}): Promise<IAndroidLivesyncSyncOperationResult> {
const operationId = this.livesyncTool.generateOperationIdentifier();

let result = {operationId, didRefresh: true };
let result = { operationId, didRefresh: true };

if (liveSyncInfo.modifiedFilesData.length) {

const doSyncPromise = this.livesyncTool.sendDoSyncOperation(doRefresh, null, operationId);

const syncInterval : NodeJS.Timer = setInterval(() => {
const syncInterval: NodeJS.Timer = setInterval(() => {
if (this.livesyncTool.isOperationInProgress(operationId)) {
this.$logger.info("Sync operation in progress...");
}
}, AndroidDeviceSocketsLiveSyncService.STATUS_UPDATE_INTERVAL);

const clearSyncInterval = () => {
const actionOnEnd = async () => {
clearInterval(syncInterval);
await this.device.fileSystem.deleteFile(this.getPathToLiveSyncFileOnDevice(liveSyncInfo.deviceAppData.appIdentifier), liveSyncInfo.deviceAppData.appIdentifier);
};

this.$processService.attachToProcessExitSignals(this, clearSyncInterval);
doSyncPromise.then(clearSyncInterval, clearSyncInterval);
this.$processService.attachToProcessExitSignals(this, actionOnEnd);
doSyncPromise.then(actionOnEnd, actionOnEnd);

result = await doSyncPromise;
}

await this.device.fileSystem.deleteFile(this.getPathToLiveSyncFileOnDevice(liveSyncInfo.deviceAppData.appIdentifier), liveSyncInfo.deviceAppData.appIdentifier);

return result;
}

public async refreshApplication(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo) {
const canExecuteFastSync = !liveSyncInfo.isFullSync && this.canExecuteFastSyncForPaths(liveSyncInfo.modifiedFilesData, projectData, this.device.deviceInfo.platform);

const syncOperationResult = await this.doSync(liveSyncInfo, {doRefresh: canExecuteFastSync});
const syncOperationResult = await this.doSync(liveSyncInfo, { doRefresh: canExecuteFastSync });

this.livesyncTool.end();

Expand Down Expand Up @@ -96,28 +109,28 @@ export class AndroidDeviceSocketsLiveSyncService extends DeviceLiveSyncServiceBa
}

private async _transferDirectory(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath: string): Promise<Mobile.ILocalToDevicePathData[]> {
let transferredLocalToDevicePaths : Mobile.ILocalToDevicePathData[];
let transferredLocalToDevicePaths: Mobile.ILocalToDevicePathData[];
const deviceHashService = this.getDeviceHashService(deviceAppData.appIdentifier);
const currentShasums: IStringDictionary = await deviceHashService.generateHashesFromLocalToDevicePaths(localToDevicePaths);
const oldShasums = await deviceHashService.getShasumsFromDevice();

if (this.$options.force || !oldShasums) {
await this.livesyncTool.sendDirectory(projectFilesPath);
await deviceHashService.uploadHashFileToDevice(currentShasums);
transferredLocalToDevicePaths = localToDevicePaths;
transferredLocalToDevicePaths = localToDevicePaths;
} else {
const changedShasums = deviceHashService.getChangedShasums(oldShasums, currentShasums);
const changedFiles = _.keys(changedShasums);
if (changedFiles.length) {
await this.livesyncTool.sendFiles(changedFiles);
await deviceHashService.uploadHashFileToDevice(currentShasums);
transferredLocalToDevicePaths = localToDevicePaths.filter(localToDevicePathData => changedFiles.indexOf(localToDevicePathData.getLocalPath()) >= 0);
transferredLocalToDevicePaths = localToDevicePaths.filter(localToDevicePathData => changedFiles.indexOf(localToDevicePathData.getLocalPath()) >= 0);
} else {
transferredLocalToDevicePaths = [];
transferredLocalToDevicePaths = [];
}
}

return transferredLocalToDevicePaths ;
return transferredLocalToDevicePaths;
}

private async connectLivesyncTool(projectFilesPath: string, appIdentifier: string) {
Expand Down
1 change: 1 addition & 0 deletions lib/services/livesync/android-livesync-tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ export class AndroidLivesyncTool implements IAndroidLivesyncTool {
socket.removeListener("close", tryConnectAfterTimeout);
socket.removeListener("error", tryConnectAfterTimeout);
isConnected = true;
clearTimeout(connectionTimer);
resolve({ socket, data });
});
socket.on("close", tryConnectAfterTimeout);
Expand Down
Loading