From 926870b294b2425306fd44936f436bd8db03a4c4 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Fri, 25 May 2018 11:16:07 +0300 Subject: [PATCH 1/6] fix: Unable to debug on iOS Simulator when multiple sims are running In case multiple iOS Simulators are running and `tns debug ios` is called, CLI prompts you to select you on which device/simulator to debug. Selecting the device and trying to debug your application leads to error as CLI does not pass correctly the device identifier. Fix this by passing the correct device identifier. Also update ios-sim-portable to latest version, where several fixes for this case are applied --- lib/common | 2 +- lib/services/ios-debug-service.ts | 5 +++-- npm-shrinkwrap.json | 6 +++--- package.json | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/common b/lib/common index fba05a71d4..a20a105da0 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit fba05a71d43a878fe8547363237f1de9d871385f +Subproject commit a20a105da0789a4c57bc6420ce6bb2b594789d77 diff --git a/lib/services/ios-debug-service.ts b/lib/services/ios-debug-service.ts index 98ba3493c0..bbf91c221a 100644 --- a/lib/services/ios-debug-service.ts +++ b/lib/services/ios-debug-service.ts @@ -106,12 +106,13 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS private async emulatorDebugBrk(debugData: IDebugData, debugOptions: IDebugOptions): Promise { const args = debugOptions.debugBrk ? "--nativescript-debug-brk" : "--nativescript-debug-start"; - const launchResult = await this.$iOSEmulatorServices.runApplicationOnEmulator(debugData.pathToAppPackage, { + const launchResult = await this.$iOSEmulatorServices.runApplicationOnEmulator(debugData.pathToAppPackage, { waitForDebugger: true, captureStdin: true, args: args, appId: debugData.applicationIdentifier, - skipInstall: true + skipInstall: true, + device: debugData.deviceIdentifier }); const pid = getPidFromiOSSimulatorLogs(debugData.applicationIdentifier, launchResult); diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index b42340ae95..4f3c58ba23 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -2868,9 +2868,9 @@ } }, "ios-sim-portable": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/ios-sim-portable/-/ios-sim-portable-3.4.1.tgz", - "integrity": "sha512-5zouPe8hjN6tLCwoxYXT4S1l2lY0aMZAXOGK9L8pPF8nXtanNKbVxpCrEszKcCbGzNQ/WyY/diJXTNL1ZO6HZg==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/ios-sim-portable/-/ios-sim-portable-3.4.3.tgz", + "integrity": "sha512-Ail75Gfk9FkEEeTbgoQwXOFR/+DJFGXWNbekZDpdd4zmyzYEMfp8ZG2J0KefKlDeYJ2H3lA/Y7OtDMcT3oF9ug==", "requires": { "bplist-parser": "https://github.com/telerik/node-bplist-parser/tarball/master", "colors": "0.6.2", diff --git a/package.json b/package.json index 180e50cbaf..51981060da 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "inquirer": "0.9.0", "ios-device-lib": "0.4.12", "ios-mobileprovision-finder": "1.0.10", - "ios-sim-portable": "3.4.1", + "ios-sim-portable": "3.4.3", "jimp": "0.2.28", "lockfile": "1.0.3", "lodash": "4.13.1", From 640789db090720e0198ecba29d7f15003974725c Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Fri, 25 May 2018 11:20:34 +0300 Subject: [PATCH 2/6] fix: `tns debug ios --start` fails The `tns debug ios --start` command fails as we do not get the port from iOS Application on device in this case. In order to fix this, start the log parsing in case --start option is passed. Also fix the attaching to ATTACH_REQUEST_EVENT_NAME - we've incorrectly attached to device's application manager, which does not emit such event. Fix it by attaching to `iOSNotification`, which is the correct one. Also remove incorrect cache decorator and ensure we do not start logging for iOS devices more than once. --- lib/declarations.d.ts | 4 ++-- lib/device-sockets/ios/notification.ts | 2 ++ lib/services/ios-debug-service.ts | 3 +++ lib/services/ios-debugger-port-service.ts | 3 ++- lib/services/ios-log-parser-service.ts | 15 +++++++++------ 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/lib/declarations.d.ts b/lib/declarations.d.ts index f2b21b0e6b..5f7de2f4cd 100644 --- a/lib/declarations.d.ts +++ b/lib/declarations.d.ts @@ -643,7 +643,7 @@ interface ISocketProxyFactory extends NodeJS.EventEmitter { createWebSocketProxy(factory: () => Promise, deviceIdentifier: string): Promise; } -interface IiOSNotification { +interface IiOSNotification extends NodeJS.EventEmitter { getWaitForDebug(projectId: string): string; getAttachRequest(projectId: string, deviceId: string): string; getAppLaunching(projectId: string): string; @@ -843,4 +843,4 @@ interface IAssetsGenerationService { * @returns {Promise} */ generateSplashScreens(splashesGenerationData: ISplashesGenerationData): Promise; -} \ No newline at end of file +} diff --git a/lib/device-sockets/ios/notification.ts b/lib/device-sockets/ios/notification.ts index d5bef34de4..d72e46057e 100644 --- a/lib/device-sockets/ios/notification.ts +++ b/lib/device-sockets/ios/notification.ts @@ -15,6 +15,8 @@ export class IOSNotification extends EventEmitter implements IiOSNotification { } public getAttachRequest(appId: string, deviceId: string): string { + // It could be too early to emit this event, but we rely that if you construct attach request, + // you will execute it immediately. this.emit(ATTACH_REQUEST_EVENT_NAME, { deviceId, appId }); return this.formatNotification(IOSNotification.ATTACH_REQUEST_NOTIFICATION_NAME, appId); } diff --git a/lib/services/ios-debug-service.ts b/lib/services/ios-debug-service.ts index bbf91c221a..978cde1f7c 100644 --- a/lib/services/ios-debug-service.ts +++ b/lib/services/ios-debug-service.ts @@ -127,6 +127,8 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS } private async emulatorStart(debugData: IDebugData, debugOptions: IDebugOptions): Promise { + const device = await this.$devicesService.getDevice(debugData.deviceIdentifier); + this.$iOSDebuggerPortService.attachToDebuggerPortFoundEvent(device); const result = await this.wireDebuggerClient(debugData, debugOptions); const attachRequestMessage = this.$iOSNotification.getAttachRequest(debugData.applicationIdentifier, debugData.deviceIdentifier); @@ -175,6 +177,7 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS } private async deviceStartCore(device: Mobile.IiOSDevice, debugData: IDebugData, debugOptions: IDebugOptions): Promise { + this.$iOSDebuggerPortService.attachToDebuggerPortFoundEvent(device); await this.$iOSSocketRequestExecutor.executeAttachRequest(device, AWAIT_NOTIFICATION_TIMEOUT_SECONDS, debugData.applicationIdentifier); return this.wireDebuggerClient(debugData, debugOptions, device); } diff --git a/lib/services/ios-debugger-port-service.ts b/lib/services/ios-debugger-port-service.ts index 5e94d373a6..64c4dc830f 100644 --- a/lib/services/ios-debugger-port-service.ts +++ b/lib/services/ios-debugger-port-service.ts @@ -9,6 +9,7 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService { constructor(private $iOSLogParserService: IIOSLogParserService, private $iOSProjectService: IPlatformProjectService, + private $iOSNotification: IiOSNotification, private $logger: ILogger, private $projectData: IProjectData) { } @@ -62,7 +63,7 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService { @cache() private attachToAttachRequestEvent(device: Mobile.IDevice): void { - device.applicationManager.on(ATTACH_REQUEST_EVENT_NAME, (data: IIOSDebuggerPortData) => { + this.$iOSNotification.on(ATTACH_REQUEST_EVENT_NAME, (data: IIOSDebuggerPortData) => { this.$logger.trace(ATTACH_REQUEST_EVENT_NAME, data); const timer = setTimeout(() => { this.clearTimeout(data); diff --git a/lib/services/ios-log-parser-service.ts b/lib/services/ios-log-parser-service.ts index dd8108f34e..efd9d75fec 100644 --- a/lib/services/ios-log-parser-service.ts +++ b/lib/services/ios-log-parser-service.ts @@ -1,26 +1,29 @@ import { DEBUGGER_PORT_FOUND_EVENT_NAME, DEVICE_LOG_EVENT_NAME } from "../common/constants"; -import { cache } from "../common/decorators"; import { EventEmitter } from "events"; export class IOSLogParserService extends EventEmitter implements IIOSLogParserService { private static MESSAGE_REGEX = /NativeScript debugger has opened inspector socket on port (\d+?) for (.*)[.]/; + private startedDeviceLogInstances: IDictionary = {}; + constructor(private $deviceLogProvider: Mobile.IDeviceLogProvider, private $iosDeviceOperations: IIOSDeviceOperations, private $iOSSimulatorLogProvider: Mobile.IiOSSimulatorLogProvider, private $logger: ILogger, private $projectData: IProjectData) { - super(); - } + super(); + } public startParsingLog(device: Mobile.IDevice): void { this.$deviceLogProvider.setProjectNameForDevice(device.deviceInfo.identifier, this.$projectData.projectName); - this.startParsingLogCore(device); - this.startLogProcess(device); + if (!this.startedDeviceLogInstances[device.deviceInfo.identifier]) { + this.startParsingLogCore(device); + this.startLogProcess(device); + this.startedDeviceLogInstances[device.deviceInfo.identifier] = true; + } } - @cache() private startParsingLogCore(device: Mobile.IDevice): void { const logProvider = device.isEmulator ? this.$iOSSimulatorLogProvider : this.$iosDeviceOperations; logProvider.on(DEVICE_LOG_EVENT_NAME, (response: IOSDeviceLib.IDeviceLogData) => this.processDeviceLogResponse(response)); From 80d779d327bf648a9f0ed7c430dfbe3b533bc296 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Fri, 25 May 2018 12:02:05 +0300 Subject: [PATCH 3/6] chore: Fix unit tests Fix unit tests and use sinon to mock the timers. This way the execution of the tests for getting port is now around 50ms instead of 15 seconds --- test/services/ios-debugger-port-service.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/test/services/ios-debugger-port-service.ts b/test/services/ios-debugger-port-service.ts index fda70f07c9..a1a8cd2950 100644 --- a/test/services/ios-debugger-port-service.ts +++ b/test/services/ios-debugger-port-service.ts @@ -6,6 +6,7 @@ import { IOSLogParserService } from "../../lib/services/ios-log-parser-service"; import { IOSSimulatorLogProvider } from "../../lib/common/mobile/ios/simulator/ios-simulator-log-provider"; import { Yok } from "../../lib/common/yok"; import { EventEmitter } from "events"; +import * as sinon from "sinon"; class DeviceApplicationManagerMock extends EventEmitter { } @@ -50,6 +51,7 @@ function createTestInjector() { projectName: "test", projectId: appId }); + injector.register("iOSNotification", DeviceApplicationManagerMock); return injector; } @@ -82,11 +84,17 @@ function getMultilineDebuggerPortMessage(port: number) { describe("iOSDebuggerPortService", () => { let injector: IInjector, iOSDebuggerPortService: IIOSDebuggerPortService, iosDeviceOperations: IIOSDeviceOperations; + let clock: sinon.SinonFakeTimers = null; beforeEach(() => { injector = createTestInjector(); iOSDebuggerPortService = injector.resolve("iOSDebuggerPortService"); iosDeviceOperations = injector.resolve("iosDeviceOperations"); + clock = sinon.useFakeTimers(); + }); + + afterEach(() => { + clock.restore(); }); function emitDeviceLog(message: string) { @@ -142,7 +150,9 @@ describe("iOSDebuggerPortService", () => { emitDeviceLog(getDebuggerPortMessage(testCase.emittedPort)); } - const port = await iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId }); + const promise = iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId }); + clock.tick(10000); + const port = await promise; assert.deepEqual(port, testCase.emittedPort); }); it(`${testCase.name} for multiline debugger port message.`, async () => { @@ -154,7 +164,9 @@ describe("iOSDebuggerPortService", () => { emitDeviceLog(getMultilineDebuggerPortMessage(testCase.emittedPort)); } - const port = await iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId }); + const promise = iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId }); + clock.tick(10000); + const port = await promise; assert.deepEqual(port, testCase.emittedPort); }); }); From dee21484c9e1d43816c381b2bbe2bf0512d59857 Mon Sep 17 00:00:00 2001 From: fatme Date: Fri, 25 May 2018 12:48:06 +0300 Subject: [PATCH 4/6] Show missing console.logs when `tns debug` command is executed --- lib/services/ios-debug-service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/services/ios-debug-service.ts b/lib/services/ios-debug-service.ts index 978cde1f7c..efdb98c62e 100644 --- a/lib/services/ios-debug-service.ts +++ b/lib/services/ios-debug-service.ts @@ -39,7 +39,9 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS return "ios"; } - public debug(debugData: IDebugData, debugOptions: IDebugOptions): Promise { + public async debug(debugData: IDebugData, debugOptions: IDebugOptions): Promise { + await this.device.openDeviceLogStream(); + if (debugOptions.debugBrk && debugOptions.start) { this.$errors.failWithoutHelp("Expected exactly one of the --debug-brk or --start options."); } From 0407d564870db1b7d04dd08b50edb6fd41665e54 Mon Sep 17 00:00:00 2001 From: fatme Date: Fri, 25 May 2018 13:16:57 +0300 Subject: [PATCH 5/6] Attach to debugger port found event when debug command is executed on real iOS device --- lib/device-sockets/ios/socket-proxy-factory.ts | 2 +- lib/services/livesync/ios-livesync-service.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/device-sockets/ios/socket-proxy-factory.ts b/lib/device-sockets/ios/socket-proxy-factory.ts index 89271a130c..368063faeb 100644 --- a/lib/device-sockets/ios/socket-proxy-factory.ts +++ b/lib/device-sockets/ios/socket-proxy-factory.ts @@ -95,7 +95,7 @@ export class SocketProxyFactory extends EventEmitter implements ISocketProxyFact err.deviceIdentifier = deviceIdentifier; this.$logger.trace(err); this.emit(CONNECTION_ERROR_EVENT_NAME, err); - this.$errors.failWithoutHelp("Cannot connect to device socket."); + this.$errors.failWithoutHelp(`Cannot connect to device socket. The error message is ${err.message}`); } this.$logger.info("Backend socket created."); diff --git a/lib/services/livesync/ios-livesync-service.ts b/lib/services/livesync/ios-livesync-service.ts index da1e921fe0..e9fe3c75d5 100644 --- a/lib/services/livesync/ios-livesync-service.ts +++ b/lib/services/livesync/ios-livesync-service.ts @@ -13,6 +13,7 @@ export class IOSLiveSyncService extends PlatformLiveSyncServiceBase implements I $devicePathProvider: IDevicePathProvider, $logger: ILogger, $projectFilesProvider: IProjectFilesProvider, + private $iOSDebuggerPortService: IIOSDebuggerPortService, ) { super($fs, $logger, $platformsData, $projectFilesManager, $devicePathProvider, $projectFilesProvider); } @@ -22,6 +23,8 @@ export class IOSLiveSyncService extends PlatformLiveSyncServiceBase implements I if (device.isEmulator) { return super.fullSync(syncInfo); + } else { + this.$iOSDebuggerPortService.attachToDebuggerPortFoundEvent(device); } const projectData = syncInfo.projectData; From 75fb86758bdf43191413633c1187e84b8ed27070 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Fri, 25 May 2018 15:10:09 +0300 Subject: [PATCH 6/6] chore: Remove unneeded else statement --- lib/services/livesync/ios-livesync-service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/services/livesync/ios-livesync-service.ts b/lib/services/livesync/ios-livesync-service.ts index e9fe3c75d5..31f66b768f 100644 --- a/lib/services/livesync/ios-livesync-service.ts +++ b/lib/services/livesync/ios-livesync-service.ts @@ -23,10 +23,10 @@ export class IOSLiveSyncService extends PlatformLiveSyncServiceBase implements I if (device.isEmulator) { return super.fullSync(syncInfo); - } else { - this.$iOSDebuggerPortService.attachToDebuggerPortFoundEvent(device); } + this.$iOSDebuggerPortService.attachToDebuggerPortFoundEvent(device); + const projectData = syncInfo.projectData; const platformData = this.$platformsData.getPlatformData(device.deviceInfo.platform, projectData); const deviceAppData = await this.getAppData(syncInfo);