Skip to content
This repository was archived by the owner on Mar 10, 2020. It is now read-only.

Commit 0f86d13

Browse files
committed
fix: remove external URLs from addFromURL tests
Relying on external URLs makes our tests dependent on the availability and response time of these services as well as not being able to run without an internet connection. This PR removes those requests to external URLs and instead spins up test HTTP(s) servers as they are needed to serve the content that `ipfs.util.addFromURL` consumes. resolves #803 License: MIT Signed-off-by: Alan Shaw <[email protected]>
1 parent b2a77d6 commit 0f86d13

File tree

3 files changed

+263
-48
lines changed

3 files changed

+263
-48
lines changed

test/fixtures/ssl/cert.pem

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDOzCCAiMCCQCVqVeRIp9pFDANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJV
3+
UzENMAsGA1UECAwEVXRhaDEOMAwGA1UEBwwFUHJvdm8xIzAhBgNVBAoMGkFDTUUg
4+
U2lnbmluZyBBdXRob3JpdHkgSW5jMRQwEgYDVQQDDAtleGFtcGxlLmNvbTAeFw0x
5+
ODA4MTQyMDEzNTdaFw0xOTEyMjcyMDEzNTdaMFgxCzAJBgNVBAYTAlVTMQ0wCwYD
6+
VQQIDARVdGFoMQ4wDAYDVQQHDAVQcm92bzEWMBQGA1UECgwNQUNNRSBUZWNoIElu
7+
YzESMBAGA1UEAwwJMTI3LjAuMC4xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
8+
CgKCAQEA6x6mTXV+rC35QW/sPutT1O1cugtnw+UsJx7EGgzyjh7EoXE3gb7sO96P
9+
tOI5zknb0vecckbiVkesmLnAs2iNa1u9EiRr6WHdc+1MfUCxyHRfP731vRZyo0kx
10+
bSXerE0qZ2N3M1XyndZF7VMthKDKIg0ZR0TvdjwLqyLYEHAnRBhJLRS0Oy0fC6Of
11+
VWCO3gIuk1HkTXH+/ZMA/obqrtlisxY85mMdlRz+1PNdZBMf+NxmrXN59uq+JqUu
12+
8/v1oQ8jH2iU9IWeqyawHDEvPW3aDorfaWGyats5Xd3cT2Ph4xF9tBLT+3PDGU8c
13+
oBmTHWDenYn+TCkCseayo1JCO5igJQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQCr
14+
R7eZxicHjJoRcbsPBDQpzx9uSux3uvpN93pyJrXXHiil/5SE7CYeDqv5+nV2p6HA
15+
6KONUAmpId0iHAEi9u+0/LgPWyYQMzT3sfBhkO8RRaMYI87VuKbk5PFmlZbD843+
16+
Qmg3Se2F7BDnTf88xA6QWR4DCejy+ZHfDRFrh3xfFl4tX1UNgqiTGfjPCzblhWx9
17+
ygzlT+flN2j3NkAlhUEV89pnH4EQWILePMTT4wh2XOQj1VFJ+2ATojHFVUTtNWAJ
18+
xrY/Q9cMYsZ++I8i9bHMZoyc1bSUd5CNFpQdfjVzlgMPT9Jj/fzWIQz+wq0KeRLI
19+
dLWsa2MZr0GZnTU39YwH
20+
-----END CERTIFICATE-----

test/fixtures/ssl/privkey.pem

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEogIBAAKCAQEA6x6mTXV+rC35QW/sPutT1O1cugtnw+UsJx7EGgzyjh7EoXE3
3+
gb7sO96PtOI5zknb0vecckbiVkesmLnAs2iNa1u9EiRr6WHdc+1MfUCxyHRfP731
4+
vRZyo0kxbSXerE0qZ2N3M1XyndZF7VMthKDKIg0ZR0TvdjwLqyLYEHAnRBhJLRS0
5+
Oy0fC6OfVWCO3gIuk1HkTXH+/ZMA/obqrtlisxY85mMdlRz+1PNdZBMf+NxmrXN5
6+
9uq+JqUu8/v1oQ8jH2iU9IWeqyawHDEvPW3aDorfaWGyats5Xd3cT2Ph4xF9tBLT
7+
+3PDGU8coBmTHWDenYn+TCkCseayo1JCO5igJQIDAQABAoIBAH5fbfFqOpie6T8T
8+
wj4bTGbA4bsZkD9JeU7ZiXubA/ABd5xyduwky2JugH0vrvRC3IVrE0qU8OiBA7Le
9+
/EUx5/kRSPFsZBf/wwChRiB4WlYsvllLZ76nRxyepZNN7H5dx3Hkk1gjVREi71jd
10+
ATUtGxfsRG77DV5WbcshIlLLhT9iaohsalmClAFBmwhqnRMvOXHiQyRbvB0fOX08
11+
uVlObOqo9jLB8N5C/ux+wFEP4wi/AxVqs9ih7Ss7T7+pmOCVWhOnbYcoY2jdaJ11
12+
iLK4F3rv/jQ82OwUpzrWsPedmZUzlOO8xdV3b8hOcPHs/BKvYed7aHSn6b5eVKKT
13+
zT8vQoECgYEA+K9pvw9K/7+F810MHG+nZ0gtVWmXJp49jB7zQ6QMIex2sUajY2y9
14+
bEJX8T6rdu3qd+HYU4zl3qt+MUnsVQEBNkLPAn3od0qIWXxu1SL2GF8SDV1xJWK1
15+
Fp0YDe9blaz1JsmSgieNcSoSwqE2V97Wfd/m+EUfyhQt9HX55H5UgAUCgYEA8gkW
16+
0xZKuHhBMYpcES2P5H5q6HN2fcEQycMuS3agAOhrFPYUT1DVNhbfNVmbOvL2NRWI
17+
hXixo5SkuEuq2fjmEoeLPTmeKO5LM4IVqovWCYomSftKDpzw4HRn2jvKzi2+mg8J
18+
qktIMqRqHu/O1NUIsszCIu4c5DzUdhr4N7GXOaECgYAEd1oF1Wd6al0kfsJN7G9s
19+
Om6d/xR43BSs5I1n5JVXMqD7FBKxIW3ReOuNaJu5uhIg7wxsi7ZBJoFQr0wwRqFX
20+
8SE4oTxAkDUcrlBrQYJ785Embkwu6LPp4Q5iia7yZDXO6YXZEo7GvoOxvSV1tInT
21+
nubOBKfKgExG/KttQBuSZQKBgAzYOqPdLP35M8yDQTuQJXDE3LuVVRZ7Zn6uowhS
22+
NU+XBgfIv28uJQKH2DSmmrxYJITQrbwXmaXKv6sgKOMEeIFHPDZ1llUpwEftgWTZ
23+
ovRCpqGKenWoEoh25QQJ5Eto1hKq9aJZ+GznmNIne9yDqcCDaVIdPN9H8yaJa97Y
24+
x+PBAoGAOiK6xAbPyJSKDSTGZzdv8+yeOdNeJjRHxKJs+4YsDchmdumrqow83DBP
25+
7ulIJD9pcmsWj+8fntMcsTX5mvzJd5LsKc7Maa5/LtitsLsynu78QFg4Njj8sAKn
26+
3991i8J98DZ9zqmkxJJhGwstCHG+c+Q7lA6kZ1UdbWJwYwIHjAs=
27+
-----END RSA PRIVATE KEY-----

test/util.spec.js

+216-48
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ const isNode = require('detect-node')
1010
const path = require('path')
1111
const fs = require('fs')
1212
const os = require('os')
13+
const http = require('http')
14+
const https = require('https')
15+
const each = require('async/each')
16+
const waterfall = require('async/waterfall')
17+
const parallel = require('async/parallel')
1318

1419
const IPFSApi = require('../src')
1520
const f = require('./utils/factory')
@@ -32,7 +37,8 @@ describe('.util', () => {
3237
})
3338
})
3439

35-
after((done) => {
40+
after(function (done) {
41+
this.timeout(10 * 1000)
3642
if (!ipfsd) return done()
3743
ipfsd.stop(done)
3844
})
@@ -113,81 +119,243 @@ describe('.util', () => {
113119
})
114120

115121
describe('.urlAdd', () => {
116-
it('http', function (done) {
117-
this.timeout(40 * 1000)
122+
let testServers = []
123+
124+
const sslOpts = {
125+
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'ssl', 'privkey.pem')),
126+
cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'ssl', 'cert.pem'))
127+
}
128+
129+
const startTestServer = (handler, opts, cb) => {
130+
if (typeof opts === 'function') {
131+
cb = opts
132+
opts = {}
133+
}
134+
135+
const agent = opts.secure ? https : http
136+
const serverOpts = opts.secure ? sslOpts : {}
137+
const server = agent.createServer(serverOpts, handler)
138+
139+
server.listen((err) => {
140+
if (err) return cb(err)
141+
testServers.push(server)
142+
cb(null, server)
143+
})
144+
}
118145

119-
ipfs.util.addFromURL('http://example.com/', (err, result) => {
120-
expect(err).to.not.exist()
121-
expect(result.length).to.equal(1)
122-
done()
146+
beforeEach(() => {
147+
// Instructs node to not reject our snake oil SSL certificate when it
148+
// can't verify the cerificate authority
149+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0
150+
})
151+
152+
afterEach((done) => {
153+
// Reinstate unauthorised SSL cert rejection
154+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1
155+
156+
each(testServers, (server, cb) => server.close(cb), (err) => {
157+
testServers = []
158+
done(err)
123159
})
124160
})
125161

126-
it('https', function (done) {
127-
this.timeout(40 * 1000)
162+
it('http', (done) => {
163+
const handler = (req, res) => {
164+
res.write(`TEST${Date.now()}`)
165+
res.end()
166+
}
128167

129-
ipfs.util.addFromURL('https://example.com/', (err, result) => {
168+
startTestServer(handler, (err, server) => {
130169
expect(err).to.not.exist()
131-
expect(result.length).to.equal(1)
132-
done()
170+
171+
const url = `http://127.0.0.1:${server.address().port}/`
172+
ipfs.util.addFromURL(url, (err, result) => {
173+
expect(err).to.not.exist()
174+
expect(result.length).to.equal(1)
175+
done()
176+
})
133177
})
134178
})
135179

136-
it('http with redirection', function (done) {
137-
this.timeout(40 * 1000)
180+
it('https', (done) => {
181+
const handler = (req, res) => {
182+
res.write(`TEST${Date.now()}`)
183+
res.end()
184+
}
138185

139-
ipfs.util.addFromURL('http://covers.openlibrary.org/book/id/969165.jpg', (err, result) => {
186+
startTestServer(handler, { secure: true }, (err, server) => {
140187
expect(err).to.not.exist()
141-
expect(result[0].hash).to.equal('QmaL9zy7YUfvWmtD5ZXp42buP7P4xmZJWFkm78p8FJqgjg')
142-
done()
188+
189+
const url = `https://127.0.0.1:${server.address().port}/`
190+
ipfs.util.addFromURL(url, (err, result) => {
191+
expect(err).to.not.exist()
192+
expect(result.length).to.equal(1)
193+
done()
194+
})
143195
})
144196
})
145197

146-
it('https with redirection', function (done) {
147-
this.timeout(40 * 1000)
148-
149-
ipfs.util.addFromURL('https://coverartarchive.org/release/6e2a1694-d8b9-466a-aa33-b1077b2333c1', (err, result) => {
198+
it('http with redirection', (done) => {
199+
const data = Buffer.from(`TEST${Date.now()}`)
200+
201+
waterfall([
202+
(cb) => {
203+
const handler = (req, res) => {
204+
res.write(data)
205+
res.end()
206+
}
207+
startTestServer(handler, cb)
208+
},
209+
(serverA, cb) => {
210+
const url = `http://127.0.0.1:${serverA.address().port}`
211+
const handler = (req, res) => {
212+
res.statusCode = 302
213+
res.setHeader('Location', url)
214+
res.end()
215+
}
216+
startTestServer(handler, (err, serverB) => {
217+
if (err) return cb(err)
218+
cb(null, { a: serverA, b: serverB })
219+
})
220+
}
221+
], (err, servers) => {
150222
expect(err).to.not.exist()
151-
expect(result[0].hash).to.equal('QmSUdDvmXuq5YGrL4M3SEz7UZh5eT9WMuAsd9K34sambSj')
152-
done()
223+
224+
ipfs.add(data, (err, res) => {
225+
expect(err).to.not.exist()
226+
227+
const expectedHash = res[0].hash
228+
const url = `http://127.0.0.1:${servers.b.address().port}`
229+
230+
ipfs.util.addFromURL(url, (err, result) => {
231+
expect(err).to.not.exist()
232+
expect(result[0].hash).to.equal(expectedHash)
233+
done()
234+
})
235+
})
153236
})
154237
})
155238

156-
it('with only-hash=true', function () {
157-
this.timeout(40 * 1000)
239+
it('https with redirection', (done) => {
240+
const data = Buffer.from(`TEST${Date.now()}`)
241+
242+
waterfall([
243+
(cb) => {
244+
const handler = (req, res) => {
245+
res.write(data)
246+
res.end()
247+
}
248+
startTestServer(handler, { secure: true }, cb)
249+
},
250+
(serverA, cb) => {
251+
const url = `https://127.0.0.1:${serverA.address().port}`
252+
const handler = (req, res) => {
253+
res.statusCode = 302
254+
res.setHeader('Location', url)
255+
res.end()
256+
}
257+
startTestServer(handler, { secure: true }, (err, serverB) => {
258+
if (err) return cb(err)
259+
cb(null, { a: serverA, b: serverB })
260+
})
261+
}
262+
], (err, servers) => {
263+
expect(err).to.not.exist()
158264

159-
return ipfs.util.addFromURL('http://www.randomtext.me/#/gibberish', { onlyHash: true })
160-
.then(out => expectTimeout(ipfs.object.get(out[0].hash), 4000))
265+
ipfs.add(data, (err, res) => {
266+
expect(err).to.not.exist()
267+
268+
const expectedHash = res[0].hash
269+
const url = `https://127.0.0.1:${servers.b.address().port}`
270+
271+
ipfs.util.addFromURL(url, (err, result) => {
272+
expect(err).to.not.exist()
273+
expect(result[0].hash).to.equal(expectedHash)
274+
done()
275+
})
276+
})
277+
})
161278
})
162279

163-
it('with wrap-with-directory=true', function (done) {
164-
this.timeout(40 * 1000)
280+
it('with only-hash=true', (done) => {
281+
const handler = (req, res) => {
282+
res.write(`TEST${Date.now()}`)
283+
res.end()
284+
}
165285

166-
ipfs.util.addFromURL('http://ipfs.io/ipfs/QmWjppACLcFLQ2qL38unKQvJBhXH3RUtcGLPk7zmrTwV61/969165.jpg?foo=bar#buzz', {
167-
wrapWithDirectory: true
168-
}, (err, result) => {
286+
startTestServer(handler, (err, server) => {
169287
expect(err).to.not.exist()
170-
expect(result[0].hash).to.equal('QmaL9zy7YUfvWmtD5ZXp42buP7P4xmZJWFkm78p8FJqgjg')
171-
expect(result[0].path).to.equal('969165.jpg')
172-
expect(result[1].hash).to.equal('QmWjppACLcFLQ2qL38unKQvJBhXH3RUtcGLPk7zmrTwV61')
173-
expect(result.length).to.equal(2)
174-
done()
288+
289+
const url = `http://127.0.0.1:${server.address().port}/`
290+
291+
ipfs.util.addFromURL(url, { onlyHash: true }, (err, res) => {
292+
expect(err).to.not.exist()
293+
294+
// A successful object.get for this size data took my laptop ~14ms
295+
let didTimeout = false
296+
const timeoutId = setTimeout(() => {
297+
didTimeout = true
298+
done()
299+
}, 500)
300+
301+
ipfs.object.get(res[0].hash, () => {
302+
clearTimeout(timeoutId)
303+
if (didTimeout) return
304+
expect(new Error('did not timeout')).to.not.exist()
305+
})
306+
})
175307
})
176308
})
177309

178-
it('with wrap-with-directory=true and URL-escaped file name', function (done) {
179-
this.timeout(40 * 1000)
310+
it('with wrap-with-directory=true', (done) => {
311+
const filename = `TEST${Date.now()}.txt`
312+
const data = Buffer.from(`TEST${Date.now()}`)
313+
314+
parallel({
315+
server: (cb) => startTestServer((req, res) => {
316+
res.write(data)
317+
res.end()
318+
}, cb),
319+
expectedResult: (cb) => {
320+
ipfs.add([{ path: filename, content: data }], { wrapWithDirectory: true }, cb)
321+
}
322+
}, (err, taskResult) => {
323+
expect(err).to.not.exist()
324+
325+
const { server, expectedResult } = taskResult
326+
const url = `http://127.0.0.1:${server.address().port}/${filename}?foo=bar#buzz`
327+
328+
ipfs.util.addFromURL(url, { wrapWithDirectory: true }, (err, result) => {
329+
expect(err).to.not.exist()
330+
expect(result).to.deep.equal(expectedResult)
331+
done()
332+
})
333+
})
334+
})
180335

181-
// Sample URL contains URL-escaped ( ) and local diacritics
182-
ipfs.util.addFromURL('https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Doma%C5%BElice%2C_Jir%C3%A1skova_43_%289102%29.jpg/320px-Doma%C5%BElice%2C_Jir%C3%A1skova_43_%289102%29.jpg?foo=bar#buzz', {
183-
wrapWithDirectory: true
184-
}, (err, result) => {
336+
it('with wrap-with-directory=true and URL-escaped file name', (done) => {
337+
const filename = '320px-Domažlice,_Jiráskova_43_(9102).jpg'
338+
const data = Buffer.from(`TEST${Date.now()}`)
339+
340+
parallel({
341+
server: (cb) => startTestServer((req, res) => {
342+
res.write(data)
343+
res.end()
344+
}, cb),
345+
expectedResult: (cb) => {
346+
ipfs.add([{ path: filename, content: data }], { wrapWithDirectory: true }, cb)
347+
}
348+
}, (err, taskResult) => {
185349
expect(err).to.not.exist()
186-
expect(result[0].hash).to.equal('QmRJ9ExxSMV4BLF9ZJUb2mLngupm6BXZEek755VHGTJo2Y')
187-
expect(result[0].path).to.equal('320px-Domažlice,_Jiráskova_43_(9102).jpg')
188-
expect(result[1].hash).to.equal('QmbxsHFU3sCfr8wszDHuDLA76C2xCv9HT8L3aC1pBwgaHk')
189-
expect(result.length).to.equal(2)
190-
done()
350+
351+
const { server, expectedResult } = taskResult
352+
const url = `http://127.0.0.1:${server.address().port}/${encodeURIComponent(filename)}?foo=bar#buzz`
353+
354+
ipfs.util.addFromURL(url, { wrapWithDirectory: true }, (err, result) => {
355+
expect(err).to.not.exist()
356+
expect(result).to.deep.equal(expectedResult)
357+
done()
358+
})
191359
})
192360
})
193361

0 commit comments

Comments
 (0)