diff --git a/src/arfs/arfs_builders/arfs_file_builders.test.ts b/src/arfs/arfs_builders/arfs_file_builders.test.ts index 1ffd40d6..068f89dd 100644 --- a/src/arfs/arfs_builders/arfs_file_builders.test.ts +++ b/src/arfs/arfs_builders/arfs_file_builders.test.ts @@ -1,11 +1,14 @@ import { expect } from 'chai'; import { stub } from 'sinon'; -import { fakeArweave, stubTxID } from '../../../tests/stubs'; +import { fakeArweave, stubTxID, stubTxIDAlt } from '../../../tests/stubs'; import { expectAsyncErrorThrow } from '../../../tests/test_helpers'; -import { EntityKey, GQLNodeInterface } from '../../types'; +import { EID, EntityKey, GQLNodeInterface } from '../../types'; import { gatewayUrlForArweave } from '../../utils/common'; import { GatewayAPI } from '../../utils/gateway_api'; import { ArFSPrivateFileBuilder, ArFSPublicFileBuilder } from './arfs_file_builders'; +import { ArFSDAOAnonymous } from '../arfsdao_anonymous'; +import { ADDR, DriveID, FolderID } from '../../types'; +import { stub, SinonStub } from 'sinon'; const gatewayApi = new GatewayAPI({ gatewayUrl: gatewayUrlForArweave(fakeArweave), diff --git a/src/arfs/arfsdao_anonymous.test.ts b/src/arfs/arfsdao_anonymous.test.ts index 1cc94ba9..4c6b1f62 100644 --- a/src/arfs/arfsdao_anonymous.test.ts +++ b/src/arfs/arfsdao_anonymous.test.ts @@ -1,15 +1,19 @@ +/* eslint-disable prettier/prettier */ import Arweave from 'arweave'; import { expect } from 'chai'; -import { stub } from 'sinon'; +import { stub, SinonStub } from 'sinon'; import { stubArweaveAddress, stubEntityID, stubEntityIDAlt, stubPublicDrive, stubPublicFile, - stubPublicFolder + stubPublicFolder, + stubTxID, + stubTxIDAlt, + stubTxIDAltTwo } from '../../tests/stubs'; -import { ArweaveAddress, DriveID, EntityID } from '../types'; +import { ADDR, ArweaveAddress, DriveID, EID, EntityID } from '../types'; import { ArFSAnonymousCache, ArFSDAOAnonymous, @@ -19,6 +23,7 @@ import { } from './arfsdao_anonymous'; import { ArFSPublicDrive, ArFSPublicFile, ArFSPublicFolder } from './arfs_entities'; import { ArFSEntityCache } from './arfs_entity_cache'; +import { ArFSPublicFileBuilder } from './arfs_builders/arfs_file_builders'; const fakeArweave = Arweave.init({ host: 'localhost', @@ -226,4 +231,280 @@ describe('ArFSDAOAnonymous class', () => { // }); }); }); + + describe('getPublicFilesWithParentFolderIds', () => { + let dao: ArFSDAOAnonymous; + let gqlRequestStub: SinonStub; + let ArFSPublicFileBuilderStub: SinonStub; + + beforeEach(() => { + dao = new ArFSDAOAnonymous(fakeArweave); + gqlRequestStub = stub(dao['gatewayApi'], 'gqlRequest'); + ArFSPublicFileBuilderStub = stub(ArFSPublicFileBuilder.prototype, 'getDataForTxID'); + }); + + afterEach(() => { + gqlRequestStub.restore(); + ArFSPublicFileBuilderStub.restore(); + }); + + it('returns expected files for given folder IDs', async () => { + // Mock GQL response + const mockGQLResponse = { + edges: [ + { + cursor: 'cursor1', + node: { + id: `${stubTxID}`, + tags: [ + { name: 'App-Name', value: 'ArDrive-CLI' }, + { name: 'App-Version', value: '1.2.0' }, + { name: 'ArFS', value: '0.11' }, + { name: 'Content-Type', value: 'application/json' }, + { name: 'Drive-Id', value: 'e93cf9c4-5f20-4d7a-87c4-034777cbb51e' }, + { name: 'Entity-Type', value: 'file' }, + { name: 'Unix-Time', value: '1639073846' }, + { name: 'Parent-Folder-Id', value: '6c312b3e-4778-4a18-8243-f2b346f5e7cb' }, + { name: 'File-Id', value: '9f7038c7-26bd-4856-a843-8de24b828d4e' } + ], + owner: { address: 'vh-NTHVvlKZqRxc8LyyTNok65yQ55a_PJ1zWLb9G2JI' } + } + } + ], + pageInfo: { + hasNextPage: false + } + }; + + gqlRequestStub.resolves(mockGQLResponse); + + // Add stub for getDataForTxID + const stubFileGetDataResult = Buffer.from( + JSON.stringify({ + name: '2', + size: 2048, + lastModifiedDate: 1639073634269, + dataTxId: 'yAogaGWWYgWO5xWZevb45Y7YRp7E9iDsvkJvfR7To9c', + dataContentType: 'unknown' + }) + ); + + // Stub the getDataForTxID method on the builder + ArFSPublicFileBuilderStub.resolves(stubFileGetDataResult); + + const folderIds = [EID('6c312b3e-4778-4a18-8243-f2b346f5e7cb')]; + const owner = ADDR('vh-NTHVvlKZqRxc8LyyTNok65yQ55a_PJ1zWLb9G2JI'); + const driveId = EID('e93cf9c4-5f20-4d7a-87c4-034777cbb51e'); + + const files = await dao.getPublicFilesWithParentFolderIds(folderIds, owner, driveId, true); + + expect(files).to.have.lengthOf(1); + expect(`${files[0].fileId}`).to.equal('9f7038c7-26bd-4856-a843-8de24b828d4e'); + expect(`${files[0].driveId}`).to.equal('e93cf9c4-5f20-4d7a-87c4-034777cbb51e'); + expect(`${files[0].parentFolderId}`).to.equal('6c312b3e-4778-4a18-8243-f2b346f5e7cb'); + }); + + it('handles pagination correctly', async () => { + const fileId1 = '9f7038c7-26bd-4856-a843-8de24b828d4e'; + const fileId2 = '1f7038c7-26bd-4856-a843-8de24b828d4e'; + + // Mock two pages of GQL responses + const mockGQLResponse1 = { + edges: [ + { + cursor: 'cursor1', + node: { + id: `${stubTxID}`, + tags: [ + { name: 'App-Name', value: 'ArDrive-CLI' }, + { name: 'App-Version', value: '1.2.0' }, + { name: 'ArFS', value: '0.11' }, + { name: 'Content-Type', value: 'application/json' }, + { name: 'Drive-Id', value: 'e93cf9c4-5f20-4d7a-87c4-034777cbb51e' }, + { name: 'Entity-Type', value: 'file' }, + { name: 'Unix-Time', value: '1639073846' }, + { name: 'Parent-Folder-Id', value: '6c312b3e-4778-4a18-8243-f2b346f5e7cb' }, + { name: 'File-Id', value: fileId1 } + ], + owner: { address: 'vh-NTHVvlKZqRxc8LyyTNok65yQ55a_PJ1zWLb9G2JI' } + } + } + ], + pageInfo: { + hasNextPage: true + } + }; + + const mockGQLResponse2 = { + edges: [ + { + cursor: 'cursor2', + node: { + id: `${stubTxIDAlt}`, + tags: [ + { name: 'App-Name', value: 'ArDrive-CLI' }, + { name: 'App-Version', value: '1.2.0' }, + { name: 'ArFS', value: '0.11' }, + { name: 'Content-Type', value: 'application/json' }, + { name: 'Drive-Id', value: 'e93cf9c4-5f20-4d7a-87c4-034777cbb51e' }, + { name: 'Entity-Type', value: 'file' }, + { name: 'Unix-Time', value: '1639073846' }, + { name: 'Parent-Folder-Id', value: '6c312b3e-4778-4a18-8243-f2b346f5e7cb' }, + { name: 'File-Id', value: fileId2 } + ], + owner: { address: 'vh-NTHVvlKZqRxc8LyyTNok65yQ55a_PJ1zWLb9G2JI' } + } + } + ], + pageInfo: { + hasNextPage: false + } + }; + + gqlRequestStub.onFirstCall().resolves(mockGQLResponse1); + gqlRequestStub.onSecondCall().resolves(mockGQLResponse2); + + const folderIds = [EID('6c312b3e-4778-4a18-8243-f2b346f5e7cb')]; + const owner = ADDR('vh-NTHVvlKZqRxc8LyyTNok65yQ55a_PJ1zWLb9G2JI'); + const driveId = EID('e93cf9c4-5f20-4d7a-87c4-034777cbb51e'); + + // Add stub for getDataForTxID + const stubFileGetDataResult = Buffer.from( + JSON.stringify({ + name: '2', + size: 2048, + lastModifiedDate: 1639073634269, + dataTxId: 'yAogaGWWYgWO5xWZevb45Y7YRp7E9iDsvkJvfR7To9c', + dataContentType: 'unknown' + }) + ); + + ArFSPublicFileBuilderStub.withArgs(stubTxID).resolves(stubFileGetDataResult); + ArFSPublicFileBuilderStub.withArgs(stubTxIDAlt).resolves(stubFileGetDataResult); + + const files = await dao.getPublicFilesWithParentFolderIds(folderIds, owner, driveId, true); + + expect(files).to.have.lengthOf(2); + expect(`${files[0].fileId}`).to.equal(fileId1); + expect(`${files[1].fileId}`).to.equal(fileId2); + expect(gqlRequestStub.callCount).to.equal(2); + }); + + it('skips invalid files and continues processing', async () => { + const fileId1 = '9f7038c7-26bd-4856-a843-8de24b828d4e'; + const fileId2 = '1f7038c7-26bd-4856-a843-8de24b828d4e'; + const fileId3 = '2f7038c7-26bd-4856-a843-8de24b828d4e'; + + const mockGQLResponse = { + edges: [ + { + cursor: 'cursor1', + node: { + id: `${stubTxID}`, + tags: [ + { name: 'App-Name', value: 'ArDrive-CLI' }, + { name: 'App-Version', value: '1.2.0' }, + { name: 'ArFS', value: '0.11' }, + { name: 'Content-Type', value: 'application/json' }, + { name: 'Drive-Id', value: 'e93cf9c4-5f20-4d7a-87c4-034777cbb51e' }, + { name: 'Entity-Type', value: 'file' }, + { name: 'Unix-Time', value: '1639073846' }, + { name: 'Parent-Folder-Id', value: '6c312b3e-4778-4a18-8243-f2b346f5e7cb' }, + { name: 'File-Id', value: fileId1 } + ], + owner: { address: 'vh-NTHVvlKZqRxc8LyyTNok65yQ55a_PJ1zWLb9G2JI' } + } + }, + { + cursor: 'cursor2', + node: { + id: `${stubTxIDAlt}`, + tags: [ + { name: 'App-Name', value: 'ArDrive-CLI' }, + { name: 'App-Version', value: '1.2.0' }, + { name: 'ArFS', value: '0.11' }, + { name: 'Content-Type', value: 'application/json' }, + { name: 'Drive-Id', value: 'e93cf9c4-5f20-4d7a-87c4-034777cbb51e' }, + { name: 'Entity-Type', value: 'file' }, + { name: 'Unix-Time', value: '1639073846' }, + { name: 'Parent-Folder-Id', value: '1c312b3e-4778-4a18-8243-f2b346f5e7cb' }, + { name: 'File-Id', value: fileId2 } + ], + owner: { address: 'vh-NTHVvlKZqRxc8LyyTNok65yQ55a_PJ1zWLb9G2JI' } + } + }, + { + cursor: 'cursor3', + node: { + id: `${stubTxIDAltTwo}`, + tags: [ + { name: 'App-Name', value: 'ArDrive-CLI' }, + { name: 'App-Version', value: '1.2.0' }, + { name: 'ArFS', value: '0.11' }, + { name: 'Content-Type', value: 'application/json' }, + { name: 'Drive-Id', value: 'e93cf9c4-5f20-4d7a-87c4-034777cbb51e' }, + { name: 'Entity-Type', value: 'file' }, + { name: 'Unix-Time', value: '1639073846' }, + { name: 'Parent-Folder-Id', value: '1c312b3e-4778-4a18-8243-f2b346f5e7cb' }, + { name: 'File-Id', value: fileId3 } + ], + owner: { address: 'vh-NTHVvlKZqRxc8LyyTNok65yQ55a_PJ1zWLb9G2JI' } + } + } + ], + pageInfo: { + hasNextPage: false + } + }; + gqlRequestStub.resolves(mockGQLResponse); + // Mock the getDataForTxID method to return valid metadata for the second file + const stubFileGetDataResultValid1 = Buffer.from( + JSON.stringify({ + name: '2', + size: 2048, + lastModifiedDate: 1639073634269, + dataTxId: 'yAogaGWWYgWO5xWZevb45Y7YRp7E9iDsvkJvfR7To9c', + dataContentType: 'application/json' + }) + ); + // Invalid file metadata missing dataContentType + const stubFileGetDataResultWithEmptyContentType = Buffer.from( + JSON.stringify({ + name: '2', + size: 2048, + lastModifiedDate: 1639073634269, + dataTxId: 'yAogaGWWYgWO5xWZevb45Y7YRp7E9iDsvkJvfR7To9c', + dataContentType: '' + }) + ); + // Valid file metadata + const stubFileGetDataResultValid2 = Buffer.from( + JSON.stringify({ + name: '2', + size: 2048, + lastModifiedDate: 1639073634269, + dataTxId: 'yAogaGWWYgWO5xWZevb45Y7YRp7E9iDsvkJvfR7To9c', + dataContentType: 'text/plain' + }) + ); + + // Valid file metadata + ArFSPublicFileBuilderStub.withArgs(stubTxID).resolves(stubFileGetDataResultValid1); + // Invalid file metadata missing dataContentType + ArFSPublicFileBuilderStub.withArgs(stubTxIDAlt).resolves(stubFileGetDataResultWithEmptyContentType); + // Valid file metadata + ArFSPublicFileBuilderStub.withArgs(stubTxIDAltTwo).resolves(stubFileGetDataResultValid2); + + const folderIds = [EID('6c312b3e-4778-4a18-8243-f2b346f5e7cb')]; + const owner = ADDR('vh-NTHVvlKZqRxc8LyyTNok65yQ55a_PJ1zWLb9G2JI'); + const driveId = EID('e93cf9c4-5f20-4d7a-87c4-034777cbb51e'); + + const files = await dao.getPublicFilesWithParentFolderIds(folderIds, owner, driveId, true); + + // Verify that the invalid file was skipped + expect(files).to.have.lengthOf(2); + expect(`${files[0].fileId}`).to.equal(fileId1); + expect(`${files[1].fileId}`).to.equal(fileId3); + }); + }); });