Skip to content

Commit

Permalink
fix: improve ping output parsing for IP targets
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinKolarik committed Aug 8, 2024
1 parent 78b1ec7 commit f6c97da
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 3 deletions.
4 changes: 2 additions & 2 deletions src/command/handlers/ping/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function parse (rawOutput: string): PingParseOutput {
return { status: 'failed', rawOutput };
}

const header = /^PING\s(?<host>.*?)\s\((?<addr>.+?)\)/.exec(lines[0] ?? '');
const header = /^PING\s(?<host>[^()\s]*?)\s?\((?:[^()\s]+\s?\()?(?<addr>[^()\s]+?)\)/.exec(lines[0] ?? '');

if (!header) {
return { status: 'failed', rawOutput };
Expand All @@ -38,7 +38,7 @@ export default function parse (rawOutput: string): PingParseOutput {
const resolvedAddress = String(header?.groups?.['addr']);
const timeLines = lines.slice(1).map(l => parseStatsLine(l)).filter(Boolean) as PingTimings[];

const resolvedHostname = (/(?<=from\s).*?(?=\s)/.exec((lines[1] ?? '')))?.[0];
const resolvedHostname = (/(?<=from\s).*?(?=\s\(|:\s)/.exec((lines[1] ?? '')))?.[0];
const summaryHeaderIndex = lines.findIndex(l => /^---\s(.*)\sstatistics ---/.test(l));
const summary = parseSummary(lines.slice(summaryHeaderIndex + 1));

Expand Down
33 changes: 33 additions & 0 deletions test/mocks/ipv6-ping-success-no-domain.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"testId": "test",
"measurementId": "measurement",
"result": {
"status": "finished",
"rawOutput": "PING 2606:4700:4700::1111(2606:4700:4700::1111) 56 data bytes\n64 bytes from 2606:4700:4700::1111: icmp_seq=1 ttl=57 time=1.47 ms\n64 bytes from 2606:4700:4700::1111: icmp_seq=2 ttl=57 time=1.14 ms\n64 bytes from 2606:4700:4700::1111: icmp_seq=3 ttl=57 time=1.07 ms\n\n--- google.com ping statistics ---\n3 packets transmitted, 3 received, 0% packet loss, time 1003ms\nrtt min/avg/max/mdev = 1.072/1.224/1.466/0.172 ms\n",
"resolvedAddress": "2606:4700:4700::1111",
"resolvedHostname": "2606:4700:4700::1111",
"timings": [
{
"ttl": 57,
"rtt": 1.47
},
{
"ttl": 57,
"rtt": 1.14
},
{
"ttl": 57,
"rtt": 1.07
}
],
"stats": {
"min": 1.072,
"max": 1.466,
"avg": 1.224,
"total": 3,
"loss": 0,
"rcv": 3,
"drop": 0
}
}
}
8 changes: 8 additions & 0 deletions test/mocks/ipv6-ping-success-no-domain.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
PING 2606:4700:4700::1111(2606:4700:4700::1111) 56 data bytes
64 bytes from 2606:4700:4700::1111: icmp_seq=1 ttl=57 time=1.47 ms
64 bytes from 2606:4700:4700::1111: icmp_seq=2 ttl=57 time=1.14 ms
64 bytes from 2606:4700:4700::1111: icmp_seq=3 ttl=57 time=1.07 ms

--- google.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1003ms
rtt min/avg/max/mdev = 1.072/1.224/1.466/0.172 ms
33 changes: 33 additions & 0 deletions test/mocks/ping-success-linux-no-domain.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"testId": "test",
"measurementId": "measurement",
"result": {
"status": "finished",
"resolvedAddress": "1.1.1.1",
"resolvedHostname": "1.1.1.1",
"stats": {
"min": 41.666,
"max": 41.706,
"avg": 41.689,
"total": 3,
"loss": 0,
"rcv": 3,
"drop": 0
},
"timings": [
{
"ttl": 58,
"rtt": 41.7
},
{
"ttl": 58,
"rtt": 41.7
},
{
"ttl": 58,
"rtt": 41.7
}
],
"rawOutput": "PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.\n64 bytes from 1.1.1.1: icmp_seq=1 ttl=58 time=41.7 ms\n64 bytes from 1.1.1.1: icmp_seq=2 ttl=58 time=41.7 ms\n64 bytes from 1.1.1.1: icmp_seq=3 ttl=58 time=41.7 ms\n\n--- 1.1.1.1 ping statistics ---\n3 packets transmitted, 3 received, 0% packet loss, time 1003ms\nrtt min/avg/max/mdev = 41.666/41.689/41.706/0.017 ms\n"
}
}
8 changes: 8 additions & 0 deletions test/mocks/ping-success-linux-no-domain.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=58 time=41.7 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=58 time=41.7 ms
64 bytes from 1.1.1.1: icmp_seq=3 ttl=58 time=41.7 ms

--- 1.1.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1003ms
rtt min/avg/max/mdev = 41.666/41.689/41.706/0.017 ms
32 changes: 31 additions & 1 deletion test/unit/command/ping-command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ describe('ping command executor', () => {
sandbox.reset();
});

const successfulCommands = [ 'ping-success-linux', 'ping-no-source-ip-linux' ];
const successfulCommands = [ 'ping-success-linux', 'ping-success-linux-no-domain', 'ping-no-source-ip-linux' ];

for (const command of successfulCommands) {
it(`should run and parse successful commands - ${command}`, async () => {
Expand Down Expand Up @@ -215,6 +215,36 @@ describe('ping command executor', () => {
expect(mockedSocket.emit.firstCall.args).to.deep.equal([ 'probe:measurement:result', expectedResult ]);
});

it(`should run and parse successful command without progress updates - ipv6-ping-success-no-domain`, async () => {
const testCase = 'ipv6-ping-success-no-domain';
const rawOutput = getCmdMock(testCase);
const outputProgress = rawOutput.split('\n');
const expectedResult = getCmdMockResult(testCase);
const options = {
type: 'ping' as PingOptions['type'],
target: '2606:4700:4700::1111',
packets: 3,
inProgressUpdates: false,
ipVersion: 6,
};

const mockedCmd = getExecaMock();

const ping = new PingCommand((): any => mockedCmd);

const runPromise = ping.run(mockedSocket as any, 'measurement', 'test', options);

for (const progressOutput of outputProgress) {
mockedCmd.stdout.emit('data', Buffer.from(progressOutput, 'utf8'));
}

mockedCmd.resolve({ stdout: rawOutput });
await runPromise;

expect(mockedSocket.emit.callCount).to.equal(1);
expect(mockedSocket.emit.firstCall.args).to.deep.equal([ 'probe:measurement:result', expectedResult ]);
});

it('should run and fail private ip command on the progress step', async () => {
const command = 'ping-private-ip-linux';
const rawOutput = getCmdMock(command);
Expand Down

0 comments on commit f6c97da

Please sign in to comment.