diff --git a/src/gridfs/download.ts b/src/gridfs/download.ts index 6b0fc57fc6..7d2a7b2ee3 100644 --- a/src/gridfs/download.ts +++ b/src/gridfs/download.ts @@ -56,15 +56,41 @@ export interface GridFSFile { /** @internal */ export interface GridFSBucketReadStreamPrivate { + /** + * The running total number of bytes read from the chunks collection. + */ bytesRead: number; + /** + * The number of bytes to remove from the last chunk read in the file. This is non-zero + * if `end` is not equal to the length of the document and `end` is not a multiple + * of the chunkSize. + */ bytesToTrim: number; + + /** + * The number of bytes to remove from the first chunk read in the file. This is non-zero + * if `start` is not equal to the 0 and `start` is not a multiple + * of the chunkSize. + */ bytesToSkip: number; + + files: Collection; chunks: Collection; cursor?: FindCursor; + + /** The running total number of chunks read from the chunks collection. */ expected: number; - files: Collection; + + /** + * The filter used to search in the _files_ collection (i.e., `{ _id: <> }`) + * This is not the same filter used when reading chunks from the chunks collection. + */ filter: Document; + + /** Indicates whether or not download has started. */ init: boolean; + + /** The expected number of chunks to read, calculated from start, end, chunkSize and file length. */ expectedEnd: number; file?: GridFSFile; options: { diff --git a/test/integration/gridfs/gridfs.spec.test.js b/test/integration/gridfs/gridfs.spec.test.js deleted file mode 100644 index 6bde9ff6e5..0000000000 --- a/test/integration/gridfs/gridfs.spec.test.js +++ /dev/null @@ -1,235 +0,0 @@ -'use strict'; - -const { EJSON } = require('bson'); -const { expect } = require('chai'); -const { once } = require('node:events'); -const { GridFSBucket } = require('../../mongodb'); - -describe('GridFS spec', function () { - let client; - let db; - - beforeEach(async function () { - client = this.configuration.newClient(); - db = client.db('gridfs_spec_tests'); - }); - - afterEach(async function () { - await db.dropDatabase().catch(() => null); - await client.close(); - }); - - const UPLOAD_SPEC = require('../../spec/gridfs/gridfs-upload.json'); - - for (const testSpec of UPLOAD_SPEC.tests) { - it(testSpec.description, async function () { - const bucket = new GridFSBucket(db, { bucketName: 'expected' }); - - const uploadStream = bucket.openUploadStream( - testSpec.act.arguments.filename, - testSpec.act.arguments.options - ); - - const buf = Buffer.from(testSpec.act.arguments.source.$hex, 'hex'); - - const finished = once(uploadStream, 'finish'); - - uploadStream.write(buf); - uploadStream.end(); - - await finished; - - for (const data of testSpec.assert.data) { - const docs = await db.collection(data.insert).find({}).toArray(); - - expect(data.documents.length).to.equal(docs.length); - for (let i = 0; i < docs.length; ++i) { - testResultDoc(data.documents[i], docs[i], uploadStream.id); - } - } - }); - } - - const DOWNLOAD_SPEC = require('../../spec/gridfs/gridfs-download.json'); - DOWNLOAD_SPEC.tests.forEach(function (specTest) { - (function (testSpec) { - it(testSpec.description, { - metadata: { requires: { topology: ['single'] } }, - - test(done) { - const configuration = this.configuration; - const client = configuration.newClient(configuration.writeConcernMax(), { - maxPoolSize: 1 - }); - client.connect(function (err, client) { - const db = client.db(configuration.db); - db.dropDatabase(function (err) { - expect(err).to.not.exist; - const BUCKET_NAME = 'fs'; - - const _runTest = function () { - const bucket = new GridFSBucket(db, { bucketName: BUCKET_NAME }); - let res = Buffer.alloc(0); - - const download = bucket.openDownloadStream( - EJSON.parse(JSON.stringify(testSpec.act.arguments.id), { relaxed: true }) - ); - - download.on('data', function (chunk) { - res = Buffer.concat([res, chunk]); - }); - - let errorReported = false; - download.on('error', function (error) { - errorReported = true; - if (!testSpec.assert.error) { - expect.fail('Should be unreached'); - - // We need to abort in order to close the underlying cursor, - // and by extension the implicit session used for the cursor. - // This is only necessary if the cursor is not exhausted - download.abort(); - client.close(done); - } - expect(error.toString().indexOf(testSpec.assert.error) !== -1).to.equal(true); - - // We need to abort in order to close the underlying cursor, - // and by extension the implicit session used for the cursor. - // This is only necessary if the cursor is not exhausted - download.abort(); - client.close(done); - }); - - download.on('end', function () { - const result = testSpec.assert.result; - if (!result) { - if (errorReported) { - return; - } - - // We need to abort in order to close the underlying cursor, - // and by extension the implicit session used for the cursor. - // This is only necessary if the cursor is not exhausted - download.abort(); - client.close(done); - expect.fail('errorReported should be set'); - } - - expect(res.toString('hex')).to.equal(result.$hex); - - // We need to abort in order to close the underlying cursor, - // and by extension the implicit session used for the cursor. - // This is only necessary if the cursor is not exhausted - download.abort(); - client.close(done); - }); - }; - - const keys = Object.keys(DOWNLOAD_SPEC.data); - let numCollections = Object.keys(DOWNLOAD_SPEC.data).length; - keys.forEach(function (collection) { - const data = DOWNLOAD_SPEC.data[collection].map(function (v) { - return deflateTestDoc(v); - }); - - db.collection(BUCKET_NAME + '.' + collection).insertMany(data, function (error) { - expect(error).to.not.exist; - - if (--numCollections === 0) { - if (testSpec.arrange) { - // only support 1 arrange op for now - expect(testSpec.arrange.data.length).to.equal(1); - applyArrange(db, deflateTestDoc(testSpec.arrange.data[0]), function (error) { - expect(error).to.not.exist; - _runTest(); - }); - } else { - _runTest(); - } - } - }); - }); - }); - }); - } - }); - })(specTest); - }); - - function testResultDoc(specDoc, resDoc, result) { - const specKeys = Object.keys(specDoc) - .filter(key => key !== 'md5') - .sort(); - const resKeys = Object.keys(resDoc).sort(); - - expect(specKeys.length === resKeys.length).to.equal(true); - - for (let i = 0; i < specKeys.length; ++i) { - const key = specKeys[i]; - expect(specKeys[i]).to.equal(resKeys[i]); - if (specDoc[key] === '*actual') { - expect(resDoc[key]).to.exist; - } else if (specDoc[key] === '*result') { - expect(resDoc[key].toString()).to.equal(result.toString()); - } else if (specDoc[key].$hex) { - expect(resDoc[key]._bsontype === 'Binary').to.equal(true); - expect(resDoc[key].toString('hex')).to.equal(specDoc[key].$hex); - } else { - if (typeof specDoc[key] === 'object') { - expect(specDoc[key]).to.deep.equal(resDoc[key]); - } else { - expect(specDoc[key]).to.equal(resDoc[key]); - } - } - } - } - - function deflateTestDoc(doc) { - const ret = EJSON.parse(JSON.stringify(doc), { relaxed: true }); - convert$hexToBuffer(ret); - return ret; - } - - function convert$hexToBuffer(doc) { - const keys = Object.keys(doc); - keys.forEach(function (key) { - if (doc[key] && typeof doc[key] === 'object') { - if (doc[key].$hex != null) { - doc[key] = Buffer.from(doc[key].$hex, 'hex'); - } else { - convert$hexToBuffer(doc[key]); - } - } - }); - } - - function applyArrange(db, command, callback) { - // Don't count on commands being there since we need to test on 2.2 and 2.4 - if (command.delete) { - if (command.deletes.length !== 1) { - return callback(new Error('can only arrange with 1 delete')); - } - if (command.deletes[0].limit !== 1) { - return callback(new Error('can only arrange with delete limit 1')); - } - db.collection(command.delete).deleteOne(command.deletes[0].q, callback); - } else if (command.insert) { - db.collection(command.insert).insertMany(command.documents, callback); - } else if (command.update) { - const bulk = []; - for (let i = 0; i < command.updates.length; ++i) { - bulk.push({ - updateOne: { - filter: command.updates[i].q, - update: command.updates[i].u - } - }); - } - - db.collection(command.update).bulkWrite(bulk, callback); - } else { - const msg = 'Command not recognized: ' + require('util').inspect(command); - callback(new Error(msg)); - } - } -}); diff --git a/test/integration/gridfs/gridfs.spec.test.ts b/test/integration/gridfs/gridfs.spec.test.ts new file mode 100644 index 0000000000..ba849713f3 --- /dev/null +++ b/test/integration/gridfs/gridfs.spec.test.ts @@ -0,0 +1,8 @@ +import { loadSpecTests } from '../../spec'; +import { runUnifiedSuite } from '../../tools/unified-spec-runner/runner'; + +describe('GridFS Unified Tests', function () { + runUnifiedSuite(loadSpecTests('gridfs'), ({ description }) => { + return description === 'download when final chunk is missing' ? `TODO(NODE-6279): throw a missing chunk error when last chunk is missing` : false; + }); +}); diff --git a/test/spec/gridfs/README.md b/test/spec/gridfs/README.md new file mode 100644 index 0000000000..8285b2e306 --- /dev/null +++ b/test/spec/gridfs/README.md @@ -0,0 +1,28 @@ +# GridFS Tests + +______________________________________________________________________ + +## Introduction + +The YAML and JSON files in this directory are platform-independent tests meant to exercise a driver's implementation of +GridFS. These tests utilize the [Unified Test Format](../../unified-test-format/unified-test-format.md). + +## Conventions for Expressing Binary Data + +The unified test format allows binary stream data to be expressed and matched with `$$hexBytes` (for uploads) and +`$$matchesHexBytes` (for downloads), respectively; however, those operators are not supported in all contexts, such as +`insertData` and `outcome`. When binary data must be expressed as a base64-encoded string +([Extended JSON](../../extended-json.md) for a BSON binary type), the test SHOULD include a comment noting the +equivalent value in hexadecimal for human-readability. For example: + +```yaml +data: { $binary: { base64: "ESIzRA==", subType: "00" } } # hex 11223344 +``` + +Creating the base64-encoded string for a sequence of hexadecimal bytes is left as an exercise to the developer. Consider +the following PHP one-liner: + +```shell-session +$ php -r 'echo base64_encode(hex2bin('11223344')), "\n";' +ESIzRA== +``` diff --git a/test/spec/gridfs/delete.json b/test/spec/gridfs/delete.json new file mode 100644 index 0000000000..7a4ec27f88 --- /dev/null +++ b/test/spec/gridfs/delete.json @@ -0,0 +1,799 @@ +{ + "description": "gridfs-delete", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "gridfs-tests" + } + }, + { + "bucket": { + "id": "bucket0", + "database": "database0" + } + }, + { + "collection": { + "id": "bucket0_files_collection", + "database": "database0", + "collectionName": "fs.files" + } + }, + { + "collection": { + "id": "bucket0_chunks_collection", + "database": "database0", + "collectionName": "fs.chunks" + } + } + ], + "initialData": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "dd254cdc958e53abaa67da9f797125f5", + "filename": "length-8", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + } + ] + } + ], + "tests": [ + { + "description": "delete when length is 0", + "operations": [ + { + "name": "delete", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000001" + } + } + } + ], + "outcome": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "dd254cdc958e53abaa67da9f797125f5", + "filename": "length-8", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "delete when length is 0 and there is one extra empty chunk", + "operations": [ + { + "name": "delete", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000002" + } + } + } + ], + "outcome": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "dd254cdc958e53abaa67da9f797125f5", + "filename": "length-8", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "delete when length is 8", + "operations": [ + { + "name": "delete", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000004" + } + } + } + ], + "outcome": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "delete when files entry does not exist", + "operations": [ + { + "name": "delete", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000000" + } + }, + "expectError": { + "isError": true + } + } + ], + "outcome": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "dd254cdc958e53abaa67da9f797125f5", + "filename": "length-8", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "delete when files entry does not exist and there are orphaned chunks", + "operations": [ + { + "name": "deleteOne", + "object": "bucket0_files_collection", + "arguments": { + "filter": { + "_id": { + "$oid": "000000000000000000000004" + } + } + }, + "expectResult": { + "deletedCount": 1 + } + }, + { + "name": "delete", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000004" + } + }, + "expectError": { + "isError": true + } + } + ], + "outcome": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + } + ] + } + ] + } + ] +} diff --git a/test/spec/gridfs/delete.yml b/test/spec/gridfs/delete.yml new file mode 100644 index 0000000000..b300cad1bc --- /dev/null +++ b/test/spec/gridfs/delete.yml @@ -0,0 +1,198 @@ +description: "gridfs-delete" + +schemaVersion: "1.0" + +createEntities: + - client: + id: &client0 client0 + - database: + id: &database0 database0 + client: *client0 + databaseName: &database0Name gridfs-tests + - bucket: + id: &bucket0 bucket0 + database: *database0 + - collection: + id: &bucket0_files_collection bucket0_files_collection + database: *database0 + collectionName: &bucket0_files_collectionName fs.files + - collection: + id: &bucket0_chunks_collection bucket0_chunks_collection + database: *database0 + collectionName: &bucket0_chunks_collectionName fs.chunks + +initialData: + - collectionName: *bucket0_files_collectionName + databaseName: *database0Name + documents: + - &file1 + _id: { "$oid": "000000000000000000000001" } + length: 0 + chunkSize: 4 + uploadDate: { "$date": "1970-01-01T00:00:00.000Z" } + md5: "d41d8cd98f00b204e9800998ecf8427e" + filename: "length-0" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - &file2 + _id: { "$oid": "000000000000000000000002" } + length: 0 + chunkSize: 4 + uploadDate: { "$date": "1970-01-01T00:00:00.000Z" } + md5: "d41d8cd98f00b204e9800998ecf8427e" + filename: "length-0-with-empty-chunk" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - &file3 + _id: { "$oid": "000000000000000000000003" } + length: 2 + chunkSize: 4 + uploadDate: { "$date": "1970-01-01T00:00:00.000Z" } + md5: "c700ed4fdb1d27055aa3faa2c2432283" + filename: "length-2" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - &file4 + _id: { "$oid": "000000000000000000000004" } + length: 8 + chunkSize: 4 + uploadDate: { "$date": "1970-01-01T00:00:00.000Z" } + md5: "dd254cdc958e53abaa67da9f797125f5" + filename: "length-8" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - collectionName: *bucket0_chunks_collectionName + databaseName: *database0Name + documents: + - &file2_chunk0 + _id: { "$oid": "000000000000000000000001" } + files_id: { "$oid": "000000000000000000000002" } + n: 0 + data: { "$binary": { "base64": "", "subType": "00" } } + - &file3_chunk0 + _id: { "$oid": "000000000000000000000002" } + files_id: { "$oid": "000000000000000000000003" } + n: 0 + data: { "$binary": { "base64": "ESI=", "subType": "00" } } # hex: 1122 + - &file4_chunk0 + _id: { "$oid": "000000000000000000000003" } + files_id: { "$oid": "000000000000000000000004" } + n: 0 + data: { "$binary": { "base64": "ESIzRA==", "subType": "00" } } # hex: 11223344 + - &file4_chunk1 + _id: { "$oid": "000000000000000000000004" } + files_id: { "$oid": "000000000000000000000004" } + n: 1 + data: { "$binary": { "base64": "VWZ3iA==", "subType": "00" } } # hex: 55667788 + +tests: + - description: "delete when length is 0" + operations: + - name: delete + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000001" } + outcome: + - collectionName: *bucket0_files_collectionName + databaseName: *database0Name + documents: + - *file2 + - *file3 + - *file4 + - collectionName: *bucket0_chunks_collectionName + databaseName: *database0Name + documents: + - *file2_chunk0 + - *file3_chunk0 + - *file4_chunk0 + - *file4_chunk1 + - description: "delete when length is 0 and there is one extra empty chunk" + operations: + - name: delete + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000002" } + outcome: + - collectionName: *bucket0_files_collectionName + databaseName: *database0Name + documents: + - *file1 + - *file3 + - *file4 + - collectionName: *bucket0_chunks_collectionName + databaseName: *database0Name + documents: + - *file3_chunk0 + - *file4_chunk0 + - *file4_chunk1 + - description: "delete when length is 8" + operations: + - name: delete + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000004" } + outcome: + - collectionName: *bucket0_files_collectionName + databaseName: *database0Name + documents: + - *file1 + - *file2 + - *file3 + - collectionName: *bucket0_chunks_collectionName + databaseName: *database0Name + documents: + - *file2_chunk0 + - *file3_chunk0 + - description: "delete when files entry does not exist" + operations: + - name: delete + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000000" } + expectError: { isError: true } # FileNotFound + outcome: + - collectionName: *bucket0_files_collectionName + databaseName: *database0Name + documents: + - *file1 + - *file2 + - *file3 + - *file4 + - collectionName: *bucket0_chunks_collectionName + databaseName: *database0Name + documents: + - *file2_chunk0 + - *file3_chunk0 + - *file4_chunk0 + - *file4_chunk1 + - description: "delete when files entry does not exist and there are orphaned chunks" + operations: + - name: deleteOne + object: *bucket0_files_collection + arguments: + filter: + _id: { $oid: "000000000000000000000004" } + expectResult: + deletedCount: 1 + - name: delete + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000004" } + expectError: { isError: true } # FileNotFound + outcome: + - collectionName: *bucket0_files_collectionName + databaseName: *database0Name + documents: + - *file1 + - *file2 + - *file3 + # Orphaned chunks are still deleted even if fs.files + - collectionName: *bucket0_chunks_collectionName + databaseName: *database0Name + documents: + - *file2_chunk0 + - *file3_chunk0 diff --git a/test/spec/gridfs/download.json b/test/spec/gridfs/download.json new file mode 100644 index 0000000000..48d3246218 --- /dev/null +++ b/test/spec/gridfs/download.json @@ -0,0 +1,558 @@ +{ + "description": "gridfs-download", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "gridfs-tests" + } + }, + { + "bucket": { + "id": "bucket0", + "database": "database0" + } + }, + { + "collection": { + "id": "bucket0_files_collection", + "database": "database0", + "collectionName": "fs.files" + } + }, + { + "collection": { + "id": "bucket0_chunks_collection", + "database": "database0", + "collectionName": "fs.chunks" + } + } + ], + "initialData": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "dd254cdc958e53abaa67da9f797125f5", + "filename": "length-8", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000005" + }, + "length": 10, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "57d83cd477bfb1ccd975ab33d827a92b", + "filename": "length-10", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000006" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000005" + }, + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000006" + }, + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000007" + }, + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 2, + "data": { + "$binary": { + "base64": "mao=", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000008" + }, + "files_id": { + "$oid": "000000000000000000000006" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + } + ] + } + ], + "tests": [ + { + "description": "download when length is zero", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000001" + } + }, + "expectResult": { + "$$matchesHexBytes": "" + } + } + ] + }, + { + "description": "download when length is zero and there is one empty chunk", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000002" + } + }, + "expectResult": { + "$$matchesHexBytes": "" + } + } + ] + }, + { + "description": "download when there is one chunk", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000003" + } + }, + "expectResult": { + "$$matchesHexBytes": "1122" + } + } + ] + }, + { + "description": "download when there are two chunks", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000004" + } + }, + "expectResult": { + "$$matchesHexBytes": "1122334455667788" + } + } + ] + }, + { + "description": "download when there are three chunks", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + }, + "expectResult": { + "$$matchesHexBytes": "112233445566778899aa" + } + } + ] + }, + { + "description": "download when files entry does not exist", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000000" + } + }, + "expectError": { + "isError": true + } + } + ] + }, + { + "description": "download when an intermediate chunk is missing", + "operations": [ + { + "name": "deleteOne", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 1 + } + }, + "expectResult": { + "deletedCount": 1 + } + }, + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + }, + "expectError": { + "isError": true + } + } + ] + }, + { + "description": "download when final chunk is missing", + "operations": [ + { + "name": "deleteOne", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 2 + } + }, + "expectResult": { + "deletedCount": 1 + } + }, + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + }, + "expectError": { + "isError": true + } + } + ] + }, + { + "description": "download when an intermediate chunk is the wrong size", + "operations": [ + { + "name": "bulkWrite", + "object": "bucket0_chunks_collection", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 1 + }, + "update": { + "$set": { + "data": { + "$binary": { + "base64": "VWZ3", + "subType": "00" + } + } + } + } + } + }, + { + "updateOne": { + "filter": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 2 + }, + "update": { + "$set": { + "data": { + "$binary": { + "base64": "iJmq", + "subType": "00" + } + } + } + } + } + } + ] + }, + "expectResult": { + "matchedCount": 2, + "modifiedCount": 2 + } + }, + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + }, + "expectError": { + "isError": true + } + } + ] + }, + { + "description": "download when final chunk is the wrong size", + "operations": [ + { + "name": "updateOne", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 2 + }, + "update": { + "$set": { + "data": { + "$binary": { + "base64": "mQ==", + "subType": "00" + } + } + } + } + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1 + } + }, + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + }, + "expectError": { + "isError": true + } + } + ] + }, + { + "description": "download legacy file with no name", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000006" + } + }, + "expectResult": { + "$$matchesHexBytes": "1122" + } + } + ] + } + ] +} diff --git a/test/spec/gridfs/download.yml b/test/spec/gridfs/download.yml new file mode 100644 index 0000000000..3da5ee950f --- /dev/null +++ b/test/spec/gridfs/download.yml @@ -0,0 +1,241 @@ +description: "gridfs-download" + +schemaVersion: "1.0" + +createEntities: + - client: + id: &client0 client0 + - database: + id: &database0 database0 + client: *client0 + databaseName: &database0Name gridfs-tests + - bucket: + id: &bucket0 bucket0 + database: *database0 + - collection: + id: &bucket0_files_collection bucket0_files_collection + database: *database0 + collectionName: &bucket0_files_collectionName fs.files + - collection: + id: &bucket0_chunks_collection bucket0_chunks_collection + database: *database0 + collectionName: &bucket0_chunks_collectionName fs.chunks + +initialData: + - collectionName: *bucket0_files_collectionName + databaseName: *database0Name + documents: + - _id: { "$oid": "000000000000000000000001" } + length: 0 + chunkSize: 4 + uploadDate: { "$date": "1970-01-01T00:00:00.000Z" } + md5: "d41d8cd98f00b204e9800998ecf8427e" + filename: "length-0" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - _id: { "$oid": "000000000000000000000002" } + length: 0 + chunkSize: 4 + uploadDate: { "$date": "1970-01-01T00:00:00.000Z" } + md5: "d41d8cd98f00b204e9800998ecf8427e" + filename: "length-0-with-empty-chunk" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - _id: { "$oid": "000000000000000000000003" } + length: 2 + chunkSize: 4 + uploadDate: { "$date": "1970-01-01T00:00:00.000Z" } + md5: "c700ed4fdb1d27055aa3faa2c2432283" + filename: "length-2" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - _id: { "$oid": "000000000000000000000004" } + length: 8 + chunkSize: 4 + uploadDate: { "$date": "1970-01-01T00:00:00.000Z" } + md5: "dd254cdc958e53abaa67da9f797125f5" + filename: "length-8" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - _id: { "$oid": "000000000000000000000005" } + length: 10 + chunkSize: 4 + uploadDate: { "$date": "1970-01-01T00:00:00.000Z" } + md5: "57d83cd477bfb1ccd975ab33d827a92b" + filename: "length-10" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - _id: { "$oid": "000000000000000000000006" } + length: 2 + chunkSize: 4 + uploadDate: { "$date": "1970-01-01T00:00:00.000Z" } + md5: "c700ed4fdb1d27055aa3faa2c2432283" + # filename is intentionally omitted + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - collectionName: *bucket0_chunks_collectionName + databaseName: *database0Name + documents: + - _id: { "$oid": "000000000000000000000001" } + files_id: { "$oid": "000000000000000000000002" } + n: 0 + data: { "$binary": { "base64": "", "subType": "00" } } + - _id: { "$oid": "000000000000000000000002" } + files_id: { "$oid": "000000000000000000000003" } + n: 0 + data: { "$binary": { "base64": "ESI=", "subType": "00" } } # hex: 1122 + - _id: { "$oid": "000000000000000000000003" } + files_id: { "$oid": "000000000000000000000004" } + n: 0 + data: { "$binary": { "base64": "ESIzRA==", "subType": "00" } } # hex: 11223344 + - _id: { "$oid": "000000000000000000000004" } + files_id: { "$oid": "000000000000000000000004" } + n: 1 + data: { "$binary": { "base64": "VWZ3iA==", "subType": "00" } } # hex: 55667788 + - _id: { "$oid": "000000000000000000000005" } + files_id: { "$oid": "000000000000000000000005" } + n: 0 + data: { "$binary": { "base64": "ESIzRA==", "subType": "00" } } # hex: 11223344 + - _id: { "$oid": "000000000000000000000006" } + files_id: { "$oid": "000000000000000000000005" } + n: 1 + data: { "$binary": { "base64": "VWZ3iA==", "subType": "00" } } # hex: 55667788 + - _id: { "$oid": "000000000000000000000007" } + files_id: { "$oid": "000000000000000000000005" } + n: 2 + data: { "$binary" : { "base64": "mao=", "subType" : "00" } } # hex: 99aa + - _id: { "$oid": "000000000000000000000008" } + files_id: { "$oid": "000000000000000000000006" } + n: 0 + data: { "$binary": { "base64": "ESI=", "subType": "00" } } # hex: 1122 + +tests: + - description: "download when length is zero" + operations: + - name: download + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000001" } + expectResult: { $$matchesHexBytes: "" } + - description: "download when length is zero and there is one empty chunk" + operations: + - name: download + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000002" } + expectResult: { $$matchesHexBytes: "" } + - description: "download when there is one chunk" + operations: + - name: download + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000003" } + expectResult: { $$matchesHexBytes: "1122" } + - description: "download when there are two chunks" + operations: + - name: download + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000004" } + expectResult: { $$matchesHexBytes: "1122334455667788" } + - description: "download when there are three chunks" + operations: + - name: download + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000005" } + expectResult: { $$matchesHexBytes: "112233445566778899aa" } + - description: "download when files entry does not exist" + operations: + - name: download + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000000" } + expectError: { isError: true } # FileNotFound + - description: "download when an intermediate chunk is missing" + operations: + - name: deleteOne + object: *bucket0_chunks_collection + arguments: + filter: + files_id: { $oid: "000000000000000000000005" } + n: 1 + expectResult: + deletedCount: 1 + - name: download + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000005" } + expectError: { isError: true } # ChunkIsMissing + - description: "download when final chunk is missing" + operations: + - name: deleteOne + object: *bucket0_chunks_collection + arguments: + filter: + files_id: { $oid: "000000000000000000000005" } + n: 2 + expectResult: + deletedCount: 1 + - name: download + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000005" } + expectError: { isError: true } # ChunkIsMissing + - description: "download when an intermediate chunk is the wrong size" + operations: + - name: bulkWrite + object: *bucket0_chunks_collection + arguments: + requests: + - updateOne: + filter: + files_id: { $oid: "000000000000000000000005" } + n: 1 + update: + $set: { data: { "$binary": { "base64": "VWZ3", "subType": "00" } } } # hex: 556677 + - updateOne: + filter: + files_id: { $oid: "000000000000000000000005" } + n: 2 + update: + $set: { data: { "$binary": { "base64": "iJmq", "subType": "00" } } } # hex: 8899aa + expectResult: + matchedCount: 2 + modifiedCount: 2 + - name: download + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000005" } + expectError: { isError: true } # ChunkIsWrongSize + - description: "download when final chunk is the wrong size" + operations: + - name: updateOne + object: *bucket0_chunks_collection + arguments: + filter: + files_id: { $oid: "000000000000000000000005" } + n: 2 + update: + $set: { data: { "$binary": { "base64": "mQ==", "subType": "00" } } } # hex: 99 + expectResult: + matchedCount: 1 + modifiedCount: 1 + - name: download + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000005" } + expectError: { isError: true } # ChunkIsWrongSize + - description: "download legacy file with no name" + operations: + - name: download + object: *bucket0 + arguments: + id: { $oid: "000000000000000000000006" } + expectResult: { $$matchesHexBytes: "1122" } diff --git a/test/spec/gridfs/downloadByName.json b/test/spec/gridfs/downloadByName.json new file mode 100644 index 0000000000..cd44663957 --- /dev/null +++ b/test/spec/gridfs/downloadByName.json @@ -0,0 +1,330 @@ +{ + "description": "gridfs-downloadByName", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "gridfs-tests" + } + }, + { + "bucket": { + "id": "bucket0", + "database": "database0" + } + }, + { + "collection": { + "id": "bucket0_files_collection", + "database": "database0", + "collectionName": "fs.files" + } + }, + { + "collection": { + "id": "bucket0_chunks_collection", + "database": "database0", + "collectionName": "fs.chunks" + } + } + ], + "initialData": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "47ed733b8d10be225eceba344d533586", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-02T00:00:00.000Z" + }, + "md5": "b15835f133ff2e27c7cb28117bfae8f4", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-03T00:00:00.000Z" + }, + "md5": "eccbc87e4b5ce2fe28308fd9f2a7baf3", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-04T00:00:00.000Z" + }, + "md5": "f623e75af30e62bbd73d6df5b50bb7b5", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000005" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-05T00:00:00.000Z" + }, + "md5": "4c614360da93c0a041b22e537de151eb", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000001" + }, + "n": 0, + "data": { + "$binary": { + "base64": "EQ==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "Ig==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "Mw==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$binary": { + "base64": "RA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000005" + }, + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 0, + "data": { + "$binary": { + "base64": "VQ==", + "subType": "00" + } + } + } + ] + } + ], + "tests": [ + { + "description": "downloadByName defaults to latest revision (-1)", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc" + }, + "expectResult": { + "$$matchesHexBytes": "55" + } + } + ] + }, + { + "description": "downloadByName when revision is 0", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc", + "revision": 0 + }, + "expectResult": { + "$$matchesHexBytes": "11" + } + } + ] + }, + { + "description": "downloadByName when revision is 1", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc", + "revision": 1 + }, + "expectResult": { + "$$matchesHexBytes": "22" + } + } + ] + }, + { + "description": "downloadByName when revision is 2", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc", + "revision": 2 + }, + "expectResult": { + "$$matchesHexBytes": "33" + } + } + ] + }, + { + "description": "downloadByName when revision is -2", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc", + "revision": -2 + }, + "expectResult": { + "$$matchesHexBytes": "44" + } + } + ] + }, + { + "description": "downloadByName when revision is -1", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc", + "revision": -1 + }, + "expectResult": { + "$$matchesHexBytes": "55" + } + } + ] + }, + { + "description": "downloadByName when files entry does not exist", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "xyz" + }, + "expectError": { + "isError": true + } + } + ] + }, + { + "description": "downloadByName when revision does not exist", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc", + "revision": 999 + }, + "expectError": { + "isError": true + } + } + ] + } + ] +} diff --git a/test/spec/gridfs/downloadByName.yml b/test/spec/gridfs/downloadByName.yml new file mode 100644 index 0000000000..6dfc602b66 --- /dev/null +++ b/test/spec/gridfs/downloadByName.yml @@ -0,0 +1,159 @@ +description: "gridfs-downloadByName" + +schemaVersion: "1.0" + +createEntities: + - client: + id: &client0 client0 + - database: + id: &database0 database0 + client: *client0 + databaseName: &database0Name gridfs-tests + - bucket: + id: &bucket0 bucket0 + database: *database0 + - collection: + id: &bucket0_files_collection bucket0_files_collection + database: *database0 + collectionName: &bucket0_files_collectionName fs.files + - collection: + id: &bucket0_chunks_collection bucket0_chunks_collection + database: *database0 + collectionName: &bucket0_chunks_collectionName fs.chunks + +initialData: + - collectionName: *bucket0_files_collectionName + databaseName: *database0Name + documents: + - _id: { $oid: "000000000000000000000001" } + length: 1 + chunkSize: 4 + uploadDate: { $date: "1970-01-01T00:00:00.000Z" } + md5: "47ed733b8d10be225eceba344d533586" + filename: "abc" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - _id: { $oid: "000000000000000000000002" } + length: 1 + chunkSize: 4 + uploadDate: { $date: "1970-01-02T00:00:00.000Z" } + md5: "b15835f133ff2e27c7cb28117bfae8f4" + filename: "abc" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - _id: { $oid: "000000000000000000000003" } + length: 1 + chunkSize: 4 + uploadDate: { $date: "1970-01-03T00:00:00.000Z" } + md5: "eccbc87e4b5ce2fe28308fd9f2a7baf3" + filename: "abc" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - _id: { $oid: "000000000000000000000004" } + length: 1 + chunkSize: 4 + uploadDate: { $date: "1970-01-04T00:00:00.000Z" } + md5: "f623e75af30e62bbd73d6df5b50bb7b5" + filename: "abc" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - _id: { $oid: "000000000000000000000005" } + length: 1 + chunkSize: 4 + uploadDate: { $date: "1970-01-05T00:00:00.000Z" } + md5: "4c614360da93c0a041b22e537de151eb" + filename: "abc" + contentType: "application/octet-stream" + aliases: [] + metadata: {} + - collectionName: *bucket0_chunks_collectionName + databaseName: *database0Name + documents: + - _id: { $oid: "000000000000000000000001" } + files_id: { $oid: "000000000000000000000001" } + n: 0 + data: { "$binary": { "base64": "EQ==", "subType": "00" } } # hex: 11 + - _id: { $oid: "000000000000000000000002" } + files_id: { $oid: "000000000000000000000002" } + n: 0 + data: { "$binary": { "base64": "Ig==", "subType": "00" } } # hex: 22 + - _id: { $oid: "000000000000000000000003" } + files_id: { $oid: "000000000000000000000003" } + n: 0 + data: { "$binary": { "base64": "Mw==", "subType": "00" } } # hex: 33 + - _id: { $oid: "000000000000000000000004" } + files_id: { $oid: "000000000000000000000004" } + n: 0 + data: { "$binary": { "base64": "RA==", "subType": "00" } } # hex: 44 + - _id: { $oid: "000000000000000000000005" } + files_id: { $oid: "000000000000000000000005" } + n: 0 + data: { "$binary": { "base64": "VQ==", "subType": "00" } } # hex: 55 + +tests: + - description: "downloadByName defaults to latest revision (-1)" + operations: + - name: downloadByName + object: *bucket0 + arguments: + filename: "abc" + expectResult: { $$matchesHexBytes: "55" } + - description: "downloadByName when revision is 0" + operations: + - name: downloadByName + object: *bucket0 + arguments: + filename: "abc" + revision: 0 + expectResult: { $$matchesHexBytes: "11" } + - description: "downloadByName when revision is 1" + operations: + - name: downloadByName + object: *bucket0 + arguments: + filename: "abc" + revision: 1 + expectResult: { $$matchesHexBytes: "22" } + - description: "downloadByName when revision is 2" + operations: + - name: downloadByName + object: *bucket0 + arguments: + filename: "abc" + revision: 2 + expectResult: { $$matchesHexBytes: "33" } + - description: "downloadByName when revision is -2" + operations: + - name: downloadByName + object: *bucket0 + arguments: + filename: "abc" + revision: -2 + expectResult: { $$matchesHexBytes: "44" } + - description: "downloadByName when revision is -1" + operations: + - name: downloadByName + object: *bucket0 + arguments: + filename: "abc" + revision: -1 + expectResult: { $$matchesHexBytes: "55" } + - description: "downloadByName when files entry does not exist" + operations: + - name: downloadByName + object: *bucket0 + arguments: + filename: "xyz" + expectError: { isError: true } # FileNotFound + - description: "downloadByName when revision does not exist" + operations: + - name: downloadByName + object: *bucket0 + arguments: + filename: "abc" + revision: 999 + expectError: { isError: true } # RevisionNotFound diff --git a/test/spec/gridfs/gridfs-download.json b/test/spec/gridfs/gridfs-download.json deleted file mode 100644 index 19b78f65fa..0000000000 --- a/test/spec/gridfs/gridfs-download.json +++ /dev/null @@ -1,564 +0,0 @@ -{ - "data": { - "files": [ - { - "_id": { - "$oid": "000000000000000000000001" - }, - "length": 0, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "d41d8cd98f00b204e9800998ecf8427e", - "filename": "length-0", - "contentType": "application/octet-stream", - "aliases": [ - - ], - "metadata": { - } - }, - { - "_id": { - "$oid": "000000000000000000000002" - }, - "length": 0, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "d41d8cd98f00b204e9800998ecf8427e", - "filename": "length-0-with-empty-chunk", - "contentType": "application/octet-stream", - "aliases": [ - - ], - "metadata": { - } - }, - { - "_id": { - "$oid": "000000000000000000000003" - }, - "length": 2, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "c700ed4fdb1d27055aa3faa2c2432283", - "filename": "length-2", - "contentType": "application/octet-stream", - "aliases": [ - - ], - "metadata": { - } - }, - { - "_id": { - "$oid": "000000000000000000000004" - }, - "length": 8, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "dd254cdc958e53abaa67da9f797125f5", - "filename": "length-8", - "contentType": "application/octet-stream", - "aliases": [ - - ], - "metadata": { - } - }, - { - "_id": { - "$oid": "000000000000000000000005" - }, - "length": 10, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "57d83cd477bfb1ccd975ab33d827a92b", - "filename": "length-10", - "contentType": "application/octet-stream", - "aliases": [ - - ], - "metadata": { - } - }, - { - "_id": { - "$oid": "000000000000000000000006" - }, - "length": 12, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "6289ac1db331d1c7677a4b7e123178f9", - "filename": "length-12-with-empty-chunk", - "contentType": "application/octet-stream", - "aliases": [ - - ], - "metadata": { - } - } - ], - "chunks": [ - { - "_id": { - "$oid": "000000000000000000000001" - }, - "files_id": { - "$oid": "000000000000000000000002" - }, - "n": 0, - "data": { - "$hex": "" - } - }, - { - "_id": { - "$oid": "000000000000000000000002" - }, - "files_id": { - "$oid": "000000000000000000000003" - }, - "n": 0, - "data": { - "$hex": "1122" - } - }, - { - "_id": { - "$oid": "000000000000000000000003" - }, - "files_id": { - "$oid": "000000000000000000000004" - }, - "n": 0, - "data": { - "$hex": "11223344" - } - }, - { - "_id": { - "$oid": "000000000000000000000004" - }, - "files_id": { - "$oid": "000000000000000000000004" - }, - "n": 1, - "data": { - "$hex": "55667788" - } - }, - { - "_id": { - "$oid": "000000000000000000000005" - }, - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 0, - "data": { - "$hex": "11223344" - } - }, - { - "_id": { - "$oid": "000000000000000000000006" - }, - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 1, - "data": { - "$hex": "55667788" - } - }, - { - "_id": { - "$oid": "000000000000000000000007" - }, - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 2, - "data": { - "$hex": "99aa" - } - }, - { - "_id": { - "$oid": "000000000000000000000008" - }, - "files_id": { - "$oid": "000000000000000000000006" - }, - "n": 0, - "data": { - "$hex": "11223344" - } - }, - { - "_id": { - "$oid": "000000000000000000000009" - }, - "files_id": { - "$oid": "000000000000000000000006" - }, - "n": 1, - "data": { - "$hex": "55667788" - } - }, - { - "_id": { - "$oid": "000000000000000000000010" - }, - "files_id": { - "$oid": "000000000000000000000006" - }, - "n": 2, - "data": { - "$hex": "99aabbcc" - } - }, - { - "_id": { - "$oid": "000000000000000000000011" - }, - "files_id": { - "$oid": "000000000000000000000006" - }, - "n": 3, - "data": { - "$hex": "" - } - } - ] - }, - "tests": [ - { - "description": "Download when length is zero", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000001" - }, - "options": { - } - } - }, - "assert": { - "result": { - "$hex": "" - } - } - }, - { - "description": "Download when length is zero and there is one empty chunk", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000002" - }, - "options": { - } - } - }, - "assert": { - "result": { - "$hex": "" - } - } - }, - { - "description": "Download when there is one chunk", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000003" - }, - "options": { - } - } - }, - "assert": { - "result": { - "$hex": "1122" - } - } - }, - { - "description": "Download when there are two chunks", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000004" - }, - "options": { - } - } - }, - "assert": { - "result": { - "$hex": "1122334455667788" - } - } - }, - { - "description": "Download when there are three chunks", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000005" - }, - "options": { - } - } - }, - "assert": { - "result": { - "$hex": "112233445566778899aa" - } - } - }, - { - "description": "Download when there are three chunks and one extra empty chunk at the end", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000006" - }, - "options": { - } - } - }, - "assert": { - "result": { - "$hex": "112233445566778899aabbcc" - } - } - }, - { - "description": "Download when files entry does not exist", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000000" - }, - "options": { - } - } - }, - "assert": { - "error": "FileNotFound" - } - }, - { - "description": "Download when an intermediate chunk is missing", - "arrange": { - "data": [ - { - "delete": "fs.chunks", - "deletes": [ - { - "q": { - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 1 - }, - "limit": 1 - } - ] - } - ] - }, - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000005" - } - } - }, - "assert": { - "error": "ChunkIsMissing" - } - }, - { - "description": "Download when final chunk is missing", - "arrange": { - "data": [ - { - "delete": "fs.chunks", - "deletes": [ - { - "q": { - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 1 - }, - "limit": 1 - } - ] - } - ] - }, - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000005" - } - } - }, - "assert": { - "error": "ChunkIsMissing" - } - }, - { - "description": "Download when there is an extra chunk", - "arrange": { - "data": [ - { - "insert": "fs.chunks", - "documents": [ - { - "_id": { - "$oid": "000000000000000000000012" - }, - "files_id": { - "$oid": "000000000000000000000004" - }, - "n": 2, - "data": { - "$hex": "99" - } - } - ] - } - ] - }, - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000004" - } - } - }, - "assert": { - "error": "ExtraChunk" - } - }, - { - "description": "Download when an intermediate chunk is the wrong size", - "arrange": { - "data": [ - { - "update": "fs.chunks", - "updates": [ - { - "q": { - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 1 - }, - "u": { - "$set": { - "data": { - "$hex": "556677" - } - } - } - }, - { - "q": { - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 2 - }, - "u": { - "$set": { - "data": { - "$hex": "8899aa" - } - } - } - } - ] - } - ] - }, - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000005" - } - } - }, - "assert": { - "error": "ChunkIsWrongSize" - } - }, - { - "description": "Download when final chunk is the wrong size", - "arrange": { - "data": [ - { - "update": "fs.chunks", - "updates": [ - { - "q": { - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 2 - }, - "u": { - "$set": { - "data": { - "$hex": "99" - } - } - } - } - ] - } - ] - }, - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000005" - } - } - }, - "assert": { - "error": "ChunkIsWrongSize" - } - } - ] -} diff --git a/test/spec/gridfs/gridfs-upload.json b/test/spec/gridfs/gridfs-upload.json deleted file mode 100644 index f581acd11c..0000000000 --- a/test/spec/gridfs/gridfs-upload.json +++ /dev/null @@ -1,391 +0,0 @@ -{ - "data": { - "files": [ - - ], - "chunks": [ - - ] - }, - "tests": [ - { - "description": "Upload when length is 0", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "" - }, - "options": { - "chunkSizeBytes": 4 - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 0, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "d41d8cd98f00b204e9800998ecf8427e", - "filename": "filename" - } - ] - } - ] - } - }, - { - "description": "Upload when length is 1", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "11" - }, - "options": { - "chunkSizeBytes": 4 - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 1, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "47ed733b8d10be225eceba344d533586", - "filename": "filename" - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "11" - } - } - ] - } - ] - } - }, - { - "description": "Upload when length is 3", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "112233" - }, - "options": { - "chunkSizeBytes": 4 - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 3, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "bafae3a174ab91fc70db7a6aa50f4f52", - "filename": "filename" - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "112233" - } - } - ] - } - ] - } - }, - { - "description": "Upload when length is 4", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "11223344" - }, - "options": { - "chunkSizeBytes": 4 - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 4, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "7e7c77cff5705d1f7574a25ef6662117", - "filename": "filename" - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "11223344" - } - } - ] - } - ] - } - }, - { - "description": "Upload when length is 5", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "1122334455" - }, - "options": { - "chunkSizeBytes": 4 - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 5, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "283d4fea5dded59cf837d3047328f5af", - "filename": "filename" - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "11223344" - } - }, - { - "_id": "*actual", - "files_id": "*result", - "n": 1, - "data": { - "$hex": "55" - } - } - ] - } - ] - } - }, - { - "description": "Upload when length is 8", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "1122334455667788" - }, - "options": { - "chunkSizeBytes": 4 - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 8, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "dd254cdc958e53abaa67da9f797125f5", - "filename": "filename" - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "11223344" - } - }, - { - "_id": "*actual", - "files_id": "*result", - "n": 1, - "data": { - "$hex": "55667788" - } - } - ] - } - ] - } - }, - { - "description": "Upload when contentType is provided", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "11" - }, - "options": { - "chunkSizeBytes": 4, - "contentType": "image/jpeg" - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 1, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "47ed733b8d10be225eceba344d533586", - "filename": "filename", - "contentType": "image/jpeg" - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "11" - } - } - ] - } - ] - } - }, - { - "description": "Upload when metadata is provided", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "11" - }, - "options": { - "chunkSizeBytes": 4, - "metadata": { - "x": 1 - } - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 1, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "47ed733b8d10be225eceba344d533586", - "filename": "filename", - "metadata": { - "x": 1 - } - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "11" - } - } - ] - } - ] - } - } - ] -} diff --git a/test/spec/gridfs/upload-disableMD5.json b/test/spec/gridfs/upload-disableMD5.json new file mode 100644 index 0000000000..d5a9d6f4ab --- /dev/null +++ b/test/spec/gridfs/upload-disableMD5.json @@ -0,0 +1,172 @@ +{ + "description": "gridfs-upload-disableMD5", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "gridfs-tests" + } + }, + { + "bucket": { + "id": "bucket0", + "database": "database0" + } + }, + { + "collection": { + "id": "bucket0_files_collection", + "database": "database0", + "collectionName": "fs.files" + } + }, + { + "collection": { + "id": "bucket0_chunks_collection", + "database": "database0", + "collectionName": "fs.chunks" + } + } + ], + "initialData": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "upload when length is 0 sans MD5", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "" + }, + "chunkSizeBytes": 4, + "disableMD5": true + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$exists": false + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [] + } + ] + }, + { + "description": "upload when length is 1 sans MD5", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "11" + }, + "chunkSizeBytes": 4, + "disableMD5": true + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$exists": false + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "EQ==", + "subType": "00" + } + } + } + ] + } + ] + } + ] +} diff --git a/test/spec/gridfs/upload-disableMD5.yml b/test/spec/gridfs/upload-disableMD5.yml new file mode 100644 index 0000000000..4f77f5a1a2 --- /dev/null +++ b/test/spec/gridfs/upload-disableMD5.yml @@ -0,0 +1,92 @@ +description: "gridfs-upload-disableMD5" + +schemaVersion: "1.0" + +createEntities: + - client: + id: &client0 client0 + - database: + id: &database0 database0 + client: *client0 + databaseName: &database0Name gridfs-tests + - bucket: + id: &bucket0 bucket0 + database: *database0 + - collection: + id: &bucket0_files_collection bucket0_files_collection + database: *database0 + collectionName: &bucket0_files_collectionName fs.files + - collection: + id: &bucket0_chunks_collection bucket0_chunks_collection + database: *database0 + collectionName: &bucket0_chunks_collectionName fs.chunks + +initialData: + - collectionName: *bucket0_files_collectionName + databaseName: *database0Name + documents: [] + - collectionName: *bucket0_chunks_collectionName + databaseName: *database0Name + documents: [] + +# Note: these tests utilize the transitional "disableMD5" option. Drivers that +# do not support the option should skip this file. +tests: + - description: "upload when length is 0 sans MD5" + operations: + - name: upload + object: *bucket0 + arguments: + filename: "filename" + source: { $$hexBytes: "" } + chunkSizeBytes: 4 + disableMD5: true + expectResult: { $$type: objectId } + saveResultAsEntity: &uploadedObjectId uploadedObjectId + - name: find + object: *bucket0_files_collection + arguments: + filter: {} + expectResult: + - _id: { $$matchesEntity: *uploadedObjectId } + length: 0 + chunkSize: 4 + uploadDate: { $$type: date } + md5: { $$exists: false } + filename: filename + - name: find + object: *bucket0_chunks_collection + arguments: + filter: {} + expectResult: [] + - description: "upload when length is 1 sans MD5" + operations: + - name: upload + object: *bucket0 + arguments: + filename: "filename" + source: { $$hexBytes: "11" } + chunkSizeBytes: 4 + disableMD5: true + expectResult: { $$type: objectId } + saveResultAsEntity: *uploadedObjectId + - name: find + object: *bucket0_files_collection + arguments: + filter: {} + expectResult: + - _id: { $$matchesEntity: *uploadedObjectId } + length: 1 + chunkSize: 4 + uploadDate: { $$type: date } + md5: { $$exists: false } + filename: filename + - name: find + object: *bucket0_chunks_collection + arguments: + filter: {} + expectResult: + - _id: { $$type: objectId } + files_id: { $$matchesEntity: *uploadedObjectId } + n: 0 + data: { $binary: { base64: "EQ==", subType: "00" } } # hex 11 diff --git a/test/spec/gridfs/upload.json b/test/spec/gridfs/upload.json new file mode 100644 index 0000000000..97e18d2bc2 --- /dev/null +++ b/test/spec/gridfs/upload.json @@ -0,0 +1,616 @@ +{ + "description": "gridfs-upload", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "gridfs-tests" + } + }, + { + "bucket": { + "id": "bucket0", + "database": "database0" + } + }, + { + "collection": { + "id": "bucket0_files_collection", + "database": "database0", + "collectionName": "fs.files" + } + }, + { + "collection": { + "id": "bucket0_chunks_collection", + "database": "database0", + "collectionName": "fs.chunks" + } + } + ], + "initialData": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "upload when length is 0", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "" + }, + "chunkSizeBytes": 4 + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "d41d8cd98f00b204e9800998ecf8427e" + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [] + } + ] + }, + { + "description": "upload when length is 1", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "11" + }, + "chunkSizeBytes": 4 + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "47ed733b8d10be225eceba344d533586" + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "EQ==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "upload when length is 3", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "112233" + }, + "chunkSizeBytes": 4 + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 3, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "bafae3a174ab91fc70db7a6aa50f4f52" + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIz", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "upload when length is 4", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "11223344" + }, + "chunkSizeBytes": 4 + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 4, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "7e7c77cff5705d1f7574a25ef6662117" + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "upload when length is 5", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "1122334455" + }, + "chunkSizeBytes": 4 + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 5, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "283d4fea5dded59cf837d3047328f5af" + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {}, + "sort": { + "n": 1 + } + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VQ==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "upload when length is 8", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "1122334455667788" + }, + "chunkSizeBytes": 4 + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "dd254cdc958e53abaa67da9f797125f5" + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {}, + "sort": { + "n": 1 + } + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "upload when contentType is provided", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "11" + }, + "chunkSizeBytes": 4, + "contentType": "image/jpeg" + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "47ed733b8d10be225eceba344d533586" + }, + "filename": "filename", + "contentType": "image/jpeg" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "EQ==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "upload when metadata is provided", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "11" + }, + "chunkSizeBytes": 4, + "metadata": { + "x": 1 + } + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "47ed733b8d10be225eceba344d533586" + }, + "filename": "filename", + "metadata": { + "x": 1 + } + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "EQ==", + "subType": "00" + } + } + } + ] + } + ] + } + ] +} diff --git a/test/spec/gridfs/upload.yml b/test/spec/gridfs/upload.yml new file mode 100644 index 0000000000..27f3186fc4 --- /dev/null +++ b/test/spec/gridfs/upload.yml @@ -0,0 +1,288 @@ +description: "gridfs-upload" + +schemaVersion: "1.0" + +createEntities: + - client: + id: &client0 client0 + - database: + id: &database0 database0 + client: *client0 + databaseName: &database0Name gridfs-tests + - bucket: + id: &bucket0 bucket0 + database: *database0 + - collection: + id: &bucket0_files_collection bucket0_files_collection + database: *database0 + collectionName: &bucket0_files_collectionName fs.files + - collection: + id: &bucket0_chunks_collection bucket0_chunks_collection + database: *database0 + collectionName: &bucket0_chunks_collectionName fs.chunks + +initialData: + - collectionName: *bucket0_files_collectionName + databaseName: *database0Name + documents: [] + - collectionName: *bucket0_chunks_collectionName + databaseName: *database0Name + documents: [] + +# Note: Uploaded files and chunks include ObjectIds, which we cannot match with +# "outcome" since it does not allow operators. Instead, these tests will use +# find operations to assert the contents of uploaded files and chunks. +tests: + - description: "upload when length is 0" + operations: + - name: upload + object: *bucket0 + arguments: + filename: "filename" + source: { $$hexBytes: "" } + chunkSizeBytes: 4 + expectResult: { $$type: objectId } + saveResultAsEntity: &uploadedObjectId uploadedObjectId + - name: find + object: *bucket0_files_collection + arguments: + filter: {} + expectResult: + - _id: { $$matchesEntity: *uploadedObjectId } + length: 0 + chunkSize: 4 + uploadDate: { $$type: date } + # The md5 field is deprecated so some drivers do not calculate it when uploading files. + md5: { $$unsetOrMatches: "d41d8cd98f00b204e9800998ecf8427e" } + filename: filename + - name: find + object: *bucket0_chunks_collection + arguments: + filter: {} + expectResult: [] + - description: "upload when length is 1" + operations: + - name: upload + object: *bucket0 + arguments: + filename: "filename" + source: { $$hexBytes: "11" } + chunkSizeBytes: 4 + expectResult: { $$type: objectId } + saveResultAsEntity: *uploadedObjectId + - name: find + object: *bucket0_files_collection + arguments: + filter: {} + expectResult: + - _id: { $$matchesEntity: *uploadedObjectId } + length: 1 + chunkSize: 4 + uploadDate: { $$type: date } + md5: { $$unsetOrMatches: "47ed733b8d10be225eceba344d533586" } + filename: filename + - name: find + object: *bucket0_chunks_collection + arguments: + filter: {} + expectResult: + - _id: { $$type: objectId } + files_id: { $$matchesEntity: *uploadedObjectId } + n: 0 + data: { $binary: { base64: "EQ==", subType: "00" } } # hex 11 + - description: "upload when length is 3" + operations: + - name: upload + object: *bucket0 + arguments: + filename: "filename" + source: { $$hexBytes: "112233" } + chunkSizeBytes: 4 + expectResult: { $$type: objectId } + saveResultAsEntity: *uploadedObjectId + - name: find + object: *bucket0_files_collection + arguments: + filter: {} + expectResult: + - _id: { $$matchesEntity: *uploadedObjectId } + length: 3 + chunkSize: 4 + uploadDate: { $$type: date } + md5: { $$unsetOrMatches: "bafae3a174ab91fc70db7a6aa50f4f52" } + filename: filename + - name: find + object: *bucket0_chunks_collection + arguments: + filter: {} + expectResult: + - _id: { $$type: objectId } + files_id: { $$matchesEntity: *uploadedObjectId } + n: 0 + data: { $binary: { base64: "ESIz", subType: "00" } } # hex 112233 + - description: "upload when length is 4" + operations: + - name: upload + object: *bucket0 + arguments: + filename: "filename" + source: { $$hexBytes: "11223344" } + chunkSizeBytes: 4 + expectResult: { $$type: objectId } + saveResultAsEntity: *uploadedObjectId + - name: find + object: *bucket0_files_collection + arguments: + filter: {} + expectResult: + - _id: { $$matchesEntity: *uploadedObjectId } + length: 4 + chunkSize: 4 + uploadDate: { $$type: date } + md5: { $$unsetOrMatches: "7e7c77cff5705d1f7574a25ef6662117" } + filename: filename + - name: find + object: *bucket0_chunks_collection + arguments: + filter: {} + expectResult: + - _id: { $$type: objectId } + files_id: { $$matchesEntity: *uploadedObjectId } + n: 0 + data: { $binary: { base64: "ESIzRA==", subType: "00" } } # hex 11223344 + - description: "upload when length is 5" + operations: + - name: upload + object: *bucket0 + arguments: + filename: filename + source: { $$hexBytes: "1122334455" } + chunkSizeBytes: 4 + expectResult: { $$type: objectId } + saveResultAsEntity: *uploadedObjectId + - name: find + object: *bucket0_files_collection + arguments: + filter: {} + expectResult: + - _id: { $$matchesEntity: *uploadedObjectId } + length: 5 + chunkSize: 4 + uploadDate: { $$type: date } + md5: { $$unsetOrMatches: "283d4fea5dded59cf837d3047328f5af" } + filename: filename + - name: find + object: *bucket0_chunks_collection + arguments: + filter: {} + # Sort to ensure chunks are returned in a deterministic order + sort: { n: 1 } + expectResult: + - _id: { $$type: objectId } + files_id: { $$matchesEntity: *uploadedObjectId } + n: 0 + data: { $binary: { base64: "ESIzRA==", subType: "00" } } # hex 11223344 + - _id: { $$type: objectId } + files_id: { $$matchesEntity: *uploadedObjectId } + n: 1 + data: { $binary: { base64: "VQ==", subType: "00" } } # hex 55 + - description: "upload when length is 8" + operations: + - name: upload + object: *bucket0 + arguments: + filename: filename + source: { $$hexBytes: "1122334455667788" } + chunkSizeBytes: 4 + expectResult: { $$type: objectId } + saveResultAsEntity: *uploadedObjectId + - name: find + object: *bucket0_files_collection + arguments: + filter: {} + expectResult: + - _id: { $$matchesEntity: *uploadedObjectId } + length: 8 + chunkSize: 4 + uploadDate: { $$type: date } + md5: { $$unsetOrMatches: "dd254cdc958e53abaa67da9f797125f5" } + filename: filename + - name: find + object: *bucket0_chunks_collection + arguments: + filter: {} + # Sort to ensure chunks are returned in a deterministic order + sort: { n: 1 } + expectResult: + - _id: { $$type: objectId } + files_id: { $$matchesEntity: *uploadedObjectId } + n: 0 + data: { $binary: { base64: "ESIzRA==", subType: "00" } } # hex 11223344 + - _id: { $$type: objectId } + files_id: { $$matchesEntity: *uploadedObjectId } + n: 1 + data: { $binary: { base64: "VWZ3iA==", subType: "00" } } # hex 55667788 + - description: "upload when contentType is provided" + operations: + - name: upload + object: *bucket0 + arguments: + filename: "filename" + source: { $$hexBytes: "11" } + chunkSizeBytes: 4 + contentType: "image/jpeg" + expectResult: { $$type: objectId } + saveResultAsEntity: *uploadedObjectId + - name: find + object: *bucket0_files_collection + arguments: + filter: {} + expectResult: + - _id: { $$matchesEntity: *uploadedObjectId } + length: 1 + chunkSize: 4 + uploadDate: { $$type: date } + md5: { $$unsetOrMatches: "47ed733b8d10be225eceba344d533586" } + filename: filename + contentType: "image/jpeg" + - name: find + object: *bucket0_chunks_collection + arguments: + filter: {} + expectResult: + - _id: { $$type: objectId } + files_id: { $$matchesEntity: *uploadedObjectId } + n: 0 + data: { $binary: { base64: "EQ==", subType: "00" } } # hex 11 + - description: "upload when metadata is provided" + operations: + - name: upload + object: *bucket0 + arguments: + filename: "filename" + source: { $$hexBytes: "11" } + chunkSizeBytes: 4 + metadata: { x: 1 } + expectResult: { $$type: objectId } + saveResultAsEntity: *uploadedObjectId + - name: find + object: *bucket0_files_collection + arguments: + filter: {} + expectResult: + - _id: { $$matchesEntity: *uploadedObjectId } + length: 1 + chunkSize: 4 + uploadDate: { $$type: date } + md5: { $$unsetOrMatches: "47ed733b8d10be225eceba344d533586" } + filename: filename + metadata: { x: 1 } + - name: find + object: *bucket0_chunks_collection + arguments: + filter: {} + expectResult: + - _id: { $$type: objectId } + files_id: { $$matchesEntity: *uploadedObjectId } + n: 0 + data: { $binary: { base64: "EQ==", subType: "00" } } # hex 11 diff --git a/test/tools/unified-spec-runner/operations.ts b/test/tools/unified-spec-runner/operations.ts index 9d71dddf55..d1ffdf64e5 100644 --- a/test/tools/unified-spec-runner/operations.ts +++ b/test/tools/unified-spec-runner/operations.ts @@ -1,6 +1,8 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ -import { once, Writable } from 'node:stream'; + +import { Readable } from 'node:stream'; +import { pipeline } from 'node:stream/promises'; import { AssertionError, expect } from 'chai'; @@ -519,27 +521,28 @@ operations.set('delete', async ({ entities, operation }) => { operations.set('download', async ({ entities, operation }) => { const bucket = entities.getEntity('bucket', operation.object); - const stream = bucket.openDownloadStream(operation.arguments!.id); - return new Promise((resolve, reject) => { - const chunks: any[] = []; - stream.on('data', chunk => chunks.push(...chunk)); - stream.on('error', reject); - stream.on('end', () => resolve(chunks)); - }); + const { id, ...options } = operation.arguments ?? {}; + const stream = bucket.openDownloadStream(id, options); + return Buffer.concat(await stream.toArray()); }); -operations.set('upload', async ({ entities, operation }) => { +operations.set('downloadByName', async ({ entities, operation }) => { const bucket = entities.getEntity('bucket', operation.object); - const stream = bucket.openUploadStream(operation.arguments!.filename, { - chunkSizeBytes: operation.arguments?.chunkSizeBytes - }); + const { filename, ...options } = operation.arguments ?? {}; + const stream: Readable = bucket.openDownloadStreamByName(filename, options); + + return Buffer.concat(await stream.toArray()); +}); + +operations.set('upload', async ({ entities, operation }) => { + const bucket = entities.getEntity('bucket', operation.object); + const { filename, source, ...options } = operation.arguments ?? {}; - const data = Buffer.from(operation.arguments!.source.$$hexBytes, 'hex'); - const willFinish = once(stream, 'finish'); - stream.end(data); - await willFinish; + const stream = bucket.openUploadStream(operation.arguments!.filename, options); + const filestream = Readable.from(Buffer.from(operation.arguments!.source.$$hexBytes, 'hex')); + await pipeline(filestream, stream); return stream.gridFSFile?._id; });