diff --git a/test/posts.js b/test/posts.js index 8c2a7d3a5c..fc9b89f44b 100644 --- a/test/posts.js +++ b/test/posts.js @@ -5,8 +5,6 @@ const assert = require('assert'); const async = require('async'); const request = require('request'); const nconf = require('nconf'); -const crypto = require('crypto'); -const fs = require('fs'); const path = require('path'); const util = require('util'); @@ -20,10 +18,10 @@ const privileges = require('../src/privileges'); const user = require('../src/user'); const groups = require('../src/groups'); const socketPosts = require('../src/socket.io/posts'); -const socketTopics = require('../src/socket.io/topics'); const apiPosts = require('../src/api/posts'); const apiTopics = require('../src/api/topics'); const meta = require('../src/meta'); +const file = require('../src/file'); const helpers = require('./helpers'); describe('Post\'s', () => { @@ -1122,258 +1120,6 @@ describe('Post\'s', () => { }); }); - describe('upload methods', () => { - let pid; - let purgePid; - - before(async () => { - // Create stub files for testing - ['abracadabra.png', 'shazam.jpg', 'whoa.gif', 'amazeballs.jpg', 'wut.txt', 'test.bmp'] - .forEach(filename => fs.closeSync(fs.openSync(path.join(nconf.get('upload_path'), 'files', filename), 'w'))); - - const topicPostData = await topics.post({ - uid: 1, - cid: 1, - title: 'topic with some images', - content: 'here is an image [alt text](/assets/uploads/files/abracadabra.png) and another [alt text](/assets/uploads/files/shazam.jpg)', - }); - pid = topicPostData.postData.pid; - - const purgePostData = await topics.post({ - uid: 1, - cid: 1, - title: 'topic with some images, to be purged', - content: 'here is an image [alt text](/assets/uploads/files/whoa.gif) and another [alt text](/assets/uploads/files/amazeballs.jpg)', - }); - purgePid = purgePostData.postData.pid; - }); - - describe('.sync()', () => { - it('should properly add new images to the post\'s zset', (done) => { - posts.uploads.sync(pid, (err) => { - assert.ifError(err); - - db.sortedSetCard(`post:${pid}:uploads`, (err, length) => { - assert.ifError(err); - assert.strictEqual(length, 2); - done(); - }); - }); - }); - - it('should remove an image if it is edited out of the post', (done) => { - async.series([ - function (next) { - posts.edit({ - pid: pid, - uid: 1, - content: 'here is an image [alt text](/assets/uploads/files/abracadabra.png)... AND NO MORE!', - }, next); - }, - async.apply(posts.uploads.sync, pid), - ], (err) => { - assert.ifError(err); - db.sortedSetCard(`post:${pid}:uploads`, (err, length) => { - assert.ifError(err); - assert.strictEqual(1, length); - done(); - }); - }); - }); - }); - - describe('.list()', () => { - it('should display the uploaded files for a specific post', (done) => { - posts.uploads.list(pid, (err, uploads) => { - assert.ifError(err); - assert.equal(true, Array.isArray(uploads)); - assert.strictEqual(1, uploads.length); - assert.equal('string', typeof uploads[0]); - done(); - }); - }); - }); - - describe('.isOrphan()', () => { - it('should return false if upload is not an orphan', (done) => { - posts.uploads.isOrphan('abracadabra.png', (err, isOrphan) => { - assert.ifError(err); - assert.equal(false, isOrphan); - done(); - }); - }); - - it('should return true if upload is an orphan', (done) => { - posts.uploads.isOrphan('shazam.jpg', (err, isOrphan) => { - assert.ifError(err); - assert.equal(true, isOrphan); - done(); - }); - }); - }); - - describe('.associate()', () => { - it('should add an image to the post\'s maintained list of uploads', (done) => { - async.waterfall([ - async.apply(posts.uploads.associate, pid, 'whoa.gif'), - async.apply(posts.uploads.list, pid), - ], (err, uploads) => { - assert.ifError(err); - assert.strictEqual(2, uploads.length); - assert.strictEqual(true, uploads.includes('whoa.gif')); - done(); - }); - }); - - it('should allow arrays to be passed in', (done) => { - async.waterfall([ - async.apply(posts.uploads.associate, pid, ['amazeballs.jpg', 'wut.txt']), - async.apply(posts.uploads.list, pid), - ], (err, uploads) => { - assert.ifError(err); - assert.strictEqual(4, uploads.length); - assert.strictEqual(true, uploads.includes('amazeballs.jpg')); - assert.strictEqual(true, uploads.includes('wut.txt')); - done(); - }); - }); - - it('should save a reverse association of md5sum to pid', (done) => { - const md5 = filename => crypto.createHash('md5').update(filename).digest('hex'); - - async.waterfall([ - async.apply(posts.uploads.associate, pid, ['test.bmp']), - function (next) { - db.getSortedSetRange(`upload:${md5('test.bmp')}:pids`, 0, -1, next); - }, - ], (err, pids) => { - assert.ifError(err); - assert.strictEqual(true, Array.isArray(pids)); - assert.strictEqual(true, pids.length > 0); - assert.equal(pid, pids[0]); - done(); - }); - }); - - it('should not associate a file that does not exist on the local disk', (done) => { - async.waterfall([ - async.apply(posts.uploads.associate, pid, ['nonexistant.xls']), - async.apply(posts.uploads.list, pid), - ], (err, uploads) => { - assert.ifError(err); - assert.strictEqual(uploads.length, 5); - assert.strictEqual(false, uploads.includes('nonexistant.xls')); - done(); - }); - }); - }); - - describe('.dissociate()', () => { - it('should remove an image from the post\'s maintained list of uploads', (done) => { - async.waterfall([ - async.apply(posts.uploads.dissociate, pid, 'whoa.gif'), - async.apply(posts.uploads.list, pid), - ], (err, uploads) => { - assert.ifError(err); - assert.strictEqual(4, uploads.length); - assert.strictEqual(false, uploads.includes('whoa.gif')); - done(); - }); - }); - - it('should allow arrays to be passed in', (done) => { - async.waterfall([ - async.apply(posts.uploads.dissociate, pid, ['amazeballs.jpg', 'wut.txt']), - async.apply(posts.uploads.list, pid), - ], (err, uploads) => { - assert.ifError(err); - assert.strictEqual(2, uploads.length); - assert.strictEqual(false, uploads.includes('amazeballs.jpg')); - assert.strictEqual(false, uploads.includes('wut.txt')); - done(); - }); - }); - }); - - describe('.dissociateAll()', () => { - it('should remove all images from a post\'s maintained list of uploads', async () => { - await posts.uploads.dissociateAll(pid); - const uploads = await posts.uploads.list(pid); - - assert.equal(uploads.length, 0); - }); - }); - - describe('Dissociation on purge', () => { - it('should not dissociate images on post deletion', async () => { - await posts.delete(purgePid, 1); - const uploads = await posts.uploads.list(purgePid); - - assert.equal(uploads.length, 2); - }); - - it('should dissociate images on post purge', async () => { - await posts.purge(purgePid, 1); - const uploads = await posts.uploads.list(purgePid); - - assert.equal(uploads.length, 0); - }); - }); - }); - - describe('post uploads management', () => { - let topic; - let reply; - before((done) => { - topics.post({ - uid: 1, - cid: cid, - title: 'topic to test uploads with', - content: '[abcdef](/assets/uploads/files/abracadabra.png)', - }, (err, topicPostData) => { - assert.ifError(err); - topics.reply({ - uid: 1, - tid: topicPostData.topicData.tid, - timestamp: Date.now(), - content: '[abcdef](/assets/uploads/files/shazam.jpg)', - }, (err, replyData) => { - assert.ifError(err); - topic = topicPostData; - reply = replyData; - done(); - }); - }); - }); - - it('should automatically sync uploads on topic create and reply', (done) => { - db.sortedSetsCard([`post:${topic.topicData.mainPid}:uploads`, `post:${reply.pid}:uploads`], (err, lengths) => { - assert.ifError(err); - assert.strictEqual(1, lengths[0]); - assert.strictEqual(1, lengths[1]); - done(); - }); - }); - - it('should automatically sync uploads on post edit', (done) => { - async.waterfall([ - async.apply(posts.edit, { - pid: reply.pid, - uid: 1, - content: 'no uploads', - }), - function (postData, next) { - posts.uploads.list(reply.pid, next); - }, - ], (err, uploads) => { - assert.ifError(err); - assert.strictEqual(true, Array.isArray(uploads)); - assert.strictEqual(0, uploads.length); - done(); - }); - }); - }); - describe('Topic Backlinks', () => { let tid1; before(async () => { @@ -1481,3 +1227,17 @@ describe('Post\'s', () => { }); }); }); + +describe('Posts\'', async () => { + let files; + + before(async () => { + files = await file.walk(path.resolve(__dirname, './posts')); + }); + + it('subfolder tests', () => { + files.forEach((filePath) => { + require(filePath); + }); + }); +}); diff --git a/test/posts/uploads.js b/test/posts/uploads.js new file mode 100644 index 0000000000..689ae8524f --- /dev/null +++ b/test/posts/uploads.js @@ -0,0 +1,296 @@ +'use strict'; + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); + +const nconf = require('nconf'); +const async = require('async'); +const crypto = require('crypto'); + +const db = require('../mocks/databasemock'); + +const categories = require('../../src/categories'); +const topics = require('../../src/topics'); +const posts = require('../../src/posts'); +const user = require('../../src/user'); + +describe('upload methods', () => { + let pid; + let purgePid; + let cid; + let uid; + + before(async () => { + // Create stub files for testing + ['abracadabra.png', 'shazam.jpg', 'whoa.gif', 'amazeballs.jpg', 'wut.txt', 'test.bmp'] + .forEach(filename => fs.closeSync(fs.openSync(path.join(nconf.get('upload_path'), 'files', filename), 'w'))); + + uid = await user.create({ + username: 'uploads user', + password: 'abracadabra', + gdpr_consent: 1, + }); + + ({ cid } = await categories.create({ + name: 'Test Category', + description: 'Test category created by testing script', + })); + + const topicPostData = await topics.post({ + uid, + cid, + title: 'topic with some images', + content: 'here is an image [alt text](/assets/uploads/files/abracadabra.png) and another [alt text](/assets/uploads/files/shazam.jpg)', + }); + pid = topicPostData.postData.pid; + + const purgePostData = await topics.post({ + uid, + cid, + title: 'topic with some images, to be purged', + content: 'here is an image [alt text](/assets/uploads/files/whoa.gif) and another [alt text](/assets/uploads/files/amazeballs.jpg)', + }); + purgePid = purgePostData.postData.pid; + }); + + describe('.sync()', () => { + it('should properly add new images to the post\'s zset', (done) => { + posts.uploads.sync(pid, (err) => { + assert.ifError(err); + + db.sortedSetCard(`post:${pid}:uploads`, (err, length) => { + assert.ifError(err); + assert.strictEqual(length, 2); + done(); + }); + }); + }); + + it('should remove an image if it is edited out of the post', (done) => { + async.series([ + function (next) { + posts.edit({ + pid: pid, + uid, + content: 'here is an image [alt text](/assets/uploads/files/abracadabra.png)... AND NO MORE!', + }, next); + }, + async.apply(posts.uploads.sync, pid), + ], (err) => { + assert.ifError(err); + db.sortedSetCard(`post:${pid}:uploads`, (err, length) => { + assert.ifError(err); + assert.strictEqual(1, length); + done(); + }); + }); + }); + }); + + describe('.list()', () => { + it('should display the uploaded files for a specific post', (done) => { + posts.uploads.list(pid, (err, uploads) => { + assert.ifError(err); + assert.equal(true, Array.isArray(uploads)); + assert.strictEqual(1, uploads.length); + assert.equal('string', typeof uploads[0]); + done(); + }); + }); + }); + + describe('.isOrphan()', () => { + it('should return false if upload is not an orphan', (done) => { + posts.uploads.isOrphan('abracadabra.png', (err, isOrphan) => { + assert.ifError(err); + assert.equal(isOrphan, false); + done(); + }); + }); + + it('should return true if upload is an orphan', (done) => { + posts.uploads.isOrphan('shazam.jpg', (err, isOrphan) => { + assert.ifError(err); + assert.equal(true, isOrphan); + done(); + }); + }); + }); + + describe('.associate()', () => { + it('should add an image to the post\'s maintained list of uploads', (done) => { + async.waterfall([ + async.apply(posts.uploads.associate, pid, 'whoa.gif'), + async.apply(posts.uploads.list, pid), + ], (err, uploads) => { + assert.ifError(err); + assert.strictEqual(2, uploads.length); + assert.strictEqual(true, uploads.includes('whoa.gif')); + done(); + }); + }); + + it('should allow arrays to be passed in', (done) => { + async.waterfall([ + async.apply(posts.uploads.associate, pid, ['amazeballs.jpg', 'wut.txt']), + async.apply(posts.uploads.list, pid), + ], (err, uploads) => { + assert.ifError(err); + assert.strictEqual(4, uploads.length); + assert.strictEqual(true, uploads.includes('amazeballs.jpg')); + assert.strictEqual(true, uploads.includes('wut.txt')); + done(); + }); + }); + + it('should save a reverse association of md5sum to pid', (done) => { + const md5 = filename => crypto.createHash('md5').update(filename).digest('hex'); + + async.waterfall([ + async.apply(posts.uploads.associate, pid, ['test.bmp']), + function (next) { + db.getSortedSetRange(`upload:${md5('test.bmp')}:pids`, 0, -1, next); + }, + ], (err, pids) => { + assert.ifError(err); + assert.strictEqual(true, Array.isArray(pids)); + assert.strictEqual(true, pids.length > 0); + assert.equal(pid, pids[0]); + done(); + }); + }); + + it('should not associate a file that does not exist on the local disk', (done) => { + async.waterfall([ + async.apply(posts.uploads.associate, pid, ['nonexistant.xls']), + async.apply(posts.uploads.list, pid), + ], (err, uploads) => { + assert.ifError(err); + assert.strictEqual(uploads.length, 5); + assert.strictEqual(false, uploads.includes('nonexistant.xls')); + done(); + }); + }); + }); + + describe('.dissociate()', () => { + it('should remove an image from the post\'s maintained list of uploads', (done) => { + async.waterfall([ + async.apply(posts.uploads.dissociate, pid, 'whoa.gif'), + async.apply(posts.uploads.list, pid), + ], (err, uploads) => { + assert.ifError(err); + assert.strictEqual(4, uploads.length); + assert.strictEqual(false, uploads.includes('whoa.gif')); + done(); + }); + }); + + it('should allow arrays to be passed in', (done) => { + async.waterfall([ + async.apply(posts.uploads.dissociate, pid, ['amazeballs.jpg', 'wut.txt']), + async.apply(posts.uploads.list, pid), + ], (err, uploads) => { + assert.ifError(err); + assert.strictEqual(2, uploads.length); + assert.strictEqual(false, uploads.includes('amazeballs.jpg')); + assert.strictEqual(false, uploads.includes('wut.txt')); + done(); + }); + }); + }); + + describe('.dissociateAll()', () => { + it('should remove all images from a post\'s maintained list of uploads', async () => { + await posts.uploads.dissociateAll(pid); + const uploads = await posts.uploads.list(pid); + + assert.equal(uploads.length, 0); + }); + }); + + describe('Dissociation on purge', () => { + it('should not dissociate images on post deletion', async () => { + await posts.delete(purgePid, 1); + const uploads = await posts.uploads.list(purgePid); + + assert.equal(uploads.length, 2); + }); + + it('should dissociate images on post purge', async () => { + await posts.purge(purgePid, 1); + const uploads = await posts.uploads.list(purgePid); + + assert.equal(uploads.length, 0); + }); + }); +}); + +describe('post uploads management', () => { + let topic; + let reply; + let uid; + let cid; + + before(async () => { + // Create stub files for testing + ['abracadabra.png', 'shazam.jpg', 'whoa.gif', 'amazeballs.jpg', 'wut.txt', 'test.bmp'] + .forEach(filename => fs.closeSync(fs.openSync(path.join(nconf.get('upload_path'), 'files', filename), 'w'))); + + uid = await user.create({ + username: 'uploads user', + password: 'abracadabra', + gdpr_consent: 1, + }); + + ({ cid } = await categories.create({ + name: 'Test Category', + description: 'Test category created by testing script', + })); + + const topicPostData = await topics.post({ + uid, + cid, + title: 'topic to test uploads with', + content: '[abcdef](/assets/uploads/files/abracadabra.png)', + }); + + const replyData = await topics.reply({ + uid, + tid: topicPostData.topicData.tid, + timestamp: Date.now(), + content: '[abcdef](/assets/uploads/files/shazam.jpg)', + }); + + topic = topicPostData; + reply = replyData; + }); + + it('should automatically sync uploads on topic create and reply', (done) => { + db.sortedSetsCard([`post:${topic.topicData.mainPid}:uploads`, `post:${reply.pid}:uploads`], (err, lengths) => { + assert.ifError(err); + assert.strictEqual(lengths[0], 1); + assert.strictEqual(lengths[1], 1); + done(); + }); + }); + + it('should automatically sync uploads on post edit', (done) => { + async.waterfall([ + async.apply(posts.edit, { + pid: reply.pid, + uid, + content: 'no uploads', + }), + function (postData, next) { + posts.uploads.list(reply.pid, next); + }, + ], (err, uploads) => { + assert.ifError(err); + assert.strictEqual(true, Array.isArray(uploads)); + assert.strictEqual(0, uploads.length); + done(); + }); + }); +}); diff --git a/test/topics.js b/test/topics.js index 8eeb821ce5..44587639bc 100644 --- a/test/topics.js +++ b/test/topics.js @@ -2830,7 +2830,7 @@ describe('Topic\'s', () => { }); }); -describe('Topics\'s', async () => { +describe('Topics\'', async () => { let files; before(async () => {