Skip to content

Commit 147eac4

Browse files
committed
Full tests, handle errors properly in many cases
1 parent 578fb9f commit 147eac4

File tree

9 files changed

+438
-549
lines changed

9 files changed

+438
-549
lines changed

chownr.js

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const LCHOWN = fs.lchown ? 'lchown' : 'chown'
77
/* istanbul ignore next */
88
const LCHOWNSYNC = fs.lchownSync ? 'lchownSync' : 'chownSync'
99

10+
/* istanbul ignore next */
1011
const needEISDIRHandled = fs.lchown &&
1112
!process.version.match(/v1[1-9]+\./) &&
1213
!process.version.match(/v10\.[6-9]/)
@@ -20,6 +21,7 @@ const lchownSync = (path, uid, gid) => {
2021
}
2122
}
2223

24+
/* istanbul ignore next */
2325
const chownSync = (path, uid, gid) => {
2426
try {
2527
return fs.chownSync(path, uid, gid)
@@ -66,18 +68,16 @@ if (/^v4\./.test(nodeVersion))
6668
const chown = (cpath, uid, gid, cb) => {
6769
fs[LCHOWN](cpath, uid, gid, handleEISDIR(cpath, uid, gid, er => {
6870
// Skip ENOENT error
69-
if (er && er.code === 'ENOENT') return cb()
70-
cb(er)
71+
cb(er && er.code !== 'ENOENT' ? er : null)
7172
}))
7273
}
7374

7475
const chownrKid = (p, child, uid, gid, cb) => {
7576
if (typeof child === 'string')
7677
return fs.lstat(path.resolve(p, child), (er, stats) => {
7778
// Skip ENOENT error
78-
if (er && er.code === 'ENOENT') return cb()
7979
if (er)
80-
return cb(er)
80+
return cb(er.code !== 'ENOENT' ? er : null)
8181
stats.name = child
8282
chownrKid(p, stats, uid, gid, cb)
8383
})
@@ -100,10 +100,12 @@ const chownr = (p, uid, gid, cb) => {
100100
readdir(p, { withFileTypes: true }, (er, children) => {
101101
// any error other than ENOTDIR or ENOTSUP means it's not readable,
102102
// or doesn't exist. give up.
103-
if (er && er.code !== 'ENOTDIR' && er.code !== 'ENOTSUP')
104-
return cb(er)
105-
if (er && er.code === 'ENOENT')
106-
return cb()
103+
if (er) {
104+
if (er.code === 'ENOENT')
105+
return cb()
106+
else if (er.code !== 'ENOTDIR' && er.code !== 'ENOTSUP')
107+
return cb(er)
108+
}
107109
if (er || !children.length)
108110
return chown(p, uid, gid, cb)
109111

@@ -129,8 +131,10 @@ const chownrKidSync = (p, child, uid, gid) => {
129131
stats.name = child
130132
child = stats
131133
} catch (er) {
132-
if (er.code === 'ENOENT') return
133-
throw er;
134+
if (er.code === 'ENOENT')
135+
return
136+
else
137+
throw er
134138
}
135139
}
136140

@@ -145,13 +149,15 @@ const chownrSync = (p, uid, gid) => {
145149
try {
146150
children = readdirSync(p, { withFileTypes: true })
147151
} catch (er) {
148-
if (er && er.code === 'ENOTDIR' && er.code !== 'ENOTSUP')
152+
if (er.code === 'ENOENT')
153+
return
154+
else if (er.code === 'ENOTDIR' || er.code === 'ENOTSUP')
149155
return handleEISDirSync(p, uid, gid)
150-
if (er && er.code === 'ENOENT') return
151-
throw er
156+
else
157+
throw er
152158
}
153159

154-
if (children.length)
160+
if (children && children.length)
155161
children.forEach(child => chownrKidSync(p, child, uid, gid))
156162

157163
return handleEISDirSync(p, uid, gid)

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616
"rimraf": "^2.7.1",
1717
"tap": "^14.10.6"
1818
},
19+
"tap": {
20+
"check-coverage": true
21+
},
1922
"scripts": {
20-
"test": "tap test/*.js --cov",
23+
"test": "tap",
2124
"preversion": "npm test",
2225
"postversion": "npm publish",
2326
"postpublish": "git push origin --follow-tags"

test/basic.js

Lines changed: 55 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,84 +2,72 @@ if (!process.getuid || !process.getgid) {
22
throw new Error("Tests require getuid/getgid support")
33
}
44

5-
var curUid = +process.getuid()
6-
, curGid = +process.getgid()
7-
, chownr = require("../")
8-
, test = require("tap").test
9-
, mkdirp = require("mkdirp")
10-
, rimraf = require("rimraf")
11-
, fs = require("fs")
5+
const curUid = +process.getuid()
6+
const curGid = +process.getgid()
7+
const chownr = require("../")
8+
const t = require("tap")
9+
const mkdirp = require("mkdirp")
10+
const rimraf = require("rimraf")
11+
const fs = require("fs")
1212

1313
// sniff the 'id' command for other groups that i can legally assign to
14-
var exec = require("child_process").exec
15-
, groups
16-
, dirs = []
14+
const {exec} = require("child_process")
15+
let groups
16+
let dirs = []
1717

18-
exec("id", function (code, output) {
19-
if (code) throw new Error("failed to run 'id' command")
20-
groups = output.trim().split("=")[3].split(",").map(function (s) {
21-
return parseInt(s, 10)
22-
}).filter(function (g) {
23-
return g !== curGid
24-
})
25-
26-
// console.error([curUid, groups[0]], "uid, gid")
27-
28-
rimraf("/tmp/chownr", function (er) {
29-
if (er) throw er
30-
var cnt = 5
31-
for (var i = 0; i < 5; i ++) {
32-
mkdirp(getDir(), then)
33-
}
34-
function then (er) {
35-
if (er) throw er
36-
if (-- cnt === 0) {
37-
runTest()
38-
}
39-
}
18+
t.test('get the ids to use', { bail: true }, t => {
19+
exec("id", function (code, output) {
20+
if (code) throw new Error("failed to run 'id' command")
21+
groups = output.trim().split("=")[3].split(",")
22+
.map(s => parseInt(s, 10))
23+
.filter(g => g !== curGid)
24+
t.end()
4025
})
4126
})
4227

43-
function getDir () {
44-
var dir = "/tmp/chownr"
45-
46-
dir += "/" + Math.floor(Math.random() * Math.pow(16,4)).toString(16)
47-
dirs.push(dir)
48-
dir += "/" + Math.floor(Math.random() * Math.pow(16,4)).toString(16)
49-
dirs.push(dir)
50-
dir += "/" + Math.floor(Math.random() * Math.pow(16,4)).toString(16)
51-
dirs.push(dir)
52-
return dir
53-
}
28+
t.test('run test', t => {
29+
const dir = t.testdir({
30+
a: { b: { c: {}}},
31+
d: { e: { f: {}}},
32+
g: { h: { i: {}}},
33+
j: { k: { l: {}}},
34+
m: { n: { o: {}}},
35+
})
5436

55-
function runTest () {
56-
test("should complete successfully", function (t) {
37+
t.test("should complete successfully", t => {
5738
// console.error("calling chownr", curUid, groups[0], typeof curUid, typeof groups[0])
58-
chownr("/tmp/chownr", curUid, groups[0], function (er) {
59-
t.ifError(er)
39+
chownr(dir, curUid, groups[0], er => {
40+
if (er)
41+
throw er
6042
t.end()
6143
})
6244
})
6345

64-
dirs.forEach(function (dir) {
65-
test("verify "+dir, function (t) {
66-
fs.stat(dir, function (er, st) {
67-
if (er) {
68-
t.ifError(er)
69-
return t.end()
70-
}
71-
t.equal(st.uid, curUid, "uid should be " + curUid)
72-
t.equal(st.gid, groups[0], "gid should be "+groups[0])
73-
t.end()
74-
})
75-
})
76-
})
46+
const dirs = [
47+
'',
48+
'a',
49+
'a/b',
50+
'a/b/c',
51+
'd',
52+
'd/e',
53+
'd/e/f',
54+
'g',
55+
'g/h',
56+
'g/h/i',
57+
'j',
58+
'j/k',
59+
'j/k/l',
60+
'm',
61+
'm/n',
62+
'm/n/o',
63+
]
7764

78-
test("cleanup", function (t) {
79-
rimraf("/tmp/chownr/", function (er) {
80-
t.ifError(er)
81-
t.end()
65+
dirs.forEach(d => t.test(`verify ${d}`, t => {
66+
t.match(fs.statSync(`${dir}/${d}`), {
67+
uid: curUid,
68+
gid: groups[0],
8269
})
83-
})
84-
}
85-
70+
t.end()
71+
}))
72+
t.end()
73+
})

0 commit comments

Comments
 (0)