From 8c96b54ad51350b93ec58dffaf8627c3bf5c5504 Mon Sep 17 00:00:00 2001 From: Mikers Date: Fri, 12 Jun 2026 13:29:30 -1000 Subject: [PATCH] test: harden Synapse upload result coverage --- cli/src/commands/upload.ts | 10 +-- cli/tests/synapse-commands.test.ts | 100 ++++++++++++++++++++++++++--- 2 files changed, 96 insertions(+), 14 deletions(-) diff --git a/cli/src/commands/upload.ts b/cli/src/commands/upload.ts index 78b70f1..8d50ac5 100644 --- a/cli/src/commands/upload.ts +++ b/cli/src/commands/upload.ts @@ -115,16 +115,16 @@ export const uploadCommand = { }) const cidStr = result.pieceCid.toString() - const copyResults = result.copies.map((copy: any) => ({ - dataSetId: copy.dataSetId, + const copyResults = result.copies.map((copy) => ({ + dataSetId: copy.dataSetId.toString(), datasetScannerUrl: datasetScannerUrl(copy.dataSetId, chain), url: copy.retrievalUrl, - pieceId: copy.pieceId, - providerId: copy.providerId, + pieceId: copy.pieceId.toString(), + providerId: copy.providerId.toString(), isNewDataSet: copy.isNewDataSet, providerRole: copy.role, })) - const copyFailures = result.failedAttempts.map((failure: any) => ({ + const copyFailures = result.failedAttempts.map((failure) => ({ providerId: failure.providerId.toString(), role: failure.role, error: formatFailedAttemptError(failure), diff --git a/cli/tests/synapse-commands.test.ts b/cli/tests/synapse-commands.test.ts index 4dbc05e..998ef50 100644 --- a/cli/tests/synapse-commands.test.ts +++ b/cli/tests/synapse-commands.test.ts @@ -115,7 +115,7 @@ afterEach(async () => { describe('top-level upload commands', () => { test('upload prepares storage, executes funding, uploads, and maps copy results', async () => { const filePath = await tempFile('upload.txt', 'data') - const contexts = [{ id: 'ctx-primary' }] + const contexts = [{ id: 'ctx-primary' }, { id: 'ctx-secondary' }] const execute = mock(async () => ({ hash: '0xprepare' })) synapseStorage.createContexts.mockImplementation(async () => contexts) @@ -125,8 +125,8 @@ describe('top-level upload commands', () => { synapseStorage.upload.mockImplementation(async () => ({ pieceCid: cid('baga-upload'), size: 4, - requestedCopies: 3, - complete: false, + requestedCopies: 2, + complete: true, copies: [ { dataSetId: 42n, @@ -136,12 +136,20 @@ describe('top-level upload commands', () => { isNewDataSet: true, role: 'primary', }, + { + dataSetId: 43n, + retrievalUrl: 'https://backup.example/piece/baga-upload', + pieceId: 8n, + providerId: 79n, + isNewDataSet: false, + role: 'secondary', + }, ], failedAttempts: [ { providerId: 78n, role: 'secondary', - error: 'temporarily unavailable', + error: 'replaced after transient failure', explicit: false, }, ], @@ -150,7 +158,7 @@ describe('top-level upload commands', () => { const result = await uploadCommand.run( commandContext({ args: { path: filePath }, - options: { copies: 3, withCDN: true }, + options: { copies: 2, withCDN: true }, }) ) @@ -159,7 +167,7 @@ describe('top-level upload commands', () => { { client: fakeWalletClient, source: 'foc-cli' }, ]) expect(synapseStorage.createContexts).toHaveBeenCalledWith({ - copies: 3, + copies: 2, withCDN: true, }) expect(synapseStorage.prepare).toHaveBeenCalledWith({ @@ -171,13 +179,13 @@ describe('top-level upload commands', () => { contexts, withCDN: true, }) - expect(result.status).toBe('partially_uploaded') + expect(result.status).toBe('uploaded') expect(result.result).toEqual({ pieceCid: 'baga-upload', pieceScannerUrl: 'https://pdp.vxb.ai/calibration/piece/baga-upload', size: 4, - requestedCopies: 3, - complete: false, + requestedCopies: 2, + complete: true, copyResults: [ { dataSetId: '42', @@ -188,6 +196,80 @@ describe('top-level upload commands', () => { isNewDataSet: true, providerRole: 'primary', }, + { + dataSetId: '43', + datasetScannerUrl: 'https://pdp.vxb.ai/calibration/dataset/43', + url: 'https://backup.example/piece/baga-upload', + pieceId: '8', + providerId: '79', + isNewDataSet: false, + providerRole: 'secondary', + }, + ], + copyFailures: [ + { + providerId: '78', + role: 'secondary', + error: 'replaced after transient failure', + explicit: false, + }, + ], + }) + }) + + test('upload reports partial status when Synapse commits fewer copies than requested', async () => { + const filePath = await tempFile('partial.txt', 'data') + const contexts = [ + { id: 'ctx-primary' }, + { id: 'ctx-secondary-a' }, + { id: 'ctx-secondary-b' }, + ] + + synapseStorage.createContexts.mockImplementation(async () => contexts) + synapseStorage.upload.mockImplementation(async () => ({ + pieceCid: cid('baga-partial'), + size: 4, + requestedCopies: 3, + complete: false, + copies: [ + { + dataSetId: 42n, + retrievalUrl: 'https://provider.example/piece/baga-partial', + pieceId: 7n, + providerId: 77n, + isNewDataSet: true, + role: 'primary', + }, + ], + failedAttempts: [ + { + providerId: 78n, + role: 'secondary', + error: 'temporarily unavailable', + explicit: false, + }, + ], + })) + + const result = await uploadCommand.run( + commandContext({ + args: { path: filePath }, + options: { copies: 3 }, + }) + ) + + expect(result.status).toBe('partially_uploaded') + expect(result.result).toMatchObject({ + pieceCid: 'baga-partial', + requestedCopies: 3, + complete: false, + copyResults: [ + { + dataSetId: '42', + pieceId: '7', + providerId: '77', + providerRole: 'primary', + }, ], copyFailures: [ {