Skip to content

Commit 16f4e8b

Browse files
committed
graceful cleanup closes #8
1 parent bc94221 commit 16f4e8b

File tree

8 files changed

+196
-83
lines changed

8 files changed

+196
-83
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,17 @@ tmp.tmpName({ template: '/tmp/tmp-XXXXXX' }, function _tempNameGenerated(err, pa
130130
});
131131
```
132132

133+
## Graceful cleanup
134+
135+
One may want to cleanup the temporary files even when an uncaught exception
136+
occurs. To enforce this, you can call the `setGracefulCleanup()` method:
137+
138+
```javascript
139+
var tmp = require('tmp');
140+
141+
tmp.setGracefulCleanup();
142+
```
143+
133144
## Options
134145

135146
All options are optional :)

lib/tmp.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,13 @@ function _garbageCollector() {
213213
}
214214
}
215215

216+
function _gracefulCleanup() {
217+
process.on('uncaughtException', function (err) {
218+
_garbageCollector();
219+
throw err;
220+
});
221+
}
222+
216223
// adding to the exit listener
217224
process.addListener('exit', _garbageCollector);
218225

@@ -221,3 +228,4 @@ module.exports.tmpdir = _TMP;
221228
module.exports.dir = _createTmpDir;
222229
module.exports.file = _createTmpFile;
223230
module.exports.tmpName = _getTmpName;
231+
module.exports.setGracefulCleanup = _gracefulCleanup;

test/base.js

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,60 @@
11
var
22
assert = require('assert'),
33
path = require('path'),
4-
spawn = require('child_process').spawn;
4+
exec = require('child_process').exec;
5+
6+
function _spawnTest(passError, testFile, params, cb) {
7+
var
8+
filename,
9+
command = [ 'node', path.join(__dirname, testFile) ].concat(params).join(' ');
10+
11+
exec(command, function _execDone(err, stdout, stderr) {
12+
if (passError) {
13+
if (err) {
14+
return cb(err);
15+
} else if (stderr.length > 0) {
16+
return cb(stderr.toString());
17+
}
18+
}
19+
20+
return cb(null, stdout.toString());
21+
});
22+
}
523

624
function _testStat(stat, mode) {
7-
assert.equal(stat.uid, process.getuid(), 'Should have the same UID');
8-
assert.equal(stat.gid, process.getgid(), 'Should have the same GUID');
25+
assert.equal(stat.uid, process.getuid(), 'should have the same UID');
26+
assert.equal(stat.gid, process.getgid(), 'should have the same GUID');
927
assert.equal(stat.mode, mode);
1028
}
1129

1230
function _testPrefix(prefix) {
1331
return function _testPrefixGenerated(err, name, fd) {
14-
assert.equal(path.basename(name).slice(0, prefix.length), prefix, 'Should have the provided prefix');
32+
assert.equal(path.basename(name).slice(0, prefix.length), prefix, 'should have the provided prefix');
1533
};
1634
}
1735

1836
function _testPostfix(postfix) {
1937
return function _testPostfixGenerated(err, name, fd) {
20-
assert.equal(name.slice(name.length - postfix.length, name.length), postfix, 'Should have the provided postfix');
38+
assert.equal(name.slice(name.length - postfix.length, name.length), postfix, 'should have the provided postfix');
2139
};
2240
}
2341

2442
function _testKeep(type, keep, cb) {
25-
var
26-
filename,
27-
cbCalled,
28-
keepTest = spawn('node', [ path.join(__dirname, 'keep.js'), type, keep ]);
29-
30-
keepTest.stdout.on('data', function (data) {
31-
filename = data.toString().replace(/\n/, "");
32-
});
33-
keepTest.stderr.on('data', function (data) {
34-
cbCalled = true;
35-
cb(new Error(data.toString()));
36-
});
37-
keepTest.on('exit', function _exited(code) {
38-
if (cbCalled) return;
43+
_spawnTest(true, 'keep.js', [ type, keep ], cb);
44+
}
3945

40-
if (code !== 0) return cb(new Error('Exited with error code: ' + code));
46+
function _testGraceful(type, graceful, cb) {
47+
_spawnTest(false, 'graceful.js', [ type, graceful ], cb);
48+
}
4149

42-
cb(null, filename);
43-
});
50+
function _assertName(err, name) {
51+
assert.isString(name);
4452
}
4553

54+
4655
module.exports.testStat = _testStat;
4756
module.exports.testPrefix = _testPrefix;
4857
module.exports.testPostfix = _testPostfix;
4958
module.exports.testKeep = _testKeep;
59+
module.exports.testGraceful = _testGraceful;
60+
module.exports.assertName = _assertName;

test/dir-test.js

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,21 @@ var
1212

1313
function _testDir(mode) {
1414
return function _testDirGenerated(err, name) {
15-
assert.ok(existsSync(name), 'Should exist');
15+
assert.ok(existsSync(name), 'should exist');
1616

1717
var stat = fs.statSync(name);
18-
assert.ok(stat.isDirectory(), 'Should be a directory');
18+
assert.ok(stat.isDirectory(), 'should be a directory');
1919

2020
Test.testStat(stat, mode);
2121
};
2222
}
2323

24-
2524
vows.describe('Directory creation').addBatch({
2625
'when using without parameters': {
2726
topic: function () {
2827
tmp.dir(this.callback);
2928
},
3029

31-
'should not return with error': assert.isNull,
3230
'should be a directory': _testDir(040700),
3331
'should have the default prefix': Test.testPrefix('tmp-')
3432
},
@@ -38,7 +36,8 @@ vows.describe('Directory creation').addBatch({
3836
tmp.dir({ prefix: 'something' }, this.callback);
3937
},
4038

41-
'should not return with error': assert.isNull,
39+
'should not return with an error': assert.isNull,
40+
'should return with a name': Test.assertName,
4241
'should be a directory': _testDir(040700),
4342
'should have the provided prefix': Test.testPrefix('something')
4443
},
@@ -48,10 +47,10 @@ vows.describe('Directory creation').addBatch({
4847
tmp.dir({ postfix: '.txt' }, this.callback);
4948
},
5049

51-
'should not return with error': assert.isNull,
50+
'should not return with an error': assert.isNull,
51+
'should return with a name': Test.assertName,
5252
'should be a directory': _testDir(040700),
5353
'should have the provided postfix': Test.testPostfix('.txt')
54-
5554
},
5655

5756
'when using template': {
@@ -60,6 +59,7 @@ vows.describe('Directory creation').addBatch({
6059
},
6160

6261
'should not return with error': assert.isNull,
62+
'should return with a name': Test.assertName,
6363
'should be a file': _testDir(040700),
6464
'should have the provided prefix': Test.testPrefix('clike-'),
6565
'should have the provided postfix': Test.testPostfix('-postfix')
@@ -70,7 +70,8 @@ vows.describe('Directory creation').addBatch({
7070
tmp.dir({ prefix: 'foo', postfix: 'bar', mode: 0750 }, this.callback);
7171
},
7272

73-
'should not return with error': assert.isNull,
73+
'should not return with an error': assert.isNull,
74+
'should return with a name': Test.assertName,
7475
'should be a directory': _testDir(040750),
7576
'should have the provided prefix': Test.testPrefix('foo'),
7677
'should have the provided postfix': Test.testPostfix('bar')
@@ -81,7 +82,8 @@ vows.describe('Directory creation').addBatch({
8182
tmp.dir({ prefix: 'complicated', postfix: 'options', mode: 0755 }, this.callback);
8283
},
8384

84-
'should not return with error': assert.isNull,
85+
'should not return with an error': assert.isNull,
86+
'should return with a name': Test.assertName,
8587
'should be a directory': _testDir(040755),
8688
'should have the provided prefix': Test.testPrefix('complicated'),
8789
'should have the provided postfix': Test.testPostfix('options')
@@ -92,17 +94,16 @@ vows.describe('Directory creation').addBatch({
9294
tmp.dir({ tries: -1 }, this.callback);
9395
},
9496

95-
'should not be created': function (err, name) {
96-
assert.isObject(err);
97-
}
97+
'should return with an error': assert.isObject
9898
},
9999

100100
'keep testing': {
101101
topic: function () {
102102
Test.testKeep('dir', '1', this.callback);
103103
},
104104

105-
'should not return with error': assert.isNull,
105+
'should not return with an error': assert.isNull,
106+
'should return with a name': Test.assertName,
106107
'should be a dir': function(err, name) {
107108
_testDir(040700)(err, name);
108109
fs.rmdirSync(name);
@@ -115,8 +116,34 @@ vows.describe('Directory creation').addBatch({
115116
},
116117

117118
'should not return with error': assert.isNull,
119+
'should return with a name': Test.assertName,
120+
'should not exist': function(err, name) {
121+
assert.ok(!existsSync(name), "Directory should be removed");
122+
}
123+
},
124+
125+
'non graceful testing': {
126+
topic: function () {
127+
Test.testGraceful('dir', '0', this.callback);
128+
},
129+
130+
'should not return with error': assert.isNull,
131+
'should return with a name': Test.assertName,
132+
'should be a dir': function(err, name) {
133+
_testDir(040700)(err, name);
134+
fs.rmdirSync(name);
135+
}
136+
},
137+
138+
'graceful testing': {
139+
topic: function () {
140+
Test.testGraceful('dir', '1', this.callback);
141+
},
142+
143+
'should not return with an error': assert.isNull,
144+
'should return with a name': Test.assertName,
118145
'should not exist': function(err, name) {
119146
assert.ok(!existsSync(name), "Directory should be removed");
120147
}
121148
}
122-
}).export(module);
149+
}).exportTo(module);

test/file-test.js

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ var
1212

1313
function _testFile(mode, fdTest) {
1414
return function _testFileGenerated(err, name, fd) {
15-
assert.ok(existsSync(name), 'Should exist');
15+
assert.ok(existsSync(name), 'should exist');
1616

1717
var stat = fs.statSync(name);
18-
assert.equal(stat.size, 0, 'Should have zero size');
19-
assert.ok(stat.isFile(), 'Should be a file');
18+
assert.equal(stat.size, 0, 'should have zero size');
19+
assert.ok(stat.isFile(), 'should be a file');
2020

2121
Test.testStat(stat, mode);
2222

@@ -26,8 +26,8 @@ function _testFile(mode, fdTest) {
2626
assert.deepEqual(fstat, stat, 'fstat results should be the same');
2727

2828
var data = new Buffer('something');
29-
assert.equal(fs.writeSync(fd, data, 0, data.length, 0), data.length, 'Should be writable');
30-
assert.ok(!fs.closeSync(fd), 'Should not return with error');
29+
assert.equal(fs.writeSync(fd, data, 0, data.length, 0), data.length, 'should be writable');
30+
assert.ok(!fs.closeSync(fd), 'should not return with error');
3131
}
3232
};
3333
}
@@ -38,7 +38,8 @@ vows.describe('File creation').addBatch({
3838
tmp.file(this.callback);
3939
},
4040

41-
'should not return with error': assert.isNull,
41+
'should not return with an error': assert.isNull,
42+
'should return with a name': Test.assertName,
4243
'should be a file': _testFile(0100600, true),
4344
'should have the default prefix': Test.testPrefix('tmp-'),
4445
'should have the default postfix': Test.testPostfix('.tmp')
@@ -49,7 +50,8 @@ vows.describe('File creation').addBatch({
4950
tmp.file({ prefix: 'something' }, this.callback);
5051
},
5152

52-
'should not return with error': assert.isNull,
53+
'should not return with an error': assert.isNull,
54+
'should return with a name': Test.assertName,
5355
'should be a file': _testFile(0100600, true),
5456
'should have the provided prefix': Test.testPrefix('something')
5557
},
@@ -59,7 +61,8 @@ vows.describe('File creation').addBatch({
5961
tmp.file({ postfix: '.txt' }, this.callback);
6062
},
6163

62-
'should not return with error': assert.isNull,
64+
'should not return with an error': assert.isNull,
65+
'should return with a name': Test.assertName,
6366
'should be a file': _testFile(0100600, true),
6467
'should have the provided postfix': Test.testPostfix('.txt')
6568

@@ -70,7 +73,8 @@ vows.describe('File creation').addBatch({
7073
tmp.file({ template: path.join(tmp.tmpdir, 'clike-XXXXXX-postfix') }, this.callback);
7174
},
7275

73-
'should not return with error': assert.isNull,
76+
'should not return with an error': assert.isNull,
77+
'should return with a name': Test.assertName,
7478
'should be a file': _testFile(0100600, true),
7579
'should have the provided prefix': Test.testPrefix('clike-'),
7680
'should have the provided postfix': Test.testPostfix('-postfix')
@@ -81,7 +85,8 @@ vows.describe('File creation').addBatch({
8185
tmp.file({ prefix: 'foo', postfix: 'bar', mode: 0640 }, this.callback);
8286
},
8387

84-
'should not return with error': assert.isNull,
88+
'should not return with an error': assert.isNull,
89+
'should return with a name': Test.assertName,
8590
'should be a file': _testFile(0100640, true),
8691
'should have the provided prefix': Test.testPrefix('foo'),
8792
'should have the provided postfix': Test.testPostfix('bar')
@@ -92,7 +97,8 @@ vows.describe('File creation').addBatch({
9297
tmp.file({ prefix: 'complicated', postfix: 'options', mode: 0644 }, this.callback);
9398
},
9499

95-
'should not return with error': assert.isNull,
100+
'should not return with an error': assert.isNull,
101+
'should return with a name': Test.assertName,
96102
'should be a file': _testFile(0100644, true),
97103
'should have the provided prefix': Test.testPrefix('complicated'),
98104
'should have the provided postfix': Test.testPostfix('options')
@@ -103,17 +109,16 @@ vows.describe('File creation').addBatch({
103109
tmp.file({ tries: -1 }, this.callback);
104110
},
105111

106-
'should not be created': function (err, name) {
107-
assert.isObject(err);
108-
}
112+
'should not be created': assert.isObject
109113
},
110114

111115
'keep testing': {
112116
topic: function () {
113117
Test.testKeep('file', '1', this.callback);
114118
},
115119

116-
'should not return with error': assert.isNull,
120+
'should not return with an error': assert.isNull,
121+
'should return with a name': Test.assertName,
117122
'should be a file': function(err, name) {
118123
_testFile(0100600, false)(err, name, null);
119124
fs.unlinkSync(name);
@@ -125,10 +130,36 @@ vows.describe('File creation').addBatch({
125130
Test.testKeep('file', '0', this.callback);
126131
},
127132

133+
'should not return with an error': assert.isNull,
134+
'should return with a name': Test.assertName,
135+
'should not exist': function(err, name) {
136+
assert.ok(!existsSync(name), "File should be removed");
137+
}
138+
},
139+
140+
'non graceful testing': {
141+
topic: function () {
142+
Test.testGraceful('file', '0', this.callback);
143+
},
144+
128145
'should not return with error': assert.isNull,
146+
'should return with a name': Test.assertName,
147+
'should be a file': function(err, name) {
148+
_testFile(0100600, false)(err, name, null);
149+
fs.unlinkSync(name);
150+
}
151+
},
152+
153+
'graceful testing': {
154+
topic: function () {
155+
Test.testGraceful('file', '1', this.callback);
156+
},
157+
158+
'should not return with an error': assert.isNull,
159+
'should return with a name': Test.assertName,
129160
'should not exist': function(err, name) {
130161
assert.ok(!existsSync(name), "File should be removed");
131162
}
132163
}
133164

134-
}).export(module);
165+
}).exportTo(module);

0 commit comments

Comments
 (0)