1. 1var sqlite3 = require('..');
2. 1var assert = require('assert');
3. 1var fs = require('fs');
4. 1var helper = require('./support/helper');
5. 1
6. 1// Check that the number of rows in two tables matches.
7. 3function assertRowsMatchDb(db1, table1, db2, table2, done) {
8. 3 db1.get("SELECT COUNT(*) as count FROM " + table1, function(err, row) {
9. 0 if (err) throw err;
10. 3 db2.get("SELECT COUNT(*) as count FROM " + table2, function(err, row2) {
11. 0 if (err) throw err;
12. 3 assert.equal(row.count, row2.count);
13. 3 done();
14. 3 });
15. 3 });
16. 3}
17. 1
18. 1// Check that the number of rows in the table "foo" is preserved in a backup.
19. 2function assertRowsMatchFile(db, backupName, done) {
20. 2 var db2 = new sqlite3.Database(backupName, sqlite3.OPEN_READONLY, function(err) {
21. 0 if (err) throw err;
22. 2 assertRowsMatchDb(db, 'foo', db2, 'foo', function() {
23. 2 db2.close(done);
24. 2 });
25. 2 });
26. 2}
27. 1
28. 1describe('backup', function() {
29. 1 before(function() {
30. 1 helper.ensureExists('test/tmp');
31. 1 });
32. 1
33. 1 var db;
34. 14 beforeEach(function(done) {
35. 14 helper.deleteFile('test/tmp/backup.db');
36. 14 helper.deleteFile('test/tmp/backup2.db');
37. 14 db = new sqlite3.Database('test/support/prepare.db', sqlite3.OPEN_READONLY, done);
38. 14 });
39. 1
40. 14 afterEach(function(done) {
41. 3 if (!db) { done(); }
42. 14 db.close(done);
43. 14 });
44. 1
45. 1 it ('output db created once step is called', function(done) {
46. 1 var backup = db.backup('test/tmp/backup.db', function(err) {
47. 0 if (err) throw err;
48. 1 backup.step(1, function(err) {
49. 0 if (err) throw err;
50. 1 assert.fileExists('test/tmp/backup.db');
51. 1 backup.finish(done);
52. 1 });
53. 1 });
54. 1 });
55. 1
56. 1 it ('copies source fully with step(-1)', function(done) {
57. 1 var backup = db.backup('test/tmp/backup.db');
58. 1 backup.step(-1, function(err) {
59. 0 if (err) throw err;
60. 1 assert.fileExists('test/tmp/backup.db');
61. 1 backup.finish(function(err) {
62. 0 if (err) throw err;
63. 1 assertRowsMatchFile(db, 'test/tmp/backup.db', done);
64. 1 });
65. 1 });
66. 1 });
67. 1
68. 1 it ('backup db not created if finished immediately', function(done) {
69. 1 var backup = db.backup('test/tmp/backup.db');
70. 1 backup.finish(function(err) {
71. 0 if (err) throw err;
72. 1 assert.fileDoesNotExist('test/tmp/backup.db');
73. 1 done();
74. 1 });
75. 1 });
76. 1
77. 1 it ('error closing db if backup not finished', function(done) {
78. 1 var backup = db.backup('test/tmp/backup.db');
79. 1 db.close(function(err) {
80. 1 db = null;
81. 0 if (!err) throw new Error('should have an error');
82. 1 if (err.errno == sqlite3.BUSY) {
83. 1 done();
84. 0 }
85. 0 else throw err;
86. 1 });
87. 1 });
88. 1
89. 1 it ('using the backup after finished is an error', function(done) {
90. 1 var backup = db.backup('test/tmp/backup.db');
91. 1 backup.finish(function(err) {
92. 0 if (err) throw err;
93. 1 backup.step(1, function(err) {
94. 0 if (!err) throw new Error('should have an error');
95. 1 if (err.errno == sqlite3.MISUSE &&
96. 1 err.message === 'SQLITE_MISUSE: Backup is already finished') {
97. 1 done();
98. 0 }
99. 0 else throw err;
100. 1 });
101. 1 });
102. 1 });
103. 1
104. 1 it ('remaining/pageCount are available after call to step', function(done) {
105. 1 var backup = db.backup('test/tmp/backup.db');
106. 1 backup.step(0, function(err) {
107. 0 if (err) throw err;
108. 1 assert.equal(typeof this.pageCount, 'number');
109. 1 assert.equal(typeof this.remaining, 'number');
110. 1 assert.equal(this.remaining, this.pageCount);
111. 1 var prevRemaining = this.remaining;
112. 1 var prevPageCount = this.pageCount;
113. 1 backup.step(1, function(err) {
114. 0 if (err) throw err;
115. 1 assert.notEqual(this.remaining, prevRemaining);
116. 1 assert.equal(this.pageCount, prevPageCount);
117. 1 backup.finish(done);
118. 1 });
119. 1 });
120. 1 });
121. 1
122. 1 it ('backup works if database is modified half-way through', function(done) {
123. 1 var backup = db.backup('test/tmp/backup.db');
124. 1 backup.step(-1, function(err) {
125. 0 if (err) throw err;
126. 1 backup.finish(function(err) {
127. 0 if (err) throw err;
128. 1 var db2 = new sqlite3.Database('test/tmp/backup.db', function(err) {
129. 0 if (err) throw err;
130. 1 var backup2 = db2.backup('test/tmp/backup2.db');
131. 1 backup2.step(1, function(err, completed) {
132. 0 if (err) throw err;
133. 1 assert.equal(completed, false); // Page size for the test db
134. 1 // should not be raised to high.
135. 1 db2.exec("insert into foo(txt) values('hello')", function(err) {
136. 0 if (err) throw err;
137. 1 backup2.step(-1, function(err, completed) {
138. 0 if (err) throw err;
139. 1 assert.equal(completed, true);
140. 1 assertRowsMatchFile(db2, 'test/tmp/backup2.db', function() {
141. 1 backup2.finish(function(err) {
142. 0 if (err) throw err;
143. 1 db2.close(done);
144. 1 });
145. 1 });
146. 1 });
147. 1 });
148. 1 });
149. 1 });
150. 1 });
151. 1 });
152. 1 });
153. 1
154. 0 (sqlite3.VERSION_NUMBER < 3026000 ? it.skip : it) ('can backup from temp to main', function(done) {
155. 1 db.exec("CREATE TEMP TABLE space (txt TEXT)", function(err) {
156. 0 if (err) throw err;
157. 1 db.exec("INSERT INTO space(txt) VALUES('monkey')", function(err) {
158. 0 if (err) throw err;
159. 1 var backup = db.backup('test/tmp/backup.db', 'temp', 'main', true, function(err) {
160. 0 if (err) throw err;
161. 1 backup.step(-1, function(err) {
162. 0 if (err) throw err;
163. 1 backup.finish(function(err) {
164. 0 if (err) throw err;
165. 1 var db2 = new sqlite3.Database('test/tmp/backup.db', function(err) {
166. 0 if (err) throw err;
167. 1 db2.get("SELECT * FROM space", function(err, row) {
168. 0 if (err) throw err;
169. 1 assert.equal(row.txt, 'monkey');
170. 1 db2.close(done);
171. 1 });
172. 1 });
173. 1 });
174. 1 });
175. 1 });
176. 1 });
177. 1 });
178. 1 });
179. 1
180. 0 (sqlite3.VERSION_NUMBER < 3026000 ? it.skip : it) ('can backup from main to temp', function(done) {
181. 1 var backup = db.backup('test/support/prepare.db', 'main', 'temp', false, function(err) {
182. 0 if (err) throw err;
183. 1 backup.step(-1, function(err) {
184. 0 if (err) throw err;
185. 1 backup.finish(function(err) {
186. 0 if (err) throw err;
187. 1 assertRowsMatchDb(db, 'temp.foo', db, 'main.foo', done);
188. 1 });
189. 1 });
190. 1 });
191. 1 });
192. 1
193. 1 it ('cannot backup to a locked db', function(done) {
194. 1 var db2 = new sqlite3.Database('test/tmp/backup.db', function(err) {
195. 1 db2.exec("PRAGMA locking_mode = EXCLUSIVE");
196. 1 db2.exec("BEGIN EXCLUSIVE", function(err) {
197. 0 if (err) throw err;
198. 1 var backup = db.backup('test/tmp/backup.db');
199. 1 backup.step(-1, function(stepErr) {
200. 1 db2.close(function(err) {
201. 0 if (err) throw err;
202. 1 if (stepErr.errno == sqlite3.BUSY) {
203. 1 backup.finish(done);
204. 0 }
205. 0 else throw stepErr;
206. 1 });
207. 1 });
208. 1 });
209. 1 });
210. 1 });
211. 1
212. 1 it ('fuss-free incremental backups work', function(done) {
213. 1 var backup = db.backup('test/tmp/backup.db');
214. 1 var timer;
215. 81 function makeProgress() {
216. 80 if (backup.idle) {
217. 80 backup.step(1);
218. 80 }
219. 80 if (backup.completed || backup.failed) {
220. 1 clearInterval(timer);
221. 1 assert.equal(backup.completed, true);
222. 1 assert.equal(backup.failed, false);
223. 1 done();
224. 1 }
225. 81 }
226. 1 timer = setInterval(makeProgress, 2);
227. 1 });
228. 1
229. 1 it ('setting retryErrors to empty disables automatic finishing', function(done) {
230. 1 var backup = db.backup('test/tmp/backup.db');
231. 1 backup.retryErrors = [];
232. 1 backup.step(-1, function(err) {
233. 0 if (err) throw err;
234. 1 db.close(function(err) {
235. 1 db = null;
236. 0 if (!err) throw new Error('should have an error');
237. 1 assert.equal(err.errno, sqlite3.BUSY);
238. 1 done();
239. 1 });
240. 1 });
241. 1 });
242. 1
243. 1 it ('setting retryErrors enables automatic finishing', function(done) {
244. 1 var backup = db.backup('test/tmp/backup.db');
245. 1 backup.retryErrors = [sqlite3.OK];
246. 1 backup.step(-1, function(err) {
247. 0 if (err) throw err;
248. 1 db.close(function(err) {
249. 0 if (err) throw err;
250. 1 db = null;
251. 1 done();
252. 1 });
253. 1 });
254. 1 });
255. 1
256. 1 it ('default retryErrors will retry on a locked/busy db', function(done) {
257. 1 var db2 = new sqlite3.Database('test/tmp/backup.db', function(err) {
258. 1 db2.exec("PRAGMA locking_mode = EXCLUSIVE");
259. 1 db2.exec("BEGIN EXCLUSIVE", function(err) {
260. 0 if (err) throw err;
261. 1 var backup = db.backup('test/tmp/backup.db');
262. 1 backup.step(-1, function(stepErr) {
263. 1 db2.close(function(err) {
264. 0 if (err) throw err;
265. 1 assert.equal(stepErr.errno, sqlite3.BUSY);
266. 1 assert.equal(backup.completed, false);
267. 1 assert.equal(backup.failed, false);
268. 1 backup.step(-1, function(err) {
269. 0 if (err) throw err;
270. 1 assert.equal(backup.completed, true);
271. 1 assert.equal(backup.failed, false);
272. 1 done();
273. 1 });
274. 1 });
275. 1 });
276. 1 });
277. 1 });
278. 1 });
279. 1});
280. 1