Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

Essential Tests for Feat/gateway #997

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions examples/traverse-ipld-graphs/git.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ createNode((err, ipfs) => {

const v1tag = 'z8mWaGfwSWLMPJ6Q2JdsAjGiXTf61Nbue'

function errOrLog(comment) {
function errOrLog (comment) {
return (err, result) => {
if (err) {
throw err
}

if (Buffer.isBuffer(result.value)) { //Blobs (files) are returned as buffer instance
if (Buffer.isBuffer(result.value)) { // Blobs (files) are returned as buffer instance
result.value = result.value.toString()
}

Expand All @@ -63,7 +63,6 @@ createNode((err, ipfs) => {
}
}


ipfs.dag.get(v1tag + '/', errOrLog('Tag object:'))
ipfs.dag.get(v1tag + '/object/message', errOrLog('Tagged commit message:'))
ipfs.dag.get(v1tag + '/object/parents/0/message', errOrLog('Parent of tagged commit:'))
Expand Down
2 changes: 1 addition & 1 deletion src/http/gateway/resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const resolveDirectory = promisify((ipfs, path, multihash, callback) => {
return callback(null, indexFiles)
}

return callback(null, dirView.build(path, dagNode.links))
return callback(null, dirView.render(path, dagNode.links))
})
})

Expand Down
83 changes: 83 additions & 0 deletions src/http/gateway/utils/html.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'use strict'

const filesize = require('filesize')

const HTML_PAGE_STYLE = require('./style')
const PathUtil = require('./path')

const getParentDirectoryURL = (originalParts) => {
const parts = originalParts.splice()

if (parts.length > 1) {
parts.pop()
}

return [ '', 'ipfs' ].concat(parts).join('/')
}

const buildFilesList = (path, links) => {
const rows = links.map((link) => {
let row = [
`<div class="ipfs-icon ipfs-_blank">&nbsp;</div>`,
`<a href="${PathUtil.joinURLParts(path, link.name)}">${link.name}</a>`,
filesize(link.size)
]

row = row.map((cell) => `<td>${cell}</td>`).join('')

return `<tr>${row}</tr>`
})

return rows.join('')
}

const buildTable = (path, links) => {
const parts = PathUtil.splitPath(path)
let parentDirectoryURL = getParentDirectoryURL(parts)

return `
<table class="table table-striped">
<tbody>
<tr>
<td class="narrow">
<div class="ipfs-icon ipfs-_blank">&nbsp;</div>
</td>
<td class="padding">
<a href="${parentDirectoryURL}">..</a>
</td>
<td></td>
</tr>
${buildFilesList(path, links)}
</tbody>
</table>
`
}

module.exports.build = (path, links) => {
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>${path}</title>
<style>${HTML_PAGE_STYLE}</style>
</head>
<body>
<div id="header" class="row">
<div class="col-xs-2">
<div id="logo" class="ipfs-logo"></div>
</div>
</div>
<br>
<div class="col-xs-12">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Index of ${path}</strong>
</div>
${buildTable(path, links)}
</div>
</div>
</body>
</html>
`
}
16 changes: 16 additions & 0 deletions src/http/gateway/utils/style.js

Large diffs are not rendered by default.

139 changes: 136 additions & 3 deletions test/gateway/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
/* eslint-env mocha */
'use strict'

const fs = require('fs')
const path = require('path')
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const API = require('../../src/http')
const loadFixture = require('aegir/fixtures')
const bigFile = loadFixture(__dirname, '../../node_modules/interface-ipfs-core/test/fixtures/15mb.random', 'ipfs')
const directoryContent = {
'index.html': loadFixture(__dirname, './test-folder/index.html', 'ipfs'),
'nested-folder/hello.txt': loadFixture(__dirname, './test-folder/nested-folder/hello.txt', 'ipfs'),
'nested-folder/ipfs.txt': loadFixture(__dirname, './test-folder/nested-folder/ipfs.txt', 'ipfs'),
'nested-folder/nested.html': loadFixture(__dirname, './test-folder/nested-folder/nested.html', 'ipfs')
}

describe('HTTP Gateway', () => {
let http = {}
Expand All @@ -15,8 +25,35 @@ describe('HTTP Gateway', () => {
http.api = new API()

http.api.start(true, () => {
gateway = http.api.server.select('Gateway')
done()
const content = (name) => ({
path: `test-folder/${name}`,
content: directoryContent[name]
})

const emptyDir = (name) => ({
path: `test-folder/${name}`
})

const expectedRootMultihash = 'QmbQD7EMEL1zeebwBsWEfA3ndgSS6F7S6iTuwuqasPgVRi'

const dirs = [
content('index.html'),
emptyDir('empty-folder'),
content('nested-folder/hello.txt'),
content('nested-folder/ipfs.txt'),
content('nested-folder/nested.html'),
emptyDir('nested-folder/empty')
]

http.api.node.files.add(dirs, (err, res) => {
expect(err).to.not.exist()
const root = res[res.length - 1]

expect(root.path).to.equal('test-folder')
expect(root.hash).to.equal(expectedRootMultihash)
gateway = http.api.server.select('Gateway')
done()
})
})
})

Expand All @@ -27,7 +64,12 @@ describe('HTTP Gateway', () => {
})
})

describe('/ipfs/* route', () => {
describe('## interface tests', () => {
fs.readdirSync(path.join(__dirname, '/interface'))
.forEach((file) => require('./interface/' + file))
})

describe('## HTTP Gateway', () => {
it('returns 400 for request without argument', (done) => {
gateway.inject({
method: 'GET',
Expand Down Expand Up @@ -61,5 +103,96 @@ describe('HTTP Gateway', () => {
done()
})
})

it('stream a large file', (done) => {
let bigFileHash = 'Qme79tX2bViL26vNjPsF3DP1R9rMKMvnPYJiKTTKPrXJjq'

gateway.inject({
method: 'GET',
url: '/ipfs/' + bigFileHash
}, (res) => {
expect(res.statusCode).to.equal(200)
expect(res.rawPayload).to.deep.equal(bigFile)
done()
})
})

it('load a non text file', (done) => {
let kitty = 'QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ/cat.jpg'

gateway.inject({
method: 'GET',
url: '/ipfs/' + kitty
}, (res) => {
expect(res.statusCode).to.equal(200)
expect(res.headers['content-type']).to.equal('image/jpeg')
done()
})
})

it('load a directory', (done) => {
let dir = 'QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ/'

gateway.inject({
method: 'GET',
url: '/ipfs/' + dir
}, (res) => {
expect(res.statusCode).to.equal(200)
expect(res.headers['content-type']).to.equal('text/html; charset=utf-8')
done()
})
})

it('load a webpage index.html', (done) => {
let dir = 'QmbQD7EMEL1zeebwBsWEfA3ndgSS6F7S6iTuwuqasPgVRi/index.html'

gateway.inject({
method: 'GET',
url: '/ipfs/' + dir
}, (res) => {
expect(res.statusCode).to.equal(200)
expect(res.rawPayload).to.deep.equal(directoryContent['index.html'])
done()
})
})

it('load a webpage {hash}/nested-folder/nested.html', (done) => {
let dir = 'QmbQD7EMEL1zeebwBsWEfA3ndgSS6F7S6iTuwuqasPgVRi/nested-folder/nested.html'

gateway.inject({
method: 'GET',
url: '/ipfs/' + dir
}, (res) => {
expect(res.statusCode).to.equal(200)
expect(res.rawPayload).to.deep.equal(directoryContent['nested-folder/nested.html'])
done()
})
})

it('redirect to generated index', (done) => {
let dir = 'QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ'

gateway.inject({
method: 'GET',
url: '/ipfs/' + dir
}, (res) => {
expect(res.statusCode).to.equal(301)
expect(res.headers['location']).to.equal('/ipfs/QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ/')
done()
})
})

it('redirect to webpage index.html', (done) => {
let dir = 'QmbQD7EMEL1zeebwBsWEfA3ndgSS6F7S6iTuwuqasPgVRi/'

gateway.inject({
method: 'GET',
url: '/ipfs/' + dir
}, (res) => {
expect(res.statusCode).to.equal(302)
expect(res.headers['location']).to.equal('/ipfs/QmbQD7EMEL1zeebwBsWEfA3ndgSS6F7S6iTuwuqasPgVRi/index.html')
done()
})
})
})
})
20 changes: 20 additions & 0 deletions test/gateway/interface/block.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* eslint-env mocha */

'use strict'

const test = require('interface-ipfs-core')
const FactoryClient = require('./../../utils/ipfs-factory-daemon')

let fc

const common = {
setup: function (callback) {
fc = new FactoryClient()
callback(null, fc)
},
teardown: function (callback) {
fc.dismantle(callback)
}
}

test.block(common)
20 changes: 20 additions & 0 deletions test/gateway/interface/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* eslint-env mocha */

'use strict'

const test = require('interface-ipfs-core')
const FactoryClient = require('./../../utils/ipfs-factory-daemon')

let fc

const common = {
setup: function (callback) {
fc = new FactoryClient()
callback(null, fc)
},
teardown: function (callback) {
fc.dismantle(callback)
}
}

test.config(common)
20 changes: 20 additions & 0 deletions test/gateway/interface/files.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* eslint-env mocha */

'use strict'

const test = require('interface-ipfs-core')
const FactoryClient = require('./../../utils/ipfs-factory-daemon')

let fc

const common = {
setup: function (callback) {
fc = new FactoryClient()
callback(null, fc)
},
teardown: function (callback) {
fc.dismantle(callback)
}
}

test.files(common)
20 changes: 20 additions & 0 deletions test/gateway/interface/object.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* eslint-env mocha */

'use strict'

const test = require('interface-ipfs-core')
const FactoryClient = require('./../../utils/ipfs-factory-daemon')

let fc

const common = {
setup: function (callback) {
fc = new FactoryClient()
callback(null, fc)
},
teardown: function (callback) {
fc.dismantle(callback)
}
}

test.object(common)
23 changes: 23 additions & 0 deletions test/gateway/interface/pubsub.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* eslint-env mocha */

'use strict'

// TODO needs: https://github.com/ipfs/js-ipfs-api/pull/493
/*
const test = require('interface-ipfs-core')
const FactoryClient = require('./../../utils/ipfs-factory-daemon')

let fc

const common = {
setup: function (callback) {
fc = new FactoryClient()
callback(null, fc)
},
teardown: function (callback) {
fc.dismantle(callback)
}
}

test.pubsub(common)
*/
Loading