From 26459f4045784a38007880aaa0646c4f10f3bf79 Mon Sep 17 00:00:00 2001 From: Richard Littauer Date: Thu, 10 Mar 2016 18:09:47 -0500 Subject: [PATCH 1/3] Stubbed out resources and routes --- src/http-api/resources/block.js | 39 +++++++++++++++++++++++++ src/http-api/routes/block.js | 52 +++++++++++++++++++++++++++++++-- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/src/http-api/resources/block.js b/src/http-api/resources/block.js index e69de29bb2..0c3fdef139 100644 --- a/src/http-api/resources/block.js +++ b/src/http-api/resources/block.js @@ -0,0 +1,39 @@ +'use strict' + +const ipfs = require('./../index.js').ipfs +// const debug = require('debug') +// const get = require('lodash.get') +// const set = require('lodash.set') +// const log = debug('http-api:config') +// log.error = debug('http-api:config:error') +// const multipart = require('ipfs-multipart') + +exports = module.exports + +exports.get = (request, reply) => { + ipfs.block.get((multihash, callback) => { + // parseargs to make sure it is a Multihash + return reply(callback) + }) +} + +exports.put = (request, reply) => { + ipfs.block.put((multihash, callback) => { + // parseArgs to make sure it is a block + return reply(callback) + }) +} + +exports.del = (request, reply) => { + ipfs.block.del((multihash, callback) => { + // parseargs to make sure it is a Multihash + return reply(callback) + }) +} + +exports.stat = (request, reply) => { + ipfs.block.stat((multihash, callback) => { + // parseargs to make sure it is a Multihash + return reply(callback) + }) +} diff --git a/src/http-api/routes/block.js b/src/http-api/routes/block.js index bd30e569b2..3daa3a2cbb 100644 --- a/src/http-api/routes/block.js +++ b/src/http-api/routes/block.js @@ -1,12 +1,58 @@ const resources = require('./../resources') +const Joi = require('joi') -// TODO module.exports = (server) => { const api = server.select('API') api.route({ method: 'GET', - path: '/api/v0/block', - handler: resources.block + path: '/api/v0/block/get/{arg?}', + handler: resources.block.get, + config: { + validate: { + query: { + arg: Joi.string().required() // The base58 multihash of an existing block to get. + } + } + } + }) + + api.route({ + method: 'POST', + path: '/api/v0/block/put/{arg?}', + handler: resources.block.put, + config: { + validate: { + query: { + arg: Joi.string().required() // The data to be stored as an IPFS block. + } + } + } + }) + + api.route({ + method: 'DELETE', + path: '/api/v0/block/del/{arg?}', + handler: resources.block.del, + config: { + validate: { + query: { + arg: Joi.string().required() // The base58 multihash of the IPFS block to be removed. + } + } + } + }) + + api.route({ + method: 'GET', + path: '/api/v0/block/stat/{arg?}', + handler: resources.block.stat, + config: { + validate: { + query: { + arg: Joi.string().required() // The base58 multihash of an existing block to get. + } + } + } }) } From c942c3f607fa92142c1c7e7222e0a9224ef089a5 Mon Sep 17 00:00:00 2001 From: Francisco Baio Dias Date: Sat, 2 Apr 2016 16:00:56 +0200 Subject: [PATCH 2/3] Implement block endpoints on http api --- .gitignore | 2 +- src/http-api/resources/block.js | 162 +++++++++++++++---- src/http-api/routes/block.js | 61 ++++---- src/http-api/routes/index.js | 2 +- test/http-api-tests/test-block.js | 249 +++++++++++++++++++++++++++++- test/test-data/hello | 1 + 6 files changed, 408 insertions(+), 69 deletions(-) create mode 100644 test/test-data/hello diff --git a/.gitignore b/.gitignore index 25076c86b6..ea440ea6c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ **/node_modules/ **/*.log -tests/repo-tests* +test/repo-tests* # Logs logs diff --git a/src/http-api/resources/block.js b/src/http-api/resources/block.js index 0c3fdef139..696fef7339 100644 --- a/src/http-api/resources/block.js +++ b/src/http-api/resources/block.js @@ -1,39 +1,149 @@ 'use strict' const ipfs = require('./../index.js').ipfs -// const debug = require('debug') -// const get = require('lodash.get') -// const set = require('lodash.set') -// const log = debug('http-api:config') -// log.error = debug('http-api:config:error') -// const multipart = require('ipfs-multipart') +const bs58 = require('bs58') +const multipart = require('ipfs-multipart') +const Block = require('ipfs-blocks').Block +const debug = require('debug') +const log = debug('http-api:block') +log.error = debug('http-api:block:error') exports = module.exports -exports.get = (request, reply) => { - ipfs.block.get((multihash, callback) => { - // parseargs to make sure it is a Multihash - return reply(callback) - }) +// common pre request handler that parses the args and returns `key` which is assigned to `request.pre.args` +exports.parseKey = (request, reply) => { + if (!request.query.arg) { + return reply("Argument 'key' is required").code(400).takeover() + } + + try { + return reply({ + key: new Buffer(bs58.decode(request.query.arg)) + }) + } catch (err) { + log.error(err) + return reply({ + Message: 'Not a valid hash', + Code: 0 + }).code(500).takeover() + } +} + +exports.get = { + // uses common parseKey method that returns a `key` + parseArgs: exports.parseKey, + + // main route handler which is called after the above `parseArgs`, but only if the args were valid + handler: (request, reply) => { + const key = request.pre.args.key + + ipfs.block.get(key, (err, block) => { + if (err) { + log.error(err) + return reply({ + Message: 'Failed to get block: ' + err, + Code: 0 + }).code(500) + } + + return reply(block.data.toString()) + }) + } } -exports.put = (request, reply) => { - ipfs.block.put((multihash, callback) => { - // parseArgs to make sure it is a block - return reply(callback) - }) +exports.put = { + // pre request handler that parses the args and returns `data` which is assigned to `request.pre.args` + parseArgs: (request, reply) => { + if (!request.payload) { + return reply("File argument 'data' is required").code(400).takeover() + } + + const parser = multipart.reqParser(request.payload) + var file + + parser.on('file', (fileName, fileStream) => { + fileStream.on('data', (data) => { + file = data + }) + }) + + parser.on('end', () => { + if (!file) { + return reply("File argument 'data' is required").code(400).takeover() + } + + return reply({ + data: file.toString() + }) + }) + }, + + // main route handler which is called after the above `parseArgs`, but only if the args were valid + handler: (request, reply) => { + const data = request.pre.args.data + + const block = new Block(data) + + ipfs.block.put(block, (err) => { + if (err) { + log.error(err) + return reply({ + Message: 'Failed to put block: ' + err, + Code: 0 + }).code(500) + } + + return reply({ + Key: bs58.encode(block.key).toString(), + Size: block.data.length + }) + }) + } } -exports.del = (request, reply) => { - ipfs.block.del((multihash, callback) => { - // parseargs to make sure it is a Multihash - return reply(callback) - }) +exports.del = { + // uses common parseKey method that returns a `key` + parseArgs: exports.parseKey, + + // main route handler which is called after the above `parseArgs`, but only if the args were valid + handler: (request, reply) => { + const key = request.pre.args.key + + ipfs.block.del(key, (err, block) => { + if (err) { + log.error(err) + return reply({ + Message: 'Failed to get block stats: ' + err, + Code: 0 + }).code(500) + } + + return reply() + }) + } } -exports.stat = (request, reply) => { - ipfs.block.stat((multihash, callback) => { - // parseargs to make sure it is a Multihash - return reply(callback) - }) +exports.stat = { + // uses common parseKey method that returns a `key` + parseArgs: exports.parseKey, + + // main route handler which is called after the above `parseArgs`, but only if the args were valid + handler: (request, reply) => { + const key = request.pre.args.key + + ipfs.block.stat(key, (err, block) => { + if (err) { + log.error(err) + return reply({ + Message: 'Failed to get block stats: ' + err, + Code: 0 + }).code(500) + } + + return reply({ + Key: bs58.encode(block.Key).toString(), + Size: block.Size + }) + }) + } } diff --git a/src/http-api/routes/block.js b/src/http-api/routes/block.js index 3daa3a2cbb..328ac71439 100644 --- a/src/http-api/routes/block.js +++ b/src/http-api/routes/block.js @@ -1,58 +1,53 @@ const resources = require('./../resources') -const Joi = require('joi') module.exports = (server) => { const api = server.select('API') api.route({ - method: 'GET', - path: '/api/v0/block/get/{arg?}', - handler: resources.block.get, + method: '*', + path: '/api/v0/block/get', config: { - validate: { - query: { - arg: Joi.string().required() // The base58 multihash of an existing block to get. - } - } + pre: [ + { method: resources.block.get.parseArgs, assign: 'args' } + ], + handler: resources.block.get.handler } }) api.route({ - method: 'POST', - path: '/api/v0/block/put/{arg?}', - handler: resources.block.put, + method: '*', + path: '/api/v0/block/put', config: { - validate: { - query: { - arg: Joi.string().required() // The data to be stored as an IPFS block. - } - } + payload: { + parse: false, + output: 'stream' + }, + pre: [ + { method: resources.block.put.parseArgs, assign: 'args' } + ], + handler: resources.block.put.handler } }) api.route({ - method: 'DELETE', - path: '/api/v0/block/del/{arg?}', - handler: resources.block.del, + method: '*', + path: '/api/v0/block/del', config: { - validate: { - query: { - arg: Joi.string().required() // The base58 multihash of the IPFS block to be removed. - } - } + pre: [ + { method: resources.block.del.parseArgs, assign: 'args' } + ], + handler: resources.block.del.handler } }) api.route({ - method: 'GET', - path: '/api/v0/block/stat/{arg?}', - handler: resources.block.stat, + method: '*', + path: '/api/v0/block/stat', config: { - validate: { - query: { - arg: Joi.string().required() // The base58 multihash of an existing block to get. - } - } + pre: [ + { method: resources.block.stat.parseArgs, assign: 'args' } + ], + handler: resources.block.stat.handler } }) } diff --git a/src/http-api/routes/index.js b/src/http-api/routes/index.js index 0c9bb64fea..57702b2f25 100644 --- a/src/http-api/routes/index.js +++ b/src/http-api/routes/index.js @@ -2,7 +2,7 @@ module.exports = (server) => { require('./version')(server) require('./id')(server) require('./bootstrap')(server) - // require('./block')(server) + require('./block')(server) require('./object')(server) // require('./repo')(server) require('./config')(server) diff --git a/test/http-api-tests/test-block.js b/test/http-api-tests/test-block.js index a1260895e8..af8ccd206c 100644 --- a/test/http-api-tests/test-block.js +++ b/test/http-api-tests/test-block.js @@ -1,23 +1,256 @@ /* eslint-env mocha */ -// const expect = require('chai').expect -// const APIctl = require('ipfs-api') +const expect = require('chai').expect +const APIctl = require('ipfs-api') +const fs = require('fs') +const FormData = require('form-data') +const streamToPromise = require('stream-to-promise') describe('block', () => { describe('api', () => { - // TODO - }) + var api + + it('api', (done) => { + api = require('../../src/http-api').server.select('API') + done() + }) + + describe('/block/put', () => { + it('returns 400 if no node is provided', (done) => { + const form = new FormData() + const headers = form.getHeaders() + + streamToPromise(form).then((payload) => { + api.inject({ + method: 'POST', + url: '/api/v0/block/put', + headers: headers, + payload: payload + }, (res) => { + expect(res.statusCode).to.equal(400) + done() + }) + }) + }) + + it('updates value', (done) => { + const form = new FormData() + const filePath = 'test/test-data/hello' + form.append('data', fs.createReadStream(filePath)) + const headers = form.getHeaders() + const expectedResult = { + Key: 'QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp', + Size: 12 + } + + streamToPromise(form).then((payload) => { + api.inject({ + method: 'POST', + url: '/api/v0/block/put', + headers: headers, + payload: payload + }, (res) => { + expect(res.statusCode).to.equal(200) + expect(res.result).to.deep.equal(expectedResult) + done() + }) + }) + }) + }) + + describe('/block/get', () => { + it('returns 400 for request without argument', (done) => { + api.inject({ + method: 'GET', + url: '/api/v0/block/get' + }, (res) => { + expect(res.statusCode).to.equal(400) + expect(res.result).to.be.a('string') + done() + }) + }) + + it('returns 500 for request with invalid argument', (done) => { + api.inject({ + method: 'GET', + url: '/api/v0/block/get?arg=invalid' + }, (res) => { + expect(res.statusCode).to.equal(500) + expect(res.result.Code).to.equal(0) + expect(res.result.Message).to.be.a('string') + done() + }) + }) + + it('returns value', (done) => { + api.inject({ + method: 'GET', + url: '/api/v0/block/get?arg=QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp' + }, (res) => { + expect(res.statusCode).to.equal(200) + expect(res.result) + .to.equal('hello world\n') + done() + }) + }) + }) + + describe('/block/stat', () => { + it('returns 400 for request without argument', (done) => { + api.inject({ + method: 'GET', + url: '/api/v0/block/stat' + }, (res) => { + expect(res.statusCode).to.equal(400) + expect(res.result).to.be.a('string') + done() + }) + }) + + it('returns 500 for request with invalid argument', (done) => { + api.inject({ + method: 'GET', + url: '/api/v0/block/stat?arg=invalid' + }, (res) => { + expect(res.statusCode).to.equal(500) + expect(res.result.Code).to.equal(0) + expect(res.result.Message).to.be.a('string') + done() + }) + }) + + it('returns value', (done) => { + api.inject({ + method: 'GET', + url: '/api/v0/block/stat?arg=QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp' + }, (res) => { + expect(res.statusCode).to.equal(200) + expect(res.result.Key) + .to.equal('QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp') + expect(res.result.Size).to.equal(12) + done() + }) + }) + }) - describe('gateway', () => {}) + describe('/block/del', () => { + it('returns 400 for request without argument', (done) => { + api.inject({ + method: 'GET', + url: '/api/v0/block/del' + }, (res) => { + expect(res.statusCode).to.equal(400) + expect(res.result).to.be.a('string') + done() + }) + }) + + it('returns 500 for request with invalid argument', (done) => { + api.inject({ + method: 'GET', + url: '/api/v0/block/del?arg=invalid' + }, (res) => { + expect(res.statusCode).to.equal(500) + expect(res.result.Code).to.equal(0) + expect(res.result.Message).to.be.a('string') + done() + }) + }) + + it('returns 200', (done) => { + api.inject({ + method: 'GET', + url: '/api/v0/block/del?arg=QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp' + }, (res) => { + expect(res.statusCode).to.equal(200) + done() + }) + }) + }) + }) describe('using js-ipfs-api', () => { -// var ctl + var ctl it('start IPFS API ctl', (done) => { -// ctl = APIctl('/ip4/127.0.0.1/tcp/6001') + ctl = APIctl('/ip4/127.0.0.1/tcp/6001') done() }) - // TODO + describe('ipfs.object.put', () => { + it('returns error for request without argument', (done) => { + const filePath = null + + ctl.block.put(filePath, (err) => { + expect(err).to.exist + done() + }) + }) + + it('updates value', (done) => { + const filePath = 'test/test-data/hello' + const expectedResult = { + Key: 'QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp', + Size: 12 + } + + ctl.block.put(filePath, (err, res) => { + expect(err).not.to.exist + expect(res).to.deep.equal(expectedResult) + done() + }) + }) + }) + + describe('ipfs.block.get', () => { + it('returns error for request without argument', (done) => { + ctl.block.get(null, (err, result) => { + expect(err).to.exist + done() + }) + }) + + it('returns error for request with invalid argument', (done) => { + ctl.block.get('invalid', (err, result) => { + expect(err).to.exist + done() + }) + }) + + it('returns value', (done) => { + ctl.block.get('QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp', (err, result) => { + expect(err).to.not.exist + expect(result.toString()) + .to.equal('hello world\n') + done() + }) + }) + }) + + describe('ipfs.block.stat', () => { + it('returns error for request without argument', (done) => { + ctl.block.stat(null, (err, result) => { + expect(err).to.exist + done() + }) + }) + + it('returns error for request with invalid argument', (done) => { + ctl.block.stat('invalid', (err, result) => { + expect(err).to.exist + done() + }) + }) + + it('returns value', (done) => { + ctl.block.stat('QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp', (err, result) => { + expect(err).to.not.exist + expect(result.Key) + .to.equal('QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp') + expect(result.Size).to.equal(12) + done() + }) + }) + }) }) }) diff --git a/test/test-data/hello b/test/test-data/hello new file mode 100644 index 0000000000..3b18e512db --- /dev/null +++ b/test/test-data/hello @@ -0,0 +1 @@ +hello world From 6179d4e790ecfcbba5a941f30b4dd3700ad59e2b Mon Sep 17 00:00:00 2001 From: Francisco Baio Dias Date: Sat, 2 Apr 2016 23:07:51 +0200 Subject: [PATCH 3/3] Add block commands to cli --- src/cli/commands/block/get.js | 42 +++++++++++ src/cli/commands/block/put.js | 60 +++++++++++++++ src/cli/commands/block/rm.js | 42 +++++++++++ src/cli/commands/block/stat.js | 45 ++++++++++++ test/cli-tests/test-block.js | 117 ++++++++++++++++++++++++++++++ test/cli-tests/test-commands.js | 2 +- test/http-api-tests/test-block.js | 2 +- 7 files changed, 308 insertions(+), 2 deletions(-) create mode 100644 src/cli/commands/block/get.js create mode 100644 src/cli/commands/block/put.js create mode 100644 src/cli/commands/block/rm.js create mode 100644 src/cli/commands/block/stat.js create mode 100644 test/cli-tests/test-block.js diff --git a/src/cli/commands/block/get.js b/src/cli/commands/block/get.js new file mode 100644 index 0000000000..ec6baedfcf --- /dev/null +++ b/src/cli/commands/block/get.js @@ -0,0 +1,42 @@ +const Command = require('ronin').Command +const utils = require('../../utils') +const bs58 = require('bs58') +const debug = require('debug') +const log = debug('cli:block') +log.error = debug('cli:block:error') + +module.exports = Command.extend({ + desc: 'Get a raw IPFS block', + + options: {}, + + run: (key) => { + if (!key) { + throw new Error("Argument 'key' is required") + } + + utils.getIPFS((err, ipfs) => { + if (err) { + throw err + } + + const mh = utils.isDaemonOn() + ? key + : new Buffer(bs58.decode(key)) + + ipfs.block.get(mh, (err, block) => { + if (err) { + log.error(err) + throw err + } + + if (block.data) { + console.log(block.data.toString()) + return + } + + console.log(block.toString()) + }) + }) + } +}) diff --git a/src/cli/commands/block/put.js b/src/cli/commands/block/put.js new file mode 100644 index 0000000000..000d043fc3 --- /dev/null +++ b/src/cli/commands/block/put.js @@ -0,0 +1,60 @@ +const Command = require('ronin').Command +const utils = require('../../utils') +const bs58 = require('bs58') +const bl = require('bl') +const fs = require('fs') +const Block = require('ipfs-blocks').Block +const debug = require('debug') +const log = debug('cli:block') +log.error = debug('cli:block:error') + +function addBlock (buf) { + utils.getIPFS((err, ipfs) => { + if (err) { + throw err + } + + if (utils.isDaemonOn()) { + return ipfs.block.put(buf, (err, block) => { + if (err) { + log.error(err) + throw err + } + + console.log(block.Key) + }) + } + + const block = new Block(buf) + + ipfs.block.put(block, (err, obj) => { + if (err) { + log.error(err) + throw err + } + + console.log(bs58.encode(block.key).toString()) + }) + }) +} + +module.exports = Command.extend({ + desc: 'Stores input as an IPFS block', + + options: {}, + + run: (filePath) => { + if (filePath) { + return addBlock(fs.readFileSync(filePath)) + } + + process.stdin.pipe(bl((err, input) => { + if (err) { + log.error(err) + throw err + } + + addBlock(input) + })) + } +}) diff --git a/src/cli/commands/block/rm.js b/src/cli/commands/block/rm.js new file mode 100644 index 0000000000..1fa26acd89 --- /dev/null +++ b/src/cli/commands/block/rm.js @@ -0,0 +1,42 @@ +'use strict' + +const Command = require('ronin').Command +const utils = require('../../utils') +const bs58 = require('bs58') +const debug = require('debug') +const log = debug('cli:block') +log.error = debug('cli:block:error') + +module.exports = Command.extend({ + desc: 'Remove a raw IPFS block', + + options: {}, + + run: (key) => { + if (!key) { + throw new Error("Argument 'key' is required") + } + + utils.getIPFS((err, ipfs) => { + if (err) { + throw err + } + + if (utils.isDaemonOn()) { + // TODO implement this once `js-ipfs-api` supports it + throw new Error('rm block with daemon running is not yet implemented') + } + + const mh = new Buffer(bs58.decode(key)) + + ipfs.block.del(mh, (err) => { + if (err) { + log.error(err) + throw err + } + + console.log('removed', key) + }) + }) + } +}) diff --git a/src/cli/commands/block/stat.js b/src/cli/commands/block/stat.js new file mode 100644 index 0000000000..a6e4a6c440 --- /dev/null +++ b/src/cli/commands/block/stat.js @@ -0,0 +1,45 @@ +'use strict' + +const Command = require('ronin').Command +const utils = require('../../utils') +const bs58 = require('bs58') +const debug = require('debug') +const log = debug('cli:block') +log.error = debug('cli:block:error') + +module.exports = Command.extend({ + desc: 'Print information of a raw IPFS block', + + options: {}, + + run: (key) => { + if (!key) { + throw new Error("Argument 'key' is required") + } + + utils.getIPFS((err, ipfs) => { + if (err) { + throw err + } + + const mh = utils.isDaemonOn() + ? key + : new Buffer(bs58.decode(key)) + + ipfs.block.stat(mh, (err, block) => { + if (err) { + log.error(err) + throw err + } + + if (typeof block.Key !== 'string') { + block.Key = bs58.encode(block.Key).toString() + } + + Object.keys(block).forEach((key) => { + console.log(`${key}: ${block[key]}`) + }) + }) + }) + } +}) diff --git a/test/cli-tests/test-block.js b/test/cli-tests/test-block.js new file mode 100644 index 0000000000..08d02b83d0 --- /dev/null +++ b/test/cli-tests/test-block.js @@ -0,0 +1,117 @@ +/* eslint-env mocha */ + +const expect = require('chai').expect +const nexpect = require('nexpect') +const httpAPI = require('../../src/http-api') + +describe('block', () => { + describe('api offline', () => { + it('put', (done) => { + nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'block', 'put', process.cwd() + '/test/test-data/hello']) + .run((err, stdout, exitcode) => { + expect(err).to.not.exist + expect(exitcode).to.equal(0) + expect(stdout[0]) + .to.equal('QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp') + done() + }) + }) + + it('get', (done) => { + nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'block', 'get', 'QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp']) + .run((err, stdout, exitcode) => { + expect(err).to.not.exist + expect(exitcode).to.equal(0) + expect(stdout[0]) + .to.equal('hello world') + done() + }) + }) + + it('stat', (done) => { + nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'block', 'stat', 'QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp']) + .run((err, stdout, exitcode) => { + expect(err).to.not.exist + expect(exitcode).to.equal(0) + expect(stdout[0]) + .to.equal('Key: QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp') + expect(stdout[1]) + .to.equal('Size: 12') + done() + }) + }) + + it('rm', (done) => { + nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'block', 'rm', 'QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp']) + .run((err, stdout, exitcode) => { + expect(err).to.not.exist + expect(exitcode).to.equal(0) + expect(stdout[0]) + .to.equal('removed QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp') + done() + }) + }) + }) + + describe('api running', () => { + before((done) => { + httpAPI.start((err) => { + expect(err).to.not.exist + done() + }) + }) + + after((done) => { + httpAPI.stop((err) => { + expect(err).to.not.exist + done() + }) + }) + + it('put', (done) => { + nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'block', 'put', process.cwd() + '/test/test-data/hello']) + .run((err, stdout, exitcode) => { + expect(err).to.not.exist + expect(exitcode).to.equal(0) + expect(stdout[0]) + .to.equal('QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp') + done() + }) + }) + + it('get', (done) => { + nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'block', 'get', 'QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp']) + .run((err, stdout, exitcode) => { + expect(err).to.not.exist + expect(exitcode).to.equal(0) + expect(stdout[0]) + .to.equal('hello world') + done() + }) + }) + + it('stat', (done) => { + nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'block', 'stat', 'QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp']) + .run((err, stdout, exitcode) => { + expect(err).to.not.exist + expect(exitcode).to.equal(0) + expect(stdout[0]) + .to.equal('Key: QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp') + expect(stdout[1]) + .to.equal('Size: 12') + done() + }) + }) + + it.skip('rm', (done) => { + nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'block', 'rm', 'QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp']) + .run((err, stdout, exitcode) => { + expect(err).to.not.exist + expect(exitcode).to.equal(0) + expect(stdout[0]) + .to.equal('removed QmZjTnYw2TFhn9Nn7tjmPSoTBoY7YRkwPzwSrSbabY24Kp') + done() + }) + }) + }) +}) diff --git a/test/cli-tests/test-commands.js b/test/cli-tests/test-commands.js index f8924cc7c9..10a69fd824 100644 --- a/test/cli-tests/test-commands.js +++ b/test/cli-tests/test-commands.js @@ -9,7 +9,7 @@ describe('commands', () => { .run((err, stdout, exitcode) => { expect(err).to.not.exist expect(exitcode).to.equal(0) - expect(stdout.length).to.equal(36) + expect(stdout.length).to.equal(40) done() }) }) diff --git a/test/http-api-tests/test-block.js b/test/http-api-tests/test-block.js index af8ccd206c..cf33426136 100644 --- a/test/http-api-tests/test-block.js +++ b/test/http-api-tests/test-block.js @@ -177,7 +177,7 @@ describe('block', () => { done() }) - describe('ipfs.object.put', () => { + describe('ipfs.block.put', () => { it('returns error for request without argument', (done) => { const filePath = null