Skip to content

Commit

Permalink
Merge pull request #2259 from brendandburns/coverage
Browse files Browse the repository at this point in the history
Add coverage improvements for web-socket-handler.
  • Loading branch information
k8s-ci-robot authored Feb 24, 2025
2 parents eca415c + 80d3092 commit b31eeb6
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 13 deletions.
11 changes: 9 additions & 2 deletions src/web-socket-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,12 @@ export class WebSocketHandler implements WebSocketInterface {
stdin: stream.Readable,
streamNum: number = 0,
retryCount: number = 3,
// kind of hacky, but otherwise we can't wait for the writes to flush before testing.
addFlushForTesting: boolean = false,
): () => WebSocket.WebSocket | null {
if (retryCount < 0) {
throw new Error("retryCount can't be lower than 0.");
}

let queue: Promise<void> = Promise.resolve();
let ws: WebSocket.WebSocket | null = null;

Expand All @@ -158,8 +159,14 @@ export class WebSocketHandler implements WebSocketInterface {
});
});

if (addFlushForTesting) {
stdin.on('flush', async () => {
await queue;
});
}

stdin.on('end', () => {
if (ws) {
if (ws !== null) {
ws.close();
}
});
Expand Down
115 changes: 104 additions & 11 deletions src/web-socket-handler_test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { deepStrictEqual, notStrictEqual, rejects, strictEqual, throws } from 'node:assert';
import { deepStrictEqual, equal, notStrictEqual, rejects, strictEqual, throws } from 'node:assert';
import { Readable, Writable } from 'node:stream';
import { setImmediate as setImmediatePromise } from 'node:timers/promises';
import WebSocket from 'isomorphic-ws';
Expand Down Expand Up @@ -335,19 +335,30 @@ describe('V5 protocol support', () => {
protocol: 'v5.channel.k8s.io',
} as WebSocket.WebSocket;
let uriOut = '';
let endCalled = false;
let stderrEndCalled = false;
let stdoutEndCalled = false;
let stdinPauseCalled = false;
const handler = new WebSocketHandler(
kc,
(uri: string, protocols: string[], opts: WebSocket.ClientOptions): WebSocket.WebSocket => {
uriOut = uri;
return mockWs as WebSocket.WebSocket;
},
{
stdin: process.stdin,
stderr: process.stderr,
stdin: {
pause: () => {
stdinPauseCalled = true;
return {} as Readable;
},
} as Readable,
stderr: {
end: () => {
stderrEndCalled = true;
},
} as Writable,
stdout: {
end: () => {
endCalled = true;
stdoutEndCalled = true;
},
} as Writable,
},
Expand All @@ -364,17 +375,30 @@ describe('V5 protocol support', () => {
type: 'open',
};
mockWs.onopen!(event);
const closeBuff = Buffer.alloc(2);
closeBuff.writeUint8(255, 0);
closeBuff.writeUint8(WebSocketHandler.StdoutStream, 1);

// Close stdin/stdout with Buffers
[WebSocketHandler.StdinStream, WebSocketHandler.StdoutStream].forEach((stream) => {
const closeBuff = Buffer.alloc(2);
closeBuff.writeUint8(255, 0);
closeBuff.writeUint8(stream, 1);

mockWs.onmessage!({
data: closeBuff,
type: 'type',
target: mockWs,
});
});
// Close stderr with a string \xff is 'close' \x02 is the stderr stream number
// so that both paths are tested.
const closeMsg = '\xFF\x02';
mockWs.onmessage!({
data: closeBuff,
data: closeMsg,
type: 'type',
target: mockWs,
});
await promise;
strictEqual(endCalled, true);
strictEqual(stdoutEndCalled, true);
strictEqual(stderrEndCalled, true);
strictEqual(stdinPauseCalled, true);
});
it('should handle closing stdin < v4 protocol', () => {
const ws = {
Expand Down Expand Up @@ -436,4 +460,73 @@ describe('Restartable Handle Standard Input', () => {
strictEqual(count, retryTimes);
});
});

it('should work correctly', async () => {
let sent: Buffer | null = null;
const ws = {
protocol: 'v5.channel.k8s.io',
send: (data) => {
sent = data;
},
readyState: WebSocket.OPEN,
close: () => {
throw new Error('should not be called');
},
} as unknown as WebSocket;
const p = new Promise<WebSocket>((resolve, reject) => resolve(ws));
let dataCb: any;
let endCb: any;
let flushCb: any;

const r = {
on: (verb, cb) => {
if (verb === 'data') {
dataCb = cb;
}
if (verb === 'end') {
endCb = cb;
}
if (verb == 'flush') {
flushCb = cb;
}
},
} as Readable;

WebSocketHandler.restartableHandleStandardInput(() => p, r, 0, 4, true);

dataCb('some test data');
endCb();
await flushCb();

equal(sent!.toString(), '\x00some test data');
});

it('should work if the web socket exists', () => {
let sent: Buffer | null = null;
const ws = {
protocol: 'v5.channel.k8s.io',
send: (data) => {
sent = data;
},
readyState: WebSocket.OPEN,
close: () => {
throw new Error('should not be called');
},
} as unknown as WebSocket;
let count = 0;
WebSocketHandler.processData(
'some test data',
ws,
(): Promise<WebSocket.WebSocket> => {
return new Promise<WebSocket.WebSocket>((resolve) => {
count++;
resolve(ws as WebSocket.WebSocket);
});
},
0,
5,
);
equal(sent!.toString(), '\x00some test data');
strictEqual(count, 0);
});
});

0 comments on commit b31eeb6

Please sign in to comment.