blob: de136a743e85b735e75ef4ff124fa3aec1f502c4 [file] [log] [blame]
'use strict';
var adapters = ['local', 'http'];
var repl_adapters = [
['local', 'http'],
['http', 'http'],
['http', 'local'],
['local', 'local']
];
adapters.forEach(function (adapter) {
describe('test.attachments.js-' + adapter, function () {
var dbs = {};
beforeEach(function (done) {
dbs.name = testUtils.adapterUrl(adapter, 'testdb');
testUtils.cleanup([dbs.name], done);
});
after(function (done) {
testUtils.cleanup([dbs.name], done);
});
var binAttDoc = {
_id: 'bin_doc',
_attachments: {
'foo.txt': {
content_type: 'text/plain',
data: 'VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ='
}
}
};
// empty attachment
var binAttDoc2 = {
_id: 'bin_doc2',
_attachments: {
'foo.txt': {
content_type: 'text/plain',
data: ''
}
}
};
// json string doc
var jsonDoc = {
_id: 'json_doc',
_attachments: {
'foo.json': {
content_type: 'application/json',
data: 'eyJIZWxsbyI6IndvcmxkIn0='
}
}
};
var pngAttDoc = {
_id: 'png_doc',
_attachments: {
'foo.png': {
content_type: 'image/png',
data: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAMFBMVEX+9+' +
'j+9OD+7tL95rr93qT80YD7x2L6vkn6syz5qRT4ogT4nwD4ngD4nQD4nQD4' +
'nQDT2nT/AAAAcElEQVQY002OUQLEQARDw1D14f7X3TCdbfPnhQTqI5UqvG' +
'OWIz8gAIXFH9zmC63XRyTsOsCWk2A9Ga7wCXlA9m2S6G4JlVwQkpw/Ymxr' +
'UgNoMoyxBwSMH/WnAzy5cnfLFu+dK2l5gMvuPGLGJd1/9AOiBQiEgkzOpg' +
'AAAABJRU5ErkJggg=='
}
}
};
it('Test some attachments', function (done) {
var db = new PouchDB(dbs.name);
db.put(binAttDoc, function (err, write) {
should.not.exist(err, 'saved doc with attachment');
db.get('bin_doc', function (err, doc) {
should.exist(doc._attachments, 'doc has attachments field');
should.exist(doc._attachments['foo.txt'], 'doc has attachment');
doc._attachments['foo.txt'].content_type.should.equal('text/plain');
db.getAttachment('bin_doc', 'foo.txt', function (err, res) {
testUtils.readBlob(res, function (data) {
data.should.equal('This is a base64 encoded text');
db.put(binAttDoc2, function (err, rev) {
db.getAttachment('bin_doc2', 'foo.txt',
function (err, res, xhr) {
testUtils.readBlob(res, function (data) {
data.should.equal('', 'Correct data returned');
moreTests(rev.rev);
});
});
});
});
});
});
});
function moreTests(rev) {
var blob = testUtils.makeBlob('This is no base64 encoded text');
db.putAttachment('bin_doc2', 'foo2.txt', rev, blob, 'text/plain',
function (err, info) {
info.ok.should.equal(true);
db.getAttachment('bin_doc2', 'foo2.txt', function (err, res, xhr) {
testUtils.readBlob(res, function (data) {
should.exist(data);
db.get('bin_doc2', { attachments: true },
function (err, res, xhr) {
should.exist(res._attachments, 'Result has attachments field');
should.not
.exist(res._attachments['foo2.txt'].stub, 'stub is false');
res._attachments['foo2.txt'].data.should
.equal('VGhpcyBpcyBubyBiYXNlNjQgZW5jb2RlZCB0ZXh0');
res._attachments['foo2.txt'].content_type.should
.equal('text/plain');
res._attachments['foo.txt'].data.should.equal('');
done();
});
});
});
});
}
});
it('Test getAttachment', function (done) {
var db = new PouchDB(dbs.name);
db.put(binAttDoc, function (err, res) {
db.getAttachment('bin_doc', 'foo.txt', function (err, res) {
if (err) {
return done(err);
}
testUtils.readBlob(res, function (data) {
data.should.equal('This is a base64 encoded text', 'correct data');
done();
});
});
});
});
it('Test attachments in allDocs/changes', function (done) {
var db = new PouchDB(dbs.name);
var docs = [
{ _id: 'doc0' },
{
_id: 'doc1',
_attachments: {
'att0': {
data: 'YXR0YWNobWVudDA=',
content_type: 'text/plain'
}
}
},
{
_id: 'doc2',
_attachments: {
'att0': {
data: 'YXR0YWNobWVudDA=',
content_type: 'text/plain'
},
'att1': {
data: 'YXR0YWNobWVudDE=',
content_type: 'text/plain'
}
}
},
{
_id: 'doc3',
_attachments: {
'att0': {
data: 'YXR0YWNobWVudDA=',
content_type: 'text/plain'
}
}
}
];
function sort(a, b) {
return a.id.localeCompare(b.id);
}
db.bulkDocs({ docs: docs }, function (err, res) {
db.allDocs({ include_docs: true }, function (err, res) {
for (var i = 0; i < docs.length; i++) {
var attachmentsNb = typeof docs[i]._attachments !== 'undefined' ?
Object.keys(docs[i]._attachments).length : 0;
for (var j = 0; j < attachmentsNb; j++) {
res.rows[i].doc._attachments['att' + j].stub.should
.equal(true, '(allDocs) doc' + i + ' contains att' + j +
' stub');
}
}
should.not.exist(res.rows[0].doc._attachments,
'(allDocs) doc0 contains no attachments');
db.changes({
include_docs: true,
onChange: function (change) {
var i = +change.id.substr(3);
if (i === 0) {
should.not.exist(res.rows[0].doc._attachments,
'(onChange) doc0 contains no attachments');
} else {
var attachmentsNb =
typeof docs[i]._attachments !== 'undefined' ?
Object.keys(docs[i]._attachments).length : 0;
for (var j = 0; j < attachmentsNb; j++) {
res.rows[i].doc._attachments['att' + j].stub.should
.equal(true, '(onChange) doc' + i + ' contains att' + j +
' stub');
}
}
},
complete: function (err, res) {
var attachmentsNb = 0;
res.results.sort(sort);
for (var i = 0; i < 3; i++) {
attachmentsNb = typeof docs[i]._attachments !== 'undefined' ?
Object.keys(docs[i]._attachments).length : 0;
for (var j = 0; j < attachmentsNb; j++) {
res.results[i].doc._attachments['att' + j].stub.should
.equal(true, '(complete) doc' + i + ' contains att' + j +
' stub');
}
}
should.not.exist(res.results[0].doc._attachments,
'(complete) doc0 contains no attachments');
done();
}
});
});
});
});
it('Test getAttachment with PNG', function (done) {
var db = new PouchDB(dbs.name);
db.put(pngAttDoc, function (err, res) {
if (err) { return done(err); }
db.getAttachment('png_doc', 'foo.png', function (err, res) {
if (err) { return done(err); }
testUtils.base64Blob(res, function (data) {
data.should
.equal(pngAttDoc._attachments['foo.png'].data, 'correct data');
done();
});
});
});
});
it('Test postAttachment with PNG then bulkDocs', function (done) {
var db = new PouchDB(dbs.name);
db.put({ _id: 'foo' }, function (err, res) {
db.get('foo', function (err, doc) {
var data = pngAttDoc._attachments['foo.png'].data;
var blob = testUtils
.makeBlob(PouchDB.utils.fixBinary(PouchDB.utils.atob(data)),
'image/png');
db.putAttachment('foo', 'foo.png', doc._rev, blob, 'image/png',
function (err, info) {
should.not.exist(err, 'attachment inserted');
db.bulkDocs([{}], function (err) {
should.not.exist(err, 'doc inserted');
done();
});
});
});
});
});
it('Testing with invalid docs', function (done) {
var db = new PouchDB(dbs.name);
var invalidDoc = {
'_id': '_invalid',
foo: 'bar'
};
db.bulkDocs({
docs: [
invalidDoc,
binAttDoc
]
}, function (err, info) {
should.exist(err, 'bad request');
done();
});
});
it('Test create attachment and doc in one go', function (done) {
var db = new PouchDB(dbs.name);
var blob = testUtils.makeBlob('Mytext');
db.putAttachment('anotherdoc', 'mytext', blob, 'text/plain',
function (err, res) {
should.exist(res.ok);
done();
});
});
it('Test create attachment and doc in one go without callback',
function (done) {
var db = new PouchDB(dbs.name);
var changes = db.changes({
complete: function (err, result) {
result.status.should.equal('cancelled');
done();
},
live: true,
onChange: function (change) {
if (change.seq === 1) {
change.id.should.equal('anotherdoc2', 'Doc has been created');
db.get(change.id, { attachments: true }, function (err, doc) {
doc._attachments.should.be
.an('object', 'doc has attachments object');
should.exist(doc._attachments.mytext,
'doc has attachments attachment');
doc._attachments.mytext.data.should
.equal('TXl0ZXh0', 'doc has attachments attachment');
changes.cancel();
});
}
}
});
var blob = testUtils.makeBlob('Mytext');
db.putAttachment('anotherdoc2', 'mytext', blob, 'text/plain');
});
it('Test create attachment without callback', function (done) {
var db = new PouchDB(dbs.name);
db.put({ _id: 'anotherdoc3' }, function (err, resp) {
should.not.exist(err, 'doc was saved');
var changes = db.changes({
complete: function (err, result) {
result.status.should.equal('cancelled');
done();
},
live: true,
include_docs: true,
onChange: function (change) {
if (change.seq === 2) {
change.id.should.equal('anotherdoc3', 'Doc has been created');
db.get(change.id, { attachments: true }, function (err, doc) {
doc._attachments.should.be.an('object',
'doc has attachments object');
should.exist(doc._attachments.mytext);
doc._attachments.mytext.data.should.equal('TXl0ZXh0');
changes.cancel();
});
}
}
});
var blob = testUtils.makeBlob('Mytext');
db.putAttachment('anotherdoc3', 'mytext', resp.rev, blob, 'text/plain');
});
});
it('Test put attachment on a doc without attachments', function (done) {
var db = new PouchDB(dbs.name);
db.put({ _id: 'mydoc' }, function (err, resp) {
var blob = testUtils.makeBlob('Mytext');
db.putAttachment('mydoc', 'mytext', resp.rev, blob, 'text/plain',
function (err, res) {
should.exist(res.ok);
done();
});
});
});
it('Testing with invalid rev', function (done) {
var db = new PouchDB(dbs.name);
var doc = { _id: 'adoc' };
db.put(doc, function (err, resp) {
should.not.exist(err, 'Doc has been saved');
doc._rev = resp.rev;
doc.foo = 'bar';
db.put(doc, function (err, resp) {
should.not.exist(err, 'Doc has been updated');
var blob = testUtils.makeBlob('bar');
db.putAttachment('adoc', 'foo.txt', doc._rev, blob, 'text/plain',
function (err) {
should.exist(err, 'Attachment has not been saved');
err.name.should.equal('conflict', 'error is a conflict');
done();
});
});
});
});
it('Test put another attachment on a doc with attachments',
function (done) {
var db = new PouchDB(dbs.name);
db.put({ _id: 'mydoc' }, function (err, res1) {
var blob = testUtils.makeBlob('Mytext');
db.putAttachment('mydoc', 'mytext', res1.rev, blob, 'text/plain',
function (err, res2) {
db.putAttachment('mydoc', 'mytext2', res2.rev, blob, 'text/plain',
function (err, res3) {
should.exist(res3.ok);
done();
});
});
});
});
it('Test get with attachments: true if empty attachments', function (done) {
var db = new PouchDB(dbs.name);
db.put({
_id: 'foo',
_attachments: {}
}, function (err, resp) {
db.get('foo', { attachments: true }, function (err, res) {
res._id.should.equal('foo');
done();
});
});
});
it('Test delete attachment from a doc', function (done) {
var db = new PouchDB(dbs.name);
db.put({
_id: 'mydoc',
_attachments: {
'mytext1': {
content_type: 'text/plain',
data: 'TXl0ZXh0MQ=='
},
'mytext2': {
content_type: 'text/plain',
data: 'TXl0ZXh0Mg=='
}
}
}, function (err, res) {
var rev = res.rev;
db.get('mydoc', { attachments: true }, function (err, res) {
res._attachments.should.include.keys('mytext1', 'mytext2');
db.removeAttachment('mydoc', 'mytext1', 0, function (err, res) {
should.exist(err, 'removal should fail due to broken rev');
db.removeAttachment('mydoc', 'mytext1', rev, function (err, res) {
db.get('mydoc', { attachments: true }, function (err, res) {
res._attachments.should.not.include.keys('mytext1');
res._attachments.should.include.keys('mytext2');
db.removeAttachment('mydoc', 'mytext2', res._rev,
function (err, res) {
should.not.exist(res._attachments);
done();
});
});
});
});
});
});
});
it('Test a document with a json string attachment', function (done) {
var db = new PouchDB(dbs.name);
db.put(jsonDoc, function (err, results) {
should.not.exist(err, 'saved doc with attachment');
db.get(results.id, function (err, doc) {
should.not.exist(err, 'fetched doc');
should.exist(doc._attachments, 'doc has attachments field');
doc._attachments.should.include.keys('foo.json');
doc._attachments['foo.json'].content_type.should
.equal('application/json', 'doc has correct content type');
db.getAttachment(results.id, 'foo.json', function (err, attachment) {
testUtils.readBlob(attachment, function (data) {
jsonDoc._attachments['foo.json'].data.should
.equal('eyJIZWxsbyI6IndvcmxkIn0=', 'correct data');
done();
});
});
});
});
});
it('Test remove doc with attachment', function (done) {
var db = new PouchDB(dbs.name);
db.put({ _id: 'mydoc' }, function (err, resp) {
var blob = testUtils.makeBlob('Mytext');
db.putAttachment('mydoc', 'mytext', resp.rev, blob, 'text/plain',
function (err, res) {
db.get('mydoc', { attachments: false }, function (err, doc) {
db.remove(doc, function (err, resp) {
should.exist(res.ok);
done();
});
});
});
});
});
it('Try to insert a doc with unencoded attachment', function (done) {
var db = new PouchDB(dbs.name);
var doc = {
_id: 'foo',
_attachments: {
'foo.txt': {
content_type: 'text/plain',
data: 'this should have been encoded!'
}
}
};
db.put(doc, function (err, res) {
should.exist(err);
err.status.should.equal(500, 'correct error');
err.name.should.equal('badarg', 'correct error');
done();
});
});
it('Try to get attachment of unexistent doc', function (done) {
var db = new PouchDB(dbs.name);
db.getAttachment('unexistent', 'attachment', function (err, res) {
should.exist(err, 'Correctly returned error');
done();
});
});
it('Test synchronous getAttachment', function (done) {
var db = new PouchDB(dbs.name);
db.getAttachment('unexistent', 'attachment', function (err, res) {
should.exist(err, 'Correctly returned error');
done();
});
});
it('Test synchronous putAttachment with text data', function (done) {
var db = new PouchDB(dbs.name);
var blob = testUtils.makeBlob('foobaz', 'text/plain');
db.putAttachment('a', 'foo2.txt', '', blob, 'text/plain', function (err) {
should.not.exist(err, 'Correctly wrote attachment');
db.get('a', { attachments: true }, function (err, doc) {
should.not.exist(err, 'Correctly got attachment');
doc._attachments['foo2.txt'].data.should.equal('Zm9vYmF6');
doc._attachments['foo2.txt'].content_type.should.equal('text/plain');
done();
});
});
});
it('Test synchronous putAttachment with no text data', function (done) {
var db = new PouchDB(dbs.name);
db.putAttachment('a', 'foo2.txt', '', '', 'text/plain', function (err) {
should.not.exist(err, 'Correctly wrote attachment');
db.get('a', { attachments: true }, function (err, doc) {
should.not.exist(err, 'Correctly got attachment');
doc._attachments['foo2.txt'].data.should.equal('');
// firefox 3 appends charset=utf8
// see http://forums.mozillazine.org/viewtopic.php?p=6318215#p6318215
doc._attachments['foo2.txt'].content_type.indexOf('text/plain')
.should.equal(0, 'expected content-type to start with text/plain');
done();
});
});
});
it('Test stubs', function (done) {
var db = new PouchDB(dbs.name);
db.putAttachment('a', 'foo2.txt', '', '', 'text/plain', function (err) {
db.allDocs({ include_docs: true }, function (err, docs) {
should.not.exist(docs.rows[0].stub, 'no stub');
done();
});
});
});
it('Try to get unexistent attachment of some doc', function (done) {
var db = new PouchDB(dbs.name);
db.put({ _id: 'foo' }, function (err, res) {
should.not.exist(err, 'doc inserted');
db.getAttachment('foo', 'unexistentAttachment', function (err, res) {
should.exist(err, 'Correctly returned error');
done();
});
});
});
it('putAttachment and getAttachment with png data', function (done) {
var db = new PouchDB(dbs.name);
db.put({ _id: 'foo' }, function (err, res) {
db.get('foo', function (err, doc) {
var data = pngAttDoc._attachments['foo.png'].data;
var blob = testUtils
.makeBlob(PouchDB.utils.fixBinary(PouchDB.utils.atob(data)),
'image/png');
db.putAttachment('foo', 'foo.png', doc._rev, blob, 'image/png',
function (err, info) {
should.not.exist(err, 'attachment inserted');
db.getAttachment('foo', 'foo.png', function (err, blob) {
should.not.exist(err, 'attachment gotten');
testUtils.readBlob(blob, function (returnedData) {
PouchDB.utils.btoa(returnedData).should.equal(data);
done();
});
});
});
});
});
});
var isSafari = (typeof process === 'undefined' || process.browser) &&
/Safari/.test(window.navigator.userAgent) &&
!/Chrome/.test(window.navigator.userAgent);
if (!isSafari) {
// skip in safari/ios because of size limit popup
it('putAttachment and getAttachment with big png data', function (done) {
this.timeout(20000);
function getData(cb) {
if (typeof process !== 'undefined' && !process.browser) {
var bigimage = require('./deps/bigimage.js');
cb(null, bigimage);
} else { // browser
var script = document.createElement('script');
script.src = 'deps/bigimage.js';
document.body.appendChild(script);
var timeout = setInterval(function () {
if (!!window.bigimage) {
clearInterval(timeout);
cb(null, window.bigimage);
}
}, 500);
}
}
var db = new PouchDB(dbs.name);
db.put({ _id: 'foo' }, function (err, res) {
db.get('foo', function (err, doc) {
getData(function (err, data) {
var blob = testUtils
.makeBlob(PouchDB.utils.fixBinary(PouchDB.utils.atob(data)),
'image/png');
db.putAttachment('foo', 'foo.png', doc._rev, blob, 'image/png',
function (err, info) {
should.not.exist(err, 'attachment inserted');
db.getAttachment('foo', 'foo.png', function (err, blob) {
should.not.exist(err, 'attachment gotten');
testUtils.readBlob(blob, function (returnedData) {
PouchDB.utils.btoa(returnedData).should.equal(data);
done();
});
});
});
});
});
});
});
}
});
});
repl_adapters.forEach(function (adapters) {
describe('test.attachments.js- ' + adapters[0] + ':' + adapters[1],
function () {
var dbs = {};
beforeEach(function (done) {
dbs.name = testUtils.adapterUrl(adapters[0], 'testdb');
dbs.remote = testUtils.adapterUrl(adapters[1], 'test_attach_remote');
testUtils.cleanup([dbs.name, dbs.remote], done);
});
afterEach(function (done) {
testUtils.cleanup([dbs.name, dbs.remote], done);
});
it('Attachments replicate', function (done) {
var binAttDoc = {
_id: 'bin_doc',
_attachments: {
'foo.txt': {
content_type: 'text/plain',
data: 'VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ='
}
}
};
var docs1 = [
binAttDoc,
{_id: '0', integer: 0},
{_id: '1', integer: 1},
{_id: '2', integer: 2},
{_id: '3', integer: 3}
];
var db = new PouchDB(dbs.name);
var remote = new PouchDB(dbs.remote);
remote.bulkDocs({ docs: docs1 }, function (err, info) {
db.replicate.from(remote, function () {
db.get('bin_doc', { attachments: true }, function (err, doc) {
binAttDoc._attachments['foo.txt'].data.should
.equal(doc._attachments['foo.txt'].data);
done();
});
});
});
});
it('Multiple attachments replicate', function () {
var doc = {_id: 'foo'};
var db = new PouchDB(dbs.name);
var remote = new PouchDB(dbs.remote);
var data = 'VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ=';
var rev;
return db.put(doc).then(function (info) {
rev = info.rev;
return db.replicate.to(remote);
}).then(function () {
return db.putAttachment(doc._id, 'foo1.txt', rev, data, 'text/plain');
}).then(function (info) {
rev = info.rev;
return db.putAttachment(doc._id, 'foo2.txt', rev, data, 'text/plain');
}).then(function (info) {
rev = info.rev;
return db.putAttachment(doc._id, 'foo3.txt', rev, data, 'text/plain');
}).then(function () {
return db.replicate.to(remote);
}).then(function () {
return remote.get('foo', {attachments: true});
}).then(function (doc) {
var keys = Object.keys(doc._attachments);
keys.sort();
keys.should.deep.equal(['foo1.txt', 'foo2.txt', 'foo3.txt']);
});
});
});
});