diff --git a/index.js b/index.js index d4c1253d..79bfce1b 100644 --- a/index.js +++ b/index.js @@ -93,10 +93,10 @@ const createMeasurement = async (req, res, client, getCurrentRound) => { measurement.protocol, measurement.participantAddress, measurement.timeout || false, - new Date(measurement.startAt), + parseOptionalDate(measurement.startAt), measurement.statusCode, - new Date(measurement.firstByteAt), - new Date(measurement.endAt), + parseOptionalDate(measurement.firstByteAt), + parseOptionalDate(measurement.endAt), measurement.byteLength, measurement.attestation, inetGroup, @@ -285,3 +285,18 @@ export const createHandler = async ({ }) } } + +/** + * Parse a date string field that may be `undefined` or `null`. + * + * - undefined -> undefined + * - null -> undefined + * - "iso-date-string" -> new Date("iso-date-string") + * + * @param {string | null | undefined} str + * @returns {Date | undefined} + */ +const parseOptionalDate = (str) => { + if (str === undefined || str === null) return undefined + return new Date(str) +} diff --git a/spark-publish/test/test.js b/spark-publish/test/test.js index 8fe35cff..78c5e7bc 100644 --- a/spark-publish/test/test.js +++ b/spark-publish/test/test.js @@ -98,7 +98,7 @@ describe('integration', () => { startAt: new Date('2023-09-18T13:33:51.239Z'), statusCode: 200, firstByteAt: new Date('2023-09-18T13:33:51.239Z'), - endAt: new Date('2023-09-18T13:33:51.239Z'), + endAt: null, byteLength: 100, attestation: 'json.sig', inetGroup: 'MTIzNDU2Nzg', @@ -208,6 +208,7 @@ describe('integration', () => { assert.strictEqual(published.cid, measurementRecorded.cid) assert.strictEqual(published.inet_group, measurementRecorded.inetGroup) assert.strictEqual(published.car_too_large, measurementRecorded.carTooLarge) + assert.strictEqual(published.end_at, null) // TODO: test other fields // We are publishing records with invalid wallet addresses too diff --git a/test/test.js b/test/test.js index 08020ee3..9377d4dd 100644 --- a/test/test.js +++ b/test/test.js @@ -213,6 +213,43 @@ describe('Routes', () => { ]) assert.strictEqual(measurementRow.participant_address, participantAddress) }) + + it('handles date fields set to null', async () => { + await client.query('DELETE FROM measurements') + + const measurement = { + cid: 'bafytest', + providerAddress: '/dns4/localhost/tcp/8080', + protocol: 'graphsync', + sparkVersion: '1.2.3', + zinniaVersion: '2.3.4', + participantAddress, + startAt: new Date(), + statusCode: undefined, + firstByteAt: null, + endAt: null + } + + const createRequest = await fetch(`${spark}/measurements`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(measurement) + }) + await assertResponseStatus(createRequest, 200) + const { id } = await createRequest.json() + + const { rows: [measurementRow] } = await client.query(` + SELECT * + FROM measurements + WHERE id = $1 + `, [ + id + ]) + + assert.strictEqual(measurementRow.status_code, null) + assert.strictEqual(measurementRow.first_byte_at, null) + assert.strictEqual(measurementRow.end_at, null) + }) }) describe('GET /measurements/:id', () => {