'not enough free disk space', function(done) { //arrange farmer = new FarmerInterface({ keyPair: KeyPair(), rpcPort: 0, tunnelServerPort: 0, doNotTraverseNat: true, contractNegotiator: function(contract, callback) { callback(false); }, logger: kad.Logger(0), storagePath: tmpPath, storageManager: new StorageManager(new RAMStorageAdapter()) }); var _size = sinon.stub( farmer.storageManager._storage, 'size' ).callsArgWith(1, null, 500, 500); farmer.storageManager._options.maxCapacity = 2000; var _verify = sinon.stub(Contract.prototype, 'verify').returns(true); var _sendOffer = sinon.stub(farmer, '_sendOfferForContract'); //execute farmer._handleContractPublication(Contract({})); //assert _verify.restore(); _size.restore(); _sendOffer.restore(); expect(_sendOffer.called).to.equal(false); done(); });
it('should adding tunnels if bucket is not full', function(done) { var _addContact = sinon.stub(); var proto = new Protocol({ network: { _logger: Logger(0), _router: { getNearestContacts: sinon.stub().returns([{}]) }, _contact: { nodeID: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' }, _transport: { _createContact: sinon.stub(), send: sinon.stub().callsArgWith(2, null, { result: { tunnels: [ { nodeID: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' } ] } }) }, _tunnelers: { addContact: _addContact, getContactList: sinon.stub().returns([]), getSize: sinon.stub().returns(19) } } }); proto._askNeighborsForTunnels([], function() { expect(_addContact.called).to.equal(true); done(); }); });
it('should error if port mapping fails', function(done) { var _createPortMapping = sinon.stub().callsArgWith( 1, new Error('Failed') ); var _createGateway = sinon.stub().callsArgWith(0, null, { getEntranceToken: function() { return 'sometoken'; }, getEntranceAddress: function() { return { address: '0.0.0.0', port: 0 }; } }); var proto = new Protocol({ network: { _logger: Logger(0), _contact: {}, _transport: { _requiresTraversal: true, _isPublic: true, _tunserver: { createGateway: _createGateway, getListeningPort: sinon.stub().returns(0) }, createPortMapping: _createPortMapping } } }); proto._handleOpenTunnel({ contact: { nodeID: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' } }, function(err) { expect(err.message).to.equal('Failed'); done(); }); });
it('should ask neighbors for tunnels if none known', function(done) { var proto = new Protocol({ network: { _logger: Logger(0), _router: { getNearestContacts: sinon.stub().returns([{}]) }, _contact: { nodeID: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' }, _transport: { _tunserver: { hasTunnelAvailable: sinon.stub().returns(false) } }, _tunnelers: { getContactList: sinon.stub().returns([]) } } }); var _ask = sinon.stub(proto, '_askNeighborsForTunnels').callsArg(1); proto._handleFindTunnel({ contact: { nodeID: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' }, relayers: [] }, function() { _ask.restore(); expect(_ask.called).to.equal(true); done(); }); });
it('should bubble manager error', function(done) { var _save = sinon.stub().callsArgWith(1, new Error('Failed')); var proto = new Protocol({ network: { _logger: Logger(0), _manager: { save: _save }, _pendingContracts: { adc83b19e793491b1c6ea0fd8b46cd9f32e592fc: function() {} } } }); var _verify = sinon.stub(proto, '_verifyContract').callsArg(2); proto._handleOffer({ contract: { data_hash: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' }, contact: { address: '127.0.0.1', port: 1337, nodeID: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' } }, function(err) { _verify.restore(); expect(err.message).to.equal('Failed'); done(); }); });
it('should create a new item if cannot load existing', function(done) { var farmer = new FarmerInterface({ keypair: KeyPair(), port: 0, noforward: true, logger: kad.Logger(0), backend: require('memdown'), storage: { path: 'test' } }); var _load = sinon.stub(farmer._manager, 'load').callsArgWith(1, {}); var _save = sinon.stub(farmer._manager, 'save'); var _verify = sinon.stub(Contract.prototype, 'verify').returns(true); farmer._handleOfferRes({ result: { contract: Contract({}).toObject() } }, new Contract(), {}); setImmediate(function() { _load.restore(); _save.restore(); _verify.restore(); expect(_save.args[0][0]).to.be.instanceOf(StorageItem); done(); }); });
function createNode(opcodes) { var node = null; var kp = new KeyPair(); var manager = new Manager(new LevelDBStorageAdapter( (Math.floor(Math.random() * 24)).toString(), memdown )); var port = STARTING_PORT--; var options = { keypair: kp, manager: manager, logger: kad.Logger(0), seeds: NODE_LIST.slice(), address: '127.0.0.1', port: port, opcodes: opcodes, noforward: true, backend: memdown, bridge: false }; if (opcodes.length) { node = FarmerInterface(options); } else { node = RenterInterface(options); } NODE_LIST.push([ 'storj://127.0.0.1:', port, '/', kp.getNodeID() ].join('')); return node; }
it('will get and complete challenge and create contact', function(done) { farmer = new FarmerInterface({ keyPair: KeyPair(), rpcPort: 0, tunnelServerPort: 0, doNotTraverseNat: true, logger: kad.Logger(0), storagePath: tmpPath, storageManager: new StorageManager(new RAMStorageAdapter()) }); let bridge = { url: 'https://api.storj.io/', extendedKey: extendedKey } let nonce = 101; sandbox.stub(farmer, 'bridgeRequest').callsArg(5); let data = { challenge: '5980ef806b470f147b44dc05238c53458efe9dc7f5711db6ccef2e5e832431c6', target: '00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' }; farmer.bridgeRequest.onFirstCall().callsArgWith(5, null, data); sandbox.stub(farmer, '_completeChallenge').callsArgWith(2, null, nonce); farmer._addBridgeContact(bridge, (err) => { if (err) { return done(err); } expect(farmer.bridgeRequest.callCount).to.equal(2); expect(farmer._completeChallenge.callCount).to.equal(1); expect(farmer.bridgeRequest.args[1][3]['x-challenge-nonce']) .to.equal(101); done(); }); });
it('will send patch request to update contact', function(done) { farmer = new FarmerInterface({ keyPair: KeyPair(), rpcPort: 11, tunnelServerPort: 0, doNotTraverseNat: true, logger: kad.Logger(0), storagePath: tmpPath, storageManager: new StorageManager(new RAMStorageAdapter()) }); let bridge = { url: 'https://api.storj.io/', extendedKey: extendedKey } sandbox.stub(farmer, 'bridgeRequest').callsArg(5); farmer._updateBridgeContact(bridge, (err) => { if (err) { return done(err); } expect(farmer.bridgeRequest.callCount).to.equal(1); expect(farmer.bridgeRequest.args[0][4].address).to.equal('127.0.0.1'); expect(farmer.bridgeRequest.args[0][4].port).to.equal(11); done(); }); });
it('will add bridge contact if contact does not exist', function(done) { farmer = new FarmerInterface({ keyPair: KeyPair(), rpcPort: 0, tunnelServerPort: 0, doNotTraverseNat: true, logger: kad.Logger(0), storagePath: tmpPath, storageManager: new StorageManager(new RAMStorageAdapter()) }); let contact = {}; let err = new Error(); err.statusCode = 404; sandbox.stub(farmer, 'bridgeRequest').callsArgWith(5, err); sandbox.stub(farmer, '_addBridgeContact').callsArgWith(1, null, contact); let bridge = { url: 'https://api.storj.io/', extendedKey: extendedKey } farmer._connectBridge(bridge, (err) => { if (err) { return done(err); } expect(farmer.bridgeRequest.callCount).to.equal(1); expect(farmer._addBridgeContact.callCount).to.equal(1); done(); }); });
it('will do nothing if contact is up-to-date', function(done) { farmer = new FarmerInterface({ keyPair: KeyPair(), rpcPort: 0, tunnelServerPort: 0, doNotTraverseNat: true, logger: kad.Logger(0), storagePath: tmpPath, storageManager: new StorageManager(new RAMStorageAdapter()) }); let contact = { address: '127.0.0.1', port: 0, spaceAvailable: true, protocol: '1.2.0' }; sandbox.stub(farmer, 'bridgeRequest').callsArgWith(5, null, contact); sandbox.stub(farmer, '_updateBridgeContact').callsArgWith(1, null); let bridge = { url: 'https://api.storj.io/', extendedKey: extendedKey } farmer._connectBridge(bridge, (err) => { if (err) { return done(err); } expect(farmer.bridgeRequest.callCount).to.equal(1); expect(farmer._updateBridgeContact.callCount).to.equal(0); done(); }); });
it('will connect each bridge', function() { farmer = new FarmerInterface({ keyPair: KeyPair(), rpcPort: 0, tunnelServerPort: 0, doNotTraverseNat: true, logger: kad.Logger(0), bridges: [ { url: 'https://api.storj.io/', extendedKey: extendedKey }, { url: 'https://api.eu.storj.io', extendedKey: extendedKey } ], storagePath: tmpPath, storageManager: new StorageManager(new RAMStorageAdapter()) }); sandbox.stub(farmer, '_connectBridge').callsArg(1); farmer.connectBridges(); let connected = 0; farmer.on('bridgeConnected', () => { connected += 1; }); farmer.on('bridgesConnected', () => { expect(farmer._connectBridge.callCount).to.equal(2); expect(connected).to.equal(2); }); });
it('will set spaceAvailable to false bridges to disconnected', function() { let bridges = [{ url: 'api.storj.io', extendedKey: extendedKey1 }, { url: 'api.eu.storj.io', extendedKey: extendedKey2 }]; farmer = new FarmerInterface({ keyPair: KeyPair(), rpcPort: 0, tunnelServerPort: 0, doNotTraverseNat: true, logger: kad.Logger(0), bridges: bridges, storagePath: tmpPath, storageManager: new StorageManager(new RAMStorageAdapter()) }); expect(farmer.spaceAvailable).to.equal(true); farmer.noSpaceLeft(true); expect(farmer.spaceAvailable).to.equal(false); expect(farmer.bridges.get(extendedKey1).connected).to.equal(false); expect(farmer.bridges.get(extendedKey2).connected).to.equal(false); });
it('should not send offer if lookup fails', function(done) { farmer = new FarmerInterface({ keyPair: KeyPair(), rpcPort: 0, tunnelServerPort: 0, doNotTraverseNat: true, logger: kad.Logger(0), storagePath: tmpPath, storageManager: new StorageManager(new RAMStorageAdapter()) }); var _save = sinon.stub(farmer.storageManager, 'save').callsArgWith( 1, null ); var _sendOffer = sinon.stub(farmer, '_sendOfferForContract'); var _getContactByNodeID = sinon.stub( farmer.router, 'getContactByNodeID' ).returns(null); var _findNode = sinon.stub(farmer.router, 'findNode').callsArgWith( 2, new Error('Lookup failed') ); farmer._negotiateContract(Contract({ data_hash: utils.rmd160('some data'), renter_id: utils.rmd160('nodeid') })); _save.restore(); _getContactByNodeID.restore(); _sendOffer.restore(); _findNode.restore(); expect(_sendOffer.called).to.equal(true); done(); });
it('should remove contract from pending if no renter', function(done) { var farmer = new FarmerInterface({ keypair: KeyPair(), port: 0, noforward: true, logger: kad.Logger(0), backend: require('memdown'), storage: { path: 'test' } }); var _remove = sinon.stub(farmer, '_removeContractFromPendingList'); var _getContactByNodeID = sinon.stub( farmer._router, 'getContactByNodeID' ).returns(null); var _findNode = sinon.stub(farmer._router, 'findNode').callsArgWith( 1, null, [] ); farmer._negotiateContract(Contract({ data_hash: utils.rmd160('some data') })); setImmediate(function() { setImmediate(function() { setImmediate(function() { _getContactByNodeID.restore(); _findNode.restore(); _remove.restore(); expect(_remove.called).to.equal(true); done(); }); }); }); });
it('should log default error if none provided', function(done) { farmer = new FarmerInterface({ keyPair: KeyPair(), rpcPort: 0, tunnelServerPort: 0, doNotTraverseNat: true, logger: kad.Logger(0), storagePath: tmpPath, storageManager: new StorageManager(new RAMStorageAdapter()) }); var _send = sinon.stub(farmer.transport, 'send').callsArgWith( 2, null, { result: {} } ); var _warn = sinon.stub(farmer._logger, 'warn'); farmer._sendOfferForContract({ toObject: sinon.stub(), get: sinon.stub() }); _send.restore(); _warn.restore(); expect(_warn.calledWith('Renter refused to sign')).to.equal(true); done(); });
it('should log default error if none provided', function(done) { var farmer = new FarmerInterface({ keypair: KeyPair(), port: 0, noforward: true, logger: kad.Logger(0), backend: require('memdown'), storage: { path: 'test' } }); var _send = sinon.stub(farmer._transport, 'send').callsArgWith( 2, null, { result: {} } ); var _error = sinon.stub(farmer._logger, 'error'); farmer._sendOfferForContract({ toObject: sinon.stub(), get: sinon.stub() }); setImmediate(function() { _send.restore(); _error.restore(); expect(_error.calledWith('Renter refused to sign')).to.equal(true); done(); }); });
function createNode(opcodes, tunnels) { var node = null; var kp = new storj.KeyPair(); var manager = new storj.Manager(new storj.RAMStorageAdapter()); var datadir = path.join(os.tmpdir(), kp.getNodeID()); var port = STARTING_PORT--; fs.mkdirSync(datadir); var options = { keypair: kp, manager: manager, logger: kad.Logger(0), seeds: NODE_LIST.length ? [NODE_LIST[0]] : NODE_LIST, address: '127.0.0.1', port: port, opcodes: opcodes, noforward: true, tunnels: tunnels }; if (opcodes.length) { node = storj.FarmerInterface(options); } else { node = storj.RenterInterface(options); } NODE_LIST.push([ 'storj://127.0.0.1:', port, '/', kp.getNodeID() ].join('')); return node; }
it('should create an instance without the new keyword', function() { expect(DataChannelServer({ server: http.createServer(function noop() {}), manager: Manager(RAMStorageAdapter()), logger: Logger(0) })).to.be.instanceOf(DataChannelServer); });
it('should send 401 if not authed', function(done) { var server = new ShardServer({ storageManager: Manager(RAMStorageAdapter()), logger: Logger(0), nodeID: utils.rmd160('') }); var request = httpMocks.createRequest({ method: 'GET', url: '/shards/hash', params: { hash: utils.rmd160('data') }, query: { token: 'token' } }); var response = httpMocks.createResponse({ eventEmitter: EventEmitter, writableStream: stream.Writable, req: request }); response.on('end', function() { expect(response.statusCode).to.equal(401); done(); }); server.routeRetrieval(request, response); });
it('should error if it fails to save', function(done) { var proto = new Protocol({ network: { _logger: Logger(0), _manager: { load: sinon.stub().callsArgWith(1, null, { trees: { adc83b19e793491b1c6ea0fd8b46cd9f32e592fc: null }, contracts: { adc83b19e793491b1c6ea0fd8b46cd9f32e592fc: { get: function(key) { if (key === 'renter_id') { return 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc'; } else if (key === 'store_begin') { return Date.now() - 100; } else { return Date.now() + 100; } } } } }), save: sinon.stub().callsArgWith(1, new Error('Failed')) } } }); proto._handleConsign({ contact: { nodeID: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' } }, function(err) { expect(err.message).to.equal('Failed'); done(); }); });
it('should send 404 if cannot load item', function(done) { var manager = Manager(RAMStorageAdapter()); sinon.stub(manager, 'load').callsArgWith(1, new Error('Failed')); var server = new ShardServer({ storageManager: manager, logger: Logger(0), nodeID: utils.rmd160('') }); let contact = { nodeID: 'nodeid' }; server.accept('token', 'hash', contact); var request = httpMocks.createRequest({ method: 'GET', url: '/shards/hash', params: { hash: 'hash' }, query: { token: 'token' } }); var response = httpMocks.createResponse({ eventEmitter: EventEmitter, writableStream: stream.Writable, req: request }); response.on('end', function() { expect(response.statusCode).to.equal(404); done(); }); server.routeRetrieval(request, response); });
it('should not ask neighbors if max relays reached', function(done) { var proto = new Protocol({ network: { _logger: Logger(0), _router: { getNearestContacts: sinon.stub().returns([{}]) }, _contact: { nodeID: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' }, _transport: { _tunserver: { hasTunnelAvailable: sinon.stub().returns(false) } }, _tunnelers: { getContactList: sinon.stub().returns([]) } } }); proto._handleFindTunnel({ contact: { nodeID: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' }, relayers: [ 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc', 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' ] }, function(err, result) { expect(result.tunnels).to.have.lengthOf(0); done(); }); });
it('should close the socket if bad operation', function(done) { var dcs = DataChannelServer({ server: http.createServer(function noop() {}), manager: Manager(RAMStorageAdapter()), logger: Logger(0) }); dcs._allowed.token = { client: null, hash: 'test', expires: Date.now() + 12000 }; var socket = new EventEmitter(); socket.close = function(code, message) { expect(code).to.equal(400); expect(message).to.equal('Failed to handle the defined operation'); done(); }; dcs._handleConnection(socket); setImmediate(function() { socket.emit('message', JSON.stringify({ token: 'token', hash: 'test', operation: 'INVALID' })); }); });
it('should skip adding tunnels if bad format response', function(done) { var _forEach = sinon.stub(); var proto = new Protocol({ network: { _logger: Logger(0), _router: { getNearestContacts: sinon.stub().returns([{}]) }, _contact: { nodeID: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' }, _transport: { send: sinon.stub().callsArgWith(2, null, { result: { tunnels: { forEach: _forEach } } }) }, _tunnelers: { getContactList: sinon.stub().returns([]) } } }); proto._askNeighborsForTunnels([], function() { expect(_forEach.called).to.equal(false); done(); }); });
it('should not send data if the connection closes', function(done) { var shard = new EventEmitter(); var socket = new EventEmitter(); socket.readyState = 3; shard.pause = sinon.stub(); shard.removeAllListeners = sinon.stub(); var manager = Manager(RAMStorageAdapter()); var dcs = DataChannelServer({ server: http.createServer(function noop() {}), manager: manager, logger: Logger(0) }); var _load = sinon.stub(manager, 'load').callsArgWith( 1, null, { shard: shard } ); dcs._allowed.token = { hash: 'hash' }; dcs._handleRetrieveStream(socket, 'token'); setImmediate(function() { _load.restore(); shard.emit('data', new Buffer('ohai')); setImmediate(function() { expect(shard.removeAllListeners.called).to.equal(true); expect(dcs._allowed.token).to.equal(undefined); done(); }); }); });
it('should respond with no tunnels if none found', function(done) { var _addContact = sinon.stub(); var proto = new Protocol({ network: { _logger: Logger(0), _router: { getNearestContacts: sinon.stub().returns([{}]) }, _contact: { nodeID: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' }, _transport: { _createContact: sinon.stub(), send: sinon.stub().callsArgWith(2, null, { result: { tunnels: [] } }) }, _tunnelers: { addContact: _addContact, getContactList: sinon.stub().returns([]), getSize: sinon.stub().returns(19) } } }); proto._askNeighborsForTunnels([], function(err, result) { expect(_addContact.called).to.equal(false); expect(result.tunnels).to.have.lengthOf(0); done(); }); });
it('should error if the consign is early or late', function(done) { var proto = new Protocol({ network: { _logger: Logger(0), _manager: { load: sinon.stub().callsArgWith(1, null, { trees: { adc83b19e793491b1c6ea0fd8b46cd9f32e592fc: null }, contracts: { adc83b19e793491b1c6ea0fd8b46cd9f32e592fc: { get: function(key) { if (key === 'renter_id') { return 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc'; } else if (key === 'store_begin') { return Date.now() + 200 + constants.CONSIGN_THRESHOLD; } else { return Date.now() + 400 + constants.CONSIGN_THRESHOLD; } } } } }) } } }); proto._handleConsign({ contact: { nodeID: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' } }, function(err) { expect(err.message).to.equal( 'Consignment violates contract store time' ); done(); }); });
it('should fail if contract incomplete', function(done) { var proto = new Protocol({ network: { _logger: Logger(0), _keypair: KeyPair(), _pendingContracts: { adc83b19e793491b1c6ea0fd8b46cd9f32e592fc: function() {} } } }); var contract = { get: sinon.stub().returns('adc83b19e793491b1c6ea0fd8b46cd9f32e592fc'), verify: sinon.stub().returns(true), isComplete: sinon.stub().returns(false), sign: sinon.stub() }; var contact = { address: '127.0.0.1', port: 1337, nodeID: 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' }; proto._verifyContract(contract, contact, function(err) { expect(err.message).to.equal('Contract is not complete'); done(); }); });
it('should return false if we have a contract and shard', function(done) { FarmerInterface.Negotiator.call({ _options: { storagePath: '/tmp' }, _logger: kad.Logger(0), isBridgeConnected: sinon.stub().returns(true), _offerBackoffLimit: 4, transport: { shardServer: { activeTransfers: 0 } }, storageManager: { load: sinon.stub().callsArgWith(1, null, { contracts: { '5ebef6c9f0cabf23c3565941e76fb6e5320143d3': {} }, shard: { read: sinon.stub() } }) } }, new Contract({ data_hash: utils.rmd160(''), renter_id: '5ebef6c9f0cabf23c3565941e76fb6e5320143d3' }), function(result) { expect(result).to.equal(false); done(); }); });