Skip to content

Commit 04f071e

Browse files
committed
fix(debug-ios): clean up and exit when the app's socket closes
The backend close handler cleared the session before closing the WebSocket, so the WebSocket's close handler no longer saw it as current and skipped destroying the socket and exiting without --watch.
1 parent 1d8dea6 commit 04f071e

3 files changed

Lines changed: 47 additions & 12 deletions

File tree

‎lib/common/test/unit-tests/services/net-service.ts‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,18 @@ describe("net", () => {
3030
const hosts = [undefined, "127.0.0.1", "::1", "0.0.0.0", "::"];
3131

3232
for (const host of hosts) {
33-
it(`returns false for a port taken on ${host || "the default address"}`, async () => {
33+
it(`returns false for a port taken on ${host || "the default address"}`, async function () {
3434
const service = createTestInjector("darwin").resolve<INet>(Net);
3535
const server = net.createServer();
36-
await new Promise<void>((resolve) =>
37-
host
38-
? server.listen(0, host, () => resolve())
39-
: server.listen(0, () => resolve()),
40-
);
36+
const listening = await new Promise<boolean>((resolve) => {
37+
server.once("error", () => resolve(false));
38+
const onListening = () => resolve(true);
39+
host ? server.listen(0, host, onListening) : server.listen(0, onListening);
40+
});
41+
if (!listening) {
42+
this.skip();
43+
return;
44+
}
4145
const { port } = <net.AddressInfo>server.address();
4246

4347
try {

‎lib/device-sockets/ios/app-debug-socket-proxy-factory.ts‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,6 @@ export class AppDebugSocketProxyFactory
290290

291291
appDebugSocket.on("close", () => {
292292
this.$logger.trace("Backend socket closed!");
293-
if (currentSession === session) {
294-
currentSession = null;
295-
}
296293
webSocket.close();
297294
});
298295

‎test/device-sockets/app-debug-socket-proxy-factory.ts‎

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { assert } from "chai";
22
import * as net from "net";
33
import * as os from "os";
4+
import * as sinon from "sinon";
45
import * as ws from "ws";
56
import { MessageUnpackStream } from "ios-device-lib";
67
import {
@@ -18,6 +19,11 @@ const encode = (message: string): Buffer => {
1819
return payload;
1920
};
2021

22+
const hasIPv6Loopback = () =>
23+
Object.values(os.networkInterfaces())
24+
.flat()
25+
.some((address) => address.internal && address.family === "IPv6");
26+
2127
describe("AppDebugSocketProxyFactory", () => {
2228
let backend: net.Server;
2329
let backendPort: number;
@@ -61,11 +67,14 @@ describe("AppDebugSocketProxyFactory", () => {
6167
};
6268
};
6369

64-
const createProxy = (getAvailablePortInRange?: () => Promise<number>) =>
70+
const createProxy = (
71+
getAvailablePortInRange?: () => Promise<number>,
72+
watch = true,
73+
) =>
6574
new AppDebugSocketProxyFactory(
6675
<any>{ info: () => {}, trace: () => {}, warn: () => {} },
6776
<any>{ fail: (message: string) => assert.fail(message) },
68-
<any>{ watch: true },
77+
<any>{ watch },
6978
<any>{},
7079
<any>{
7180
getAvailablePortInRange:
@@ -161,7 +170,11 @@ describe("AppDebugSocketProxyFactory", () => {
161170
it("listens on both loopback addresses and nothing else", async () => {
162171
const port = await startProxy();
163172

164-
for (const host of ["127.0.0.1", "[::1]"]) {
173+
const hosts = ["127.0.0.1"];
174+
if (hasIPv6Loopback()) {
175+
hosts.push("[::1]");
176+
}
177+
for (const host of hosts) {
165178
const client = await open(port, undefined, host);
166179
assert.equal(await roundTrip(client, host), host);
167180
}
@@ -229,6 +242,27 @@ describe("AppDebugSocketProxyFactory", () => {
229242
assert.equal(backendConnections, 2);
230243
});
231244

245+
it("cleans up and exits without watch when the app goes away", async () => {
246+
const exit = sinon.stub(process, "exit");
247+
const destroyDebugSocket = sinon.spy(device, "destroyDebugSocket");
248+
try {
249+
const port = await startProxy(createProxy(undefined, false));
250+
const client = await open(port);
251+
const closed = closeReason(client);
252+
const appSocket = await device.getDebugSocket("app");
253+
254+
appSocket.destroy();
255+
await closed;
256+
await new Promise((resolve) => setTimeout(resolve, 20));
257+
258+
assert.isTrue(destroyDebugSocket.called);
259+
assert.isTrue(exit.calledWith(0));
260+
} finally {
261+
exit.restore();
262+
destroyDebugSocket.restore();
263+
}
264+
});
265+
232266
it("keeps the new client's backend when the replaced client closes late", async () => {
233267
const port = await startProxy();
234268
const first = await open(port);

0 commit comments

Comments
 (0)