├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── lib ├── beanstalk_client.js └── net.js ├── package-lock.json ├── package.json └── tests ├── helper.js ├── test_ignore.js ├── test_kick.js ├── test_list_tube_used.js ├── test_list_tubes.js ├── test_list_tubes_watched.js ├── test_multiline_put.js ├── test_peek_buried.js ├── test_peek_delayed.js ├── test_peek_ready.js ├── test_put_buffer.js ├── test_put_in_forloop.js ├── test_put_peek_delete.js ├── test_put_stats_job_delete.js ├── test_quit.js ├── test_reserve.js ├── test_reserve_buffer.js ├── test_reserve_jobs_multichunk.js ├── test_reserve_jobs_multichunk_timeout.js ├── test_reserve_with_timeout.js ├── test_stats.js ├── test_stats_job.js ├── test_stats_tube.js ├── test_stats_tube_notfound.js ├── test_use.js ├── test_utf8.js ├── test_utf8_reserve.js └── test_watch.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | docs 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "13.0" 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2010, 2011 Pascal Opitz. All rights reserved. 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to 4 | deal in the Software without restriction, including without limitation the 5 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 6 | sell copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 18 | IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A Beanstalk client utilising node.js 2 | Tested for beanstalkd 1.4.6 3 | 4 | [![Build Status](https://travis-ci.org/pascalopitz/nodestalker.png)](https://travis-ci.org/pascalopitz/nodestalker) 5 | 6 | [![Dependencies](https://david-dm.org/pascalopitz/nodestalker.png)](https://david-dm.org/pascalopitz/nodestalker) 7 | 8 | [![NPM](http://nodei.co/npm/nodestalker.png)](http://nodei.co/npm/nodestalker/) 9 | 10 | ## INSTALL 11 | 12 | npm install nodestalker 13 | 14 | 15 | ## USAGE 16 | 17 | Simple usage example: 18 | 19 | var bs = require('nodestalker'), 20 | client = bs.Client('127.0.0.1:11300'); 21 | 22 | client.use('default').onSuccess(function(data) { 23 | console.log(data); 24 | 25 | client.put('my job').onSuccess(function(data) { 26 | console.log(data); 27 | client.disconnect(); 28 | }); 29 | }); 30 | 31 | 32 | 33 | 34 | ### How do I reserve multiple items? 35 | 36 | Each client basically represents one open socket to beanstalkd. 37 | Each command call just pumps one command into that socket, which then expects a corresponding return. 38 | 39 | The server should maintain the state of the socket. 40 | However, reserve (or reserve with timeout) will only pull one job. 41 | You should then be able to reserve again on the same socket with the state of watch and ignore still preserved by the server. 42 | 43 | Probably the most common usage scenario: 44 | 45 | var bs = require('nodestalker'), 46 | client = bs.Client('127.0.0.1:11300'), 47 | tube = 'test_tube'; 48 | 49 | client.watch(tube).onSuccess(function(data) { 50 | function resJob() { 51 | client.reserve().onSuccess(function(job) { 52 | console.log('reserved', job); 53 | 54 | client.deleteJob(job.id).onSuccess(function(del_msg) { 55 | console.log('deleted', job); 56 | console.log('message', del_msg); 57 | resJob(); 58 | }); 59 | }); 60 | } 61 | 62 | resJob(); 63 | }); 64 | 65 | If you want to do this fully in a fully asynchronous way, because there's a blocking process happening otherwise, you'll have to work with multiple sockets. 66 | This means that you'll have to repeat watch and ignore commands for each socket. 67 | 68 | var bs = require('nodestalker'), 69 | tube = 'test_tube'; 70 | 71 | function processJob(job, callback) { 72 | // doing something really expensive 73 | console.log('processing...'); 74 | setTimeout(function() { 75 | callback(); 76 | }, 1000); 77 | } 78 | 79 | function resJob() { 80 | var client = bs.Client('127.0.0.1:11300'); 81 | 82 | client.watch(tube).onSuccess(function(data) { 83 | client.reserve().onSuccess(function(job) { 84 | console.log('received job:', job); 85 | resJob(); 86 | 87 | processJob(job, function() { 88 | client.deleteJob(job.id).onSuccess(function(del_msg) { 89 | console.log('deleted', job); 90 | console.log(del_msg); 91 | client.disconnect(); 92 | }); 93 | console.log('processed', job); 94 | }); 95 | }); 96 | }); 97 | } 98 | 99 | resJob(); 100 | 101 | 102 | ## DOCUMENTATION 103 | 104 | npm run-script docs 105 | 106 | Annotated source is now in the docs folder 107 | 108 | ## TESTING 109 | 110 | Also there are some tests now. 111 | Please make sure beanstalkd is running on the default settings. 112 | 113 | To run all tests: 114 | 115 | npm test 116 | 117 | 118 | ## CREDIT 119 | 120 | Depends on the yaml package by nodeca. 121 | 122 | https://github.com/nodeca/js-yaml 123 | 124 | Thanks to people that took time to fix some things. 125 | 126 | aahoughton 127 | andho 128 | jney 129 | nmcquay 130 | tokudu 131 | justinwalsh 132 | yeldarby 133 | cincodenada 134 | -------------------------------------------------------------------------------- /lib/beanstalk_client.js: -------------------------------------------------------------------------------- 1 | // Includes 2 | var isChrome = false; 3 | 4 | try { 5 | isChrome = chrome.sockets.tcp 6 | } catch (e) { 7 | 8 | } 9 | 10 | 11 | var events = require('events'), 12 | net = (!isChrome) ? require('net') : require('./net'), 13 | util = require('util'), 14 | yaml = require('js-yaml'); 15 | 16 | 17 | // ###simple debug console 18 | var Debug = new function() { 19 | var active = false; 20 | 21 | this.log = function(str) { 22 | if(active) { 23 | console.log(str.toString()); 24 | } 25 | }; 26 | 27 | this.activate = function() { 28 | active = true; 29 | }; 30 | }; 31 | 32 | // ###Job wrapper 33 | // returns an object that represents a job 34 | var BeanstalkJob = {}; 35 | BeanstalkJob.create = function(data) { 36 | if(data.length == 2) { 37 | return { 38 | id : data[0], 39 | data : data[1] 40 | }; 41 | } 42 | return false; 43 | }; 44 | 45 | 46 | // ##Internal command object 47 | function BeanstalkCommand(obj, isRaw) { 48 | this._obj = obj; 49 | this._isRaw = isRaw 50 | events.EventEmitter.call(this); 51 | }; 52 | util.inherits(BeanstalkCommand, events.EventEmitter); 53 | 54 | BeanstalkCommand.prototype.commandObject = function() { 55 | return this._obj; 56 | }; 57 | 58 | BeanstalkCommand.prototype.command = function(cmd) { 59 | if(!cmd) { 60 | return this._obj.hasOwnProperty('command') ? this._obj.command : null; 61 | } 62 | this._obj.command = cmd; 63 | return this; 64 | }; 65 | 66 | BeanstalkCommand.prototype.expected = function(expected) { 67 | if(!expected) { 68 | var obj = this.commandObject(); 69 | if( obj.hasOwnProperty('expected') ) { 70 | return (typeof obj.expected === "string") ? [ obj.expected ] : obj.expected; 71 | } 72 | return []; 73 | } 74 | this._obj.expected = expected; 75 | return this; 76 | }; 77 | 78 | BeanstalkCommand.prototype.isYaml = function(isYaml) { 79 | if(!isYaml) { 80 | return this._obj.hasOwnProperty('is_yaml') ? this._obj.is_yaml : 0; 81 | } 82 | this._obj.is_yaml = isYaml; 83 | return this; 84 | }; 85 | 86 | // simulates callback style, but calls immediately, in order to inject 87 | // subcommands into expected call queue location 88 | BeanstalkCommand.prototype.then = function(fn) { 89 | fn(); 90 | return this; 91 | }; 92 | 93 | BeanstalkCommand.prototype.onEnd = function(fn) { 94 | this.addListener('command_error', function(err) { 95 | fn(err, null); 96 | }); 97 | 98 | this.addListener('command_success', function(data) { 99 | fn(null, data); 100 | }); 101 | 102 | return this; 103 | }; 104 | 105 | BeanstalkCommand.prototype.onError = function(fn) { 106 | this.addListener('command_error', fn); 107 | return this; 108 | }; 109 | 110 | BeanstalkCommand.prototype.onSuccess = function(fn) { 111 | this.addListener('command_success', fn); 112 | return this; 113 | }; 114 | 115 | BeanstalkCommand.prototype.multiBuffer = null; 116 | BeanstalkCommand.prototype.rawBuffers = []; 117 | BeanstalkCommand.prototype.multiErrorTimer = null; 118 | BeanstalkCommand.prototype.multiErrorOccurred = false; 119 | 120 | BeanstalkCommand.prototype.responseHandler = function(data, callback) { 121 | 122 | if(this.multiErrorOccurred) { 123 | Debug.log('responseHandler skip'); 124 | return false; 125 | } 126 | 127 | var self = this, firstLine, jobdata, lines; 128 | var dataString = data.toString(); 129 | 130 | // if we're handling an additional http chunk 131 | if(this.multiBuffer) { 132 | clearTimeout(this.multiErrorTimer); 133 | dataString = this.multiBuffer + dataString; 134 | } 135 | 136 | Debug.log( "responseHandler data: '" + dataString + "'"); 137 | 138 | lines = dataString.split('\r\n'); 139 | firstLine = lines.shift(); 140 | var chunks = firstLine.split(' '); 141 | 142 | var expected = this.expected(); 143 | var expected_match = false; 144 | 145 | for(var i=0; i is not completed yet 162 | this.rawBuffers.push(data); 163 | } 164 | 165 | this.multiErrorTimer = setTimeout(function () { 166 | self.emit('command_error', chunks); 167 | self.multiErrorOccurred = true; 168 | }, this._obj.reserve_multichunk_timeout); 169 | return false; 170 | } 171 | } 172 | 173 | if(!expected_match) { 174 | Debug.log( 'responseHandler command_error' ); 175 | this.emit('command_error', chunks); 176 | return false; 177 | } 178 | 179 | // handle multiline data correctly 180 | if(lines.length > 1) { 181 | lines.pop(); 182 | jobdata = lines.join('\r\n'); 183 | } 184 | 185 | if(this.isYaml() && jobdata) { 186 | Debug.log( 'responseHandler command_success isYaml' ); 187 | this.emit('command_success', yaml.load(jobdata)); 188 | } else { 189 | if(chunks.length > 1) { 190 | chunks.shift(); 191 | 192 | if(jobdata) { 193 | chunks.pop(); 194 | 195 | if(this._isRaw) { 196 | // Append last buffer, full copy of the array (prototype), 197 | // create the full buffer and extract 198 | this.rawBuffers.push(data); 199 | var rawBuffersCopy = this.rawBuffers.slice(); 200 | this.rawBuffers.length = 0; 201 | var reserveOutput = Buffer.concat(rawBuffersCopy); 202 | chunks.push(this._extractDataReserveOutput(reserveOutput)); 203 | } else { 204 | chunks.push(jobdata); 205 | } 206 | 207 | chunks = BeanstalkJob.create(chunks); 208 | } 209 | } 210 | 211 | Debug.log( 'responseHandler command_success' ); 212 | this.emit('command_success', chunks); 213 | } 214 | 215 | return true; 216 | }; 217 | 218 | /** 219 | * Extract from the full response for reserve command looking for 220 | * the first "\r\n" aparition. 221 | */ 222 | BeanstalkCommand.prototype._extractDataReserveOutput = function(buff) { 223 | var i; 224 | var length = buff.length; 225 | 226 | for(i = 0; i < length - 1; i++) { 227 | if(buff[i] === 0x0d && buff[i+1] === 0x0a) { 228 | return buff.slice(i + 2, length - 2); 229 | } 230 | } 231 | return buff; 232 | }; 233 | 234 | // ##Beanstalk client 235 | // A client that binds to one single socket 236 | function BeanstalkClient() { 237 | events.EventEmitter.call(this); 238 | 239 | this.address = '127.0.0.1'; 240 | this.port = 11300; 241 | this.isRaw = false; 242 | this.conn; 243 | this.default_priority = 10; 244 | this.reserve_multichunk_timeout = 500; 245 | 246 | this.queue = []; 247 | this.waitingForResponses = false; 248 | }; 249 | util.inherits(BeanstalkClient, events.EventEmitter); 250 | 251 | // Singleton like method that returns an instance 252 | BeanstalkClient.prototype.Instance = function(config, isRaw) { 253 | if (config) { 254 | if (typeof config == 'string') { 255 | var c = config.split(':'); 256 | this.address = c[0] || this.address; 257 | this.port = c[1] || this.port; 258 | this.isRaw = isRaw || this.isRaw; 259 | } else { 260 | this.address = config.address || this.address; 261 | this.port = config.port || this.port; 262 | this.isRaw = config.isRaw || this.isRaw; 263 | } 264 | } 265 | 266 | return this; 267 | }; 268 | 269 | // executes command 270 | BeanstalkClient.prototype.command = function(obj) { 271 | var _self = this; 272 | obj.reserve_multichunk_timeout = this.reserve_multichunk_timeout; 273 | var cmd = new BeanstalkCommand(obj, this.isRaw); 274 | 275 | // pushes commands to the server 276 | var requestExec = function() { 277 | if(!_self.waitingForResponse && _self.queue.length) { 278 | _self.waitingForResponse = true; 279 | var cmd = _self.queue.shift(); 280 | 281 | if(_self.conn) { 282 | _self.conn.removeAllListeners('data'); 283 | _self.conn.addListener('data', function(data) { 284 | Debug.log('response:'); 285 | Debug.log(data); 286 | cmd.responseHandler.call(cmd, data); 287 | }); 288 | } 289 | Debug.log('request:'); 290 | Debug.log(cmd.command()); 291 | process.nextTick(function() { 292 | _self.conn.write(cmd.command()); 293 | }); 294 | } 295 | }; 296 | 297 | // makes sure that if there's another command queued, it gets done 298 | cmd.addListener('command_success', function(data) { 299 | _self.waitingForResponse = false; 300 | requestExec(); 301 | }); 302 | 303 | // if the command fails, event an error 304 | cmd.addListener('command_error', function(data) { 305 | _self.waitingForResponse = false; 306 | _self.emit('end', 'Command failed'); 307 | }); 308 | 309 | // put every command into the local queue to control execution order 310 | this.queue.push(cmd); 311 | 312 | if(!this.conn) { 313 | // if there's no connection, create one 314 | this.conn = net.createConnection(this.port, this.address); 315 | this.conn.setNoDelay(); 316 | this.conn.setKeepAlive(); 317 | 318 | this.conn.addListener('connect', function() { 319 | Debug.log('connected: '+_self.address+':'+_self.port); 320 | _self.emit('connect', _self.address+':'+_self.port); 321 | requestExec(); 322 | }); 323 | 324 | this.conn.addListener('end', function(err) { 325 | _self.emit('end', err); 326 | Debug.log('connection ended, writeOnly from now on'); 327 | }); 328 | 329 | this.conn.addListener('error', function(err) { 330 | _self.emit('error', err); 331 | Debug.log('connection error'); 332 | }); 333 | 334 | this.conn.addListener('close', function(err) { 335 | _self.emit('close', err); 336 | Debug.log('connection closed'); 337 | }); 338 | } else { 339 | requestExec(); 340 | } 341 | 342 | return cmd; 343 | }; 344 | 345 | // disconnects a client 346 | BeanstalkClient.prototype.disconnect = function() { 347 | this.conn.end(); 348 | this.conn.destroy(); 349 | this.conn = null; 350 | }; 351 | 352 | // ##Beanstalk client commands 353 | 354 | // ###use 355 | // uses tube, this is for producers 356 | BeanstalkClient.prototype.use = function(tube) { 357 | return this.command({ 358 | command: 'use '+tube+'\r\n', 359 | expected: 'USING' 360 | }); 361 | }; 362 | 363 | // ###watch 364 | // watches tube, this is for receivers 365 | BeanstalkClient.prototype.watch = function(tube) { 366 | return this.command({ 367 | command: 'watch '+tube+'\r\n', 368 | expected: 'WATCHING' 369 | }); 370 | }; 371 | 372 | // ###ignore 373 | // ignores tube 374 | BeanstalkClient.prototype.ignore = function(tube) { 375 | return this.command({ 376 | command: 'ignore '+tube+'\r\n', 377 | expected: ['WATCHING', 'NOT_IGNORED'] 378 | }); 379 | }; 380 | 381 | // ###put 382 | // puts data in a tube 383 | BeanstalkClient.prototype.put = function(data, priority, delay, ttr) { 384 | if(typeof priority == 'undefined') { 385 | priority = this.default_priority; 386 | } 387 | 388 | if(typeof delay == 'undefined') { 389 | delay = 0; 390 | } 391 | 392 | if(typeof ttr == 'undefined') { 393 | ttr = 100000; 394 | } 395 | 396 | return this.command({ 397 | command: this._createPutCommand(data, priority, delay, ttr), 398 | expected: 'INSERTED' 399 | }); 400 | }; 401 | 402 | // ###reserve 403 | // picks up job from tube 404 | BeanstalkClient.prototype.reserve = function() { 405 | return this.command({ 406 | command: 'reserve\r\n', 407 | expected: 'RESERVED' 408 | }); 409 | }; 410 | 411 | // ###reserve 412 | // picks up job from tube, with timeout 413 | BeanstalkClient.prototype.reserve_with_timeout = function(time) { 414 | return this.command({ 415 | command: 'reserve-with-timeout '+time+'\r\n', 416 | expected: 'RESERVED' 417 | }); 418 | }; 419 | // camel case alias 420 | BeanstalkClient.prototype.reserveWithTimeout = BeanstalkClient.prototype.reserve_with_timeout; 421 | 422 | // ###touch 423 | // tell the server that you're still working on a job 424 | BeanstalkClient.prototype.touch = function(id) { 425 | return this.command({ 426 | command: 'touch '+id+'\r\n', 427 | expected: 'TOUCHED' 428 | }); 429 | }; 430 | 431 | 432 | // ###delete 433 | // delets job from queue 434 | BeanstalkClient.prototype.deleteJob = function(id) { 435 | return this.command({ 436 | command: 'delete '+id+'\r\n', 437 | expected: 'DELETED' 438 | }); 439 | }; 440 | 441 | // ###release 442 | // releases job from reserved state 443 | BeanstalkClient.prototype.release = function(id, priority, delay) { 444 | if(typeof priority == 'undefined') { 445 | priority = this.default_priority; 446 | } 447 | 448 | if(typeof delay == 'undefined') { 449 | delay = 0; 450 | } 451 | 452 | return this.command({ 453 | command: 'release '+id+' '+priority+' '+delay+'\r\n', 454 | expected: 'RELEASED' 455 | }); 456 | }; 457 | 458 | 459 | // ###bury 460 | // buries job so it isn't picked up by reserve 461 | BeanstalkClient.prototype.bury = function(id, priority) { 462 | if(typeof priority == 'undefined') { 463 | priority = this.default_priority; 464 | } 465 | 466 | return this.command({ 467 | command: 'bury '+id+' '+priority+'\r\n', 468 | expected: 'BURIED' 469 | }); 470 | }; 471 | 472 | // ###kick 473 | // kicks buried job back into queue 474 | BeanstalkClient.prototype.kick = function(bound) { 475 | return this.command({ 476 | command: 'kick '+bound+'\r\n', 477 | expected: 'KICKED' 478 | }); 479 | }; 480 | 481 | // ###peek 482 | // let's you inspect a job 483 | BeanstalkClient.prototype.peek = function(id) { 484 | return this.command({ 485 | command: 'peek '+id+'\r\n', 486 | expected: [ 'FOUND', 'NOT_FOUND' ] 487 | }); 488 | }; 489 | 490 | // ###peek-ready 491 | // let's you inspect the next ready job 492 | BeanstalkClient.prototype.peek_ready = function() { 493 | return this.command({ 494 | command: 'peek-ready\r\n', 495 | expected: [ 'FOUND', 'NOT_FOUND' ] 496 | }); 497 | }; 498 | // camel case alias 499 | BeanstalkClient.prototype.peekReady = BeanstalkClient.prototype.peek_ready; 500 | 501 | // ###peek-delayed 502 | // let's you inspect the next delayed job 503 | BeanstalkClient.prototype.peek_delayed = function() { 504 | return this.command({ 505 | command: 'peek-delayed\r\n', 506 | expected: [ 'FOUND', 'NOT_FOUND' ] 507 | }); 508 | }; 509 | // camel case alias 510 | BeanstalkClient.prototype.peekDelayed = BeanstalkClient.prototype.peek_delayed; 511 | 512 | // ###peek-buried 513 | // let's you inspect the next buried job 514 | BeanstalkClient.prototype.peek_buried = function() { 515 | return this.command({ 516 | command: 'peek-buried\r\n', 517 | expected: [ 'FOUND', 'NOT_FOUND' ] 518 | }); 519 | }; 520 | // camel case alias 521 | BeanstalkClient.prototype.peekBuried = BeanstalkClient.prototype.peek_buried; 522 | 523 | // ###stats 524 | // gives statistical information about the server 525 | BeanstalkClient.prototype.stats = function() { 526 | return this.command({ 527 | command: 'stats\r\n', 528 | expected: 'OK', 529 | is_yaml: 1 530 | }); 531 | }; 532 | 533 | // ###stats-job 534 | // gives statistical information about the specified job if it exists 535 | BeanstalkClient.prototype.stats_job = function(id) { 536 | return this.command({ 537 | command: 'stats-job '+id+'\r\n', 538 | expected: ['OK', 'NOT_FOUND'], 539 | is_yaml: 1 540 | }); 541 | }; 542 | // camel case alias 543 | BeanstalkClient.prototype.statsJob = BeanstalkClient.prototype.stats_job; 544 | 545 | // ###stats-tube 546 | // gives statistical information about the specified tube if it exists 547 | BeanstalkClient.prototype.stats_tube = function(tube) { 548 | return this.command({ 549 | command: 'stats-tube '+tube+'\r\n', 550 | expected: ['OK', 'NOT_FOUND'], 551 | is_yaml: 1 552 | }); 553 | }; 554 | // camel case alias 555 | BeanstalkClient.prototype.statsTube = BeanstalkClient.prototype.stats_tube; 556 | 557 | // ###list-tubes 558 | // lists all existing tubes 559 | BeanstalkClient.prototype.list_tubes = function() { 560 | return this.command({ 561 | command: 'list-tubes\r\n', 562 | expected: 'OK', 563 | is_yaml: 1 564 | }); 565 | }; 566 | // camel case alias 567 | BeanstalkClient.prototype.listTubes = BeanstalkClient.prototype.list_tubes; 568 | 569 | // ###list-tubes-watched 570 | // lists all existing tubes that are currently watched 571 | BeanstalkClient.prototype.list_tubes_watched = function() { 572 | return this.command({ 573 | command: 'list-tubes-watched\r\n', 574 | expected: 'OK', 575 | is_yaml: 1 576 | }); 577 | }; 578 | // camel case alias 579 | BeanstalkClient.prototype.listTubesWatched = BeanstalkClient.prototype.list_tubes_watched; 580 | 581 | // ###list-tube-used 582 | // returns the tube currently being used by the client 583 | BeanstalkClient.prototype.list_tube_used = function() { 584 | return this.command({ 585 | command: 'list-tube-used\r\n', 586 | expected: 'USING' 587 | }); 588 | }; 589 | // camel case alias 590 | BeanstalkClient.prototype.listTubeUsed = BeanstalkClient.prototype.list_tube_used; 591 | 592 | // ###pause-tube 593 | // can delay any new job being reserved for a given time 594 | BeanstalkClient.prototype.pause_tube = function(tube, delay) { 595 | return this.command({ 596 | command: 'pause-tube '+tube+' '+delay+'\r\n', 597 | expected: 'PAUSED' 598 | }); 599 | }; 600 | // camel case alias 601 | BeanstalkClient.prototype.pauseTube = BeanstalkClient.prototype.pause_tube; 602 | 603 | // ###quit 604 | // closes connection 605 | BeanstalkClient.prototype.quit = function() { 606 | return this.command({ 607 | command: 'quit\r\n' 608 | }); 609 | }; 610 | 611 | // Private 612 | 613 | /** 614 | * Creates the correct put command for the data provided. It allows to send strings or 615 | * raw buffers to Beanstalk. 616 | * 617 | * @param {string|Buffer} data 618 | * @param {number} priority 619 | * @param {number} delay 620 | * @param {number} ttr 621 | * @returns {string|Buffer} 622 | * @private 623 | */ 624 | BeanstalkClient.prototype._createPutCommand = function(data, priority, delay, ttr) { 625 | var command; 626 | 627 | if(typeof data === 'string') { 628 | command = 'put ' + priority + ' ' + delay + ' ' + ttr + ' ' 629 | + Buffer.byteLength(data.toString(), 'utf8') + '\r\n' + data + '\r\n'; 630 | } else { 631 | var commandBegin = 'put ' + priority + ' ' + delay + ' ' + ttr + ' ' + data.length + '\r\n'; 632 | var commandEnd = '\r\n'; 633 | 634 | command = Buffer.alloc(commandBegin.length + data.length + commandEnd.length); 635 | command.write(commandBegin, 0, commandBegin.length, 'binary'); 636 | data.copy(command, commandBegin.length, 0, data.length); 637 | command.write(commandEnd, commandBegin.length + data.length, commandEnd.length, 'binary'); 638 | } 639 | 640 | return command; 641 | }; 642 | 643 | // ##Exposed to node 644 | var Beanstalk = function(server, isRaw) { 645 | var c = new BeanstalkClient; 646 | return c.Instance(server, isRaw); 647 | }; 648 | 649 | exports.Client = Beanstalk; 650 | exports.Debug = Debug; 651 | -------------------------------------------------------------------------------- /lib/net.js: -------------------------------------------------------------------------------- 1 | var events = require('events'), 2 | util = require('util'); 3 | 4 | 5 | var connections = {}; 6 | 7 | chrome.sockets.tcp.onReceive.addListener(function(info) { 8 | var con = connections[info.socketId]; 9 | 10 | if(!con) { 11 | return; 12 | } 13 | 14 | con.emit('data', ab2str(info.data)); 15 | }); 16 | 17 | chrome.sockets.tcp.onReceiveError.addListener(function(info) { 18 | var con = connections[info.socketId]; 19 | 20 | if(!con) { 21 | return; 22 | } 23 | 24 | con.emit('error', ab2str(info.data)); 25 | }); 26 | 27 | function ab2str(buf) { 28 | return String.fromCharCode.apply(null, new Uint8Array(buf)); 29 | } 30 | 31 | function str2ab(str) { 32 | var buf = new ArrayBuffer(str.length); // 2 bytes for each char 33 | var bufView = new Uint8Array(buf); 34 | for (var i=0, strLen=str.length; i < strLen; i++) { 35 | bufView[i] = str.charCodeAt(i); 36 | } 37 | return buf; 38 | } 39 | 40 | function Connection(p, a) { 41 | 42 | var self = this; 43 | this.port = p; 44 | this.address = a; 45 | this.socketId = null; 46 | this.noDelay = false; 47 | this.keepAlive = false; 48 | 49 | window.setTimeout(function () { 50 | chrome.sockets.tcp.create({}, function (info) { 51 | self.socketId = info.socketId; 52 | connections[info.socketId] = self; 53 | 54 | 55 | chrome.sockets.tcp.connect(self.socketId, self.address, self.port, function (cInfo) { 56 | 57 | if(cInfo < 0) { 58 | self.emit('error', 'socket connection failed'); 59 | return; 60 | } 61 | 62 | chrome.sockets.tcp.setNoDelay(self.socketId, self.noDelay, function () { 63 | chrome.sockets.tcp.setKeepAlive(self.socketId, self.keepAlive, 100, function () { 64 | self.emit('connect'); 65 | }); 66 | }); 67 | }); 68 | }); 69 | }, 10); 70 | } 71 | 72 | util.inherits(Connection, events.EventEmitter); 73 | 74 | Connection.prototype.write = function (data) { 75 | var self = this; 76 | 77 | chrome.sockets.tcp.send(this.socketId, str2ab(data), function (info) { 78 | //self.emit('close'); 79 | if(info.resultCode < 0) { 80 | self.emit('error', info.resultCode); 81 | } 82 | }); 83 | }; 84 | 85 | Connection.prototype.close = function () { 86 | var self = this; 87 | 88 | chrome.sockets.tcp.close(this.socketId, function () { 89 | self.emit('close'); 90 | }); 91 | }; 92 | 93 | Connection.prototype.end = function () { 94 | var self = this; 95 | 96 | chrome.sockets.tcp.disconnect(this.socketId, function () { 97 | self.emit('disconnect'); 98 | delete connections[self.socketId]; 99 | }); 100 | }; 101 | 102 | Connection.prototype.destroy = function () { 103 | // noop 104 | }; 105 | 106 | Connection.prototype.setNoDelay = function () { 107 | this.noDelay = true; 108 | }; 109 | 110 | Connection.prototype.setKeepAlive = function () { 111 | this.keepAlive = true; 112 | }; 113 | 114 | module.exports = { 115 | createConnection: function (p, a) { 116 | return new Connection (p, a); 117 | } 118 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodestalker", 3 | "version": "0.1.22", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "argparse": { 8 | "version": "1.0.10", 9 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 10 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 11 | "requires": { 12 | "sprintf-js": "~1.0.2" 13 | } 14 | }, 15 | "commander": { 16 | "version": "5.0.0", 17 | "resolved": "https://registry.npmjs.org/commander/-/commander-5.0.0.tgz", 18 | "integrity": "sha512-JrDGPAKjMGSP1G0DUoaceEJ3DZgAfr/q6X7FVk4+U5KxUSKviYGM2k6zWkfyyBHy5rAtzgYJFa1ro2O9PtoxwQ==", 19 | "dev": true 20 | }, 21 | "docco": { 22 | "version": "0.8.0", 23 | "resolved": "https://registry.npmjs.org/docco/-/docco-0.8.0.tgz", 24 | "integrity": "sha512-QcWBDnnGaT+rgC0wqynznXv0/4hd6nAFdWNs2fN4FvkH2yAnCYVeRU7GIZXNCeUQ955Lufq+TmZcSXiBa1cGQQ==", 25 | "dev": true, 26 | "requires": { 27 | "commander": ">= 0.5.2", 28 | "fs-extra": ">= 0.6.0", 29 | "highlight.js": ">= 8.0.x", 30 | "marked": ">= 0.2.7", 31 | "underscore": ">= 1.0.0" 32 | } 33 | }, 34 | "esprima": { 35 | "version": "4.0.1", 36 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 37 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" 38 | }, 39 | "fs-extra": { 40 | "version": "8.1.0", 41 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", 42 | "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", 43 | "dev": true, 44 | "requires": { 45 | "graceful-fs": "^4.2.0", 46 | "jsonfile": "^4.0.0", 47 | "universalify": "^0.1.0" 48 | } 49 | }, 50 | "graceful-fs": { 51 | "version": "4.2.3", 52 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", 53 | "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", 54 | "dev": true 55 | }, 56 | "highlight.js": { 57 | "version": "9.18.1", 58 | "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.1.tgz", 59 | "integrity": "sha512-OrVKYz70LHsnCgmbXctv/bfuvntIKDz177h0Co37DQ5jamGZLVmoCVMtjMtNZY3X9DrCcKfklHPNeA0uPZhSJg==", 60 | "dev": true 61 | }, 62 | "js-yaml": { 63 | "version": "3.13.1", 64 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 65 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 66 | "requires": { 67 | "argparse": "^1.0.7", 68 | "esprima": "^4.0.0" 69 | } 70 | }, 71 | "jsonfile": { 72 | "version": "4.0.0", 73 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", 74 | "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", 75 | "dev": true, 76 | "requires": { 77 | "graceful-fs": "^4.1.6" 78 | } 79 | }, 80 | "marked": { 81 | "version": "0.8.0", 82 | "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.0.tgz", 83 | "integrity": "sha512-MyUe+T/Pw4TZufHkzAfDj6HarCBWia2y27/bhuYkTaiUnfDYFnCP3KUN+9oM7Wi6JA2rymtVYbQu3spE0GCmxQ==", 84 | "dev": true 85 | }, 86 | "sprintf-js": { 87 | "version": "1.0.3", 88 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 89 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" 90 | }, 91 | "underscore": { 92 | "version": "1.9.2", 93 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.2.tgz", 94 | "integrity": "sha512-D39qtimx0c1fI3ya1Lnhk3E9nONswSKhnffBI0gME9C99fYOkNi04xs8K6pePLhvl1frbDemkaBQ5ikWllR2HQ==", 95 | "dev": true 96 | }, 97 | "universalify": { 98 | "version": "0.1.2", 99 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 100 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", 101 | "dev": true 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodestalker", 3 | "description": "A Beanstalk client for node.js.", 4 | "keywords": [ 5 | "beanstalkd", 6 | "queue" 7 | ], 8 | "version": "0.1.22", 9 | "author": "Pascal Opitz (http://blog.pascalopitz.com)", 10 | "contributors": [ 11 | { 12 | "name": "Andrew Houghton", 13 | "github": "https://github.com/aahoughton" 14 | }, 15 | { 16 | "name": "Amjad Mohamed", 17 | "github": "https://github.com/andho" 18 | }, 19 | { 20 | "name": "Jean-Sébastien Ney", 21 | "github": "https://github.com/jney" 22 | }, 23 | { 24 | "name": "Nate McQuay", 25 | "github": "https://github.com/nmcquay" 26 | }, 27 | { 28 | "name": "Anton Lopyrev", 29 | "github": "https://github.com/tokudu" 30 | }, 31 | { 32 | "name": "Justin Walsh", 33 | "github": "https://github.com/justinwalsh" 34 | }, 35 | { 36 | "name": "Brad Dwyer", 37 | "github": "https://github.com/yeldarby" 38 | }, 39 | { 40 | "name": "Joel Bradshaw", 41 | "github": "https://github.com/cincodenada" 42 | }, 43 | { 44 | "name": "Alejandro Santiago", 45 | "github": "https://github.com/alemures" 46 | } 47 | ], 48 | "repository": { 49 | "type": "git", 50 | "url": "git://github.com/pascalopitz/nodestalker.git" 51 | }, 52 | "main": "./lib/beanstalk_client", 53 | "dependencies": { 54 | "js-yaml": "^3.13.1" 55 | }, 56 | "scripts": { 57 | "docs": "./node_modules/.bin/docco ./lib/beanstalk_client.js", 58 | "test": "find tests/test_*.js | xargs -n1 node" 59 | }, 60 | "licenses": [ 61 | { 62 | "type": "MIT", 63 | "url": "http://github.com/pascalopitz/nodestalker/raw/master/LICENSE" 64 | } 65 | ], 66 | "engines": { 67 | "node": ">=0.11" 68 | }, 69 | "devDependencies": { 70 | "docco": "^0.8.0" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/helper.js: -------------------------------------------------------------------------------- 1 | var bs = require('../lib/beanstalk_client'); 2 | var net = require('net'); 3 | 4 | var port = process.env.BEANSTALK_PORT || 11333; 5 | 6 | var mock = process.env.BEANSTALKD !== '1'; 7 | var mock_server; 8 | 9 | var connection; 10 | 11 | module.exports = { 12 | bind : function (fn, closeOnEnd) { 13 | 14 | if(!mock) { 15 | return false; 16 | } 17 | 18 | mock_server = net.createServer(function(conn) { 19 | connection = conn; 20 | 21 | connection.on('data', function (data) { 22 | fn.call(mock_server, connection, data); 23 | }); 24 | 25 | if(closeOnEnd === true) { 26 | closeOnEnd = function () { 27 | mock_server.close(); 28 | } 29 | } 30 | 31 | if(closeOnEnd) { 32 | connection.on('end', function () { 33 | closeOnEnd.call(mock_server); 34 | }); 35 | } 36 | }); 37 | 38 | mock_server.listen(port); 39 | }, 40 | getClient : function (isRaw) { 41 | return bs.Client('127.0.0.1:' + port, isRaw || false); 42 | }, 43 | activateDebug : function() { 44 | bs.Debug.activate(); 45 | } 46 | } -------------------------------------------------------------------------------- /tests/test_ignore.js: -------------------------------------------------------------------------------- 1 | console.log('testing ignore'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == "ignore default\r\n") { 8 | conn.write('WATCHING'); 9 | } 10 | }, true); 11 | var client = helper.getClient(); 12 | 13 | 14 | var success = false; 15 | var error = false; 16 | 17 | client.ignore('default').onSuccess(function(data) { 18 | console.log(data); 19 | assert.ok(data); 20 | assert.equal(typeof data, 'object'); 21 | success = true; 22 | client.disconnect(); 23 | }); 24 | 25 | client.addListener('error', function() { 26 | error = true; 27 | }); 28 | 29 | process.addListener('exit', function() { 30 | assert.ok(!error); 31 | assert.ok(success); 32 | console.log('test passed'); 33 | }); 34 | 35 | -------------------------------------------------------------------------------- /tests/test_kick.js: -------------------------------------------------------------------------------- 1 | console.log('testing kick'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == "kick 10\r\n") { 8 | conn.write('KICKED'); 9 | } 10 | }, true); 11 | var client = helper.getClient(); 12 | 13 | var success = false; 14 | var error = false; 15 | 16 | client.kick(10).onSuccess(function(data) { 17 | console.log(data); 18 | assert.ok(data); 19 | assert.equal(typeof data, 'object'); 20 | success = true; 21 | client.disconnect(); 22 | }); 23 | 24 | client.addListener('error', function() { 25 | error = true; 26 | }); 27 | 28 | process.addListener('exit', function() { 29 | assert.ok(!error); 30 | assert.ok(success); 31 | console.log('test passed'); 32 | }); -------------------------------------------------------------------------------- /tests/test_list_tube_used.js: -------------------------------------------------------------------------------- 1 | console.log('testing list_tube_used'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == "list-tube-used\r\n") { 8 | var response = 'USING'; 9 | response += "\r\n"; 10 | response += "tube" 11 | response += "\r\n"; 12 | conn.write(response); 13 | } 14 | }, true); 15 | var client = helper.getClient(); 16 | 17 | var success = false; 18 | var error = false; 19 | 20 | client.list_tube_used().onSuccess(function(data) { 21 | console.log(data); 22 | assert.ok(data); 23 | assert.equal(typeof data, 'object'); 24 | success = true; 25 | client.disconnect(); 26 | }); 27 | 28 | client.addListener('error', function() { 29 | error = true; 30 | }); 31 | 32 | process.addListener('exit', function() { 33 | assert.ok(!error); 34 | assert.ok(success); 35 | console.log('test passed'); 36 | }); -------------------------------------------------------------------------------- /tests/test_list_tubes.js: -------------------------------------------------------------------------------- 1 | console.log('testing list_tubes'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == "list-tubes\r\n") { 8 | var response = 'OK'; 9 | response += "\r\n"; 10 | response += "---\n- default\n - second\n" 11 | response += "\r\n"; 12 | conn.write(response); 13 | } 14 | }, true); 15 | var client = helper.getClient(); 16 | 17 | 18 | var success = false; 19 | var error = false; 20 | 21 | client.list_tubes().onSuccess(function(data) { 22 | console.log(data); 23 | assert.ok(data); 24 | assert.equal(typeof data, 'object'); 25 | success = true; 26 | client.disconnect(); 27 | }); 28 | 29 | client.addListener('error', function() { 30 | error = true; 31 | }); 32 | 33 | process.addListener('exit', function() { 34 | assert.ok(!error); 35 | assert.ok(success); 36 | console.log('test passed'); 37 | }); -------------------------------------------------------------------------------- /tests/test_list_tubes_watched.js: -------------------------------------------------------------------------------- 1 | console.log('testing list_tubes_watched'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == "watch default\r\n") { 8 | conn.write("WATCHING\r\n"); 9 | } 10 | 11 | if(String(data) == "list-tubes-watched\r\n") { 12 | var response = 'OK'; 13 | response += "\r\n"; 14 | response += "---\n- default\n - second\n" 15 | response += "\r\n"; 16 | conn.write(response); 17 | } 18 | }, true); 19 | var client = helper.getClient(); 20 | 21 | 22 | var success = false; 23 | var error = false; 24 | 25 | client.watch('default').onSuccess(function(data) { 26 | console.log('watch', data); 27 | 28 | client.list_tubes_watched().onSuccess(function(data) { 29 | assert.ok(data); 30 | success = true; 31 | client.disconnect(); 32 | }); 33 | }); 34 | 35 | client.addListener('error', function() { 36 | error = true; 37 | }); 38 | 39 | process.addListener('exit', function() { 40 | assert.ok(!error); 41 | assert.ok(success); 42 | console.log('test passed'); 43 | }); 44 | -------------------------------------------------------------------------------- /tests/test_multiline_put.js: -------------------------------------------------------------------------------- 1 | console.log('testing multiline put, peek, delete'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data).indexOf('put') > -1) { 8 | conn.write("INSERTED 10\r\n"); 9 | } 10 | 11 | if(String(data) == 'peek 10\r\n') { 12 | conn.write("FOUND 10 13\r\ntest\r\nhere\r\n\r\n"); 13 | } 14 | 15 | if(String(data) == "delete 10\r\n") { 16 | conn.write("DELETED\r\n"); 17 | this.close(); 18 | } 19 | }); 20 | var client = helper.getClient(); 21 | 22 | var success = false; 23 | var error = false; 24 | 25 | client.put("test\r\nhere\r\n").onSuccess(function(data) { 26 | console.log(data); 27 | var test_id = data[0]; 28 | 29 | client.peek(test_id).onSuccess(function(data) { 30 | console.log(data); 31 | assert.ok(data); 32 | assert.equal(data.id, test_id); 33 | assert.equal(data.data, "test\r\nhere\r\n"); 34 | assert.equal(typeof data, 'object'); 35 | success = true; 36 | 37 | client.deleteJob(test_id).onSuccess(function() { 38 | client.disconnect(); 39 | }); 40 | }); 41 | }); 42 | 43 | client.addListener('error', function() { 44 | error = true; 45 | }); 46 | 47 | process.addListener('exit', function() { 48 | assert.ok(!error); 49 | assert.ok(success); 50 | console.log('test passed'); 51 | }); -------------------------------------------------------------------------------- /tests/test_peek_buried.js: -------------------------------------------------------------------------------- 1 | console.log('testing use, put, watch, reserve, bury, peek_buried'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == 'use burytest\r\n') { 8 | conn.write("USING\r\n"); 9 | } 10 | 11 | if(String(data).indexOf('put') > -1) { 12 | conn.write("INSERTED 9\r\n"); 13 | } 14 | 15 | if(String(data) == 'watch burytest\r\n') { 16 | conn.write("WATCHING\r\n"); 17 | } 18 | 19 | if(String(data) == 'reserve\r\n') { 20 | conn.write("RESERVED 9 8\r\nburytest\r\n"); 21 | } 22 | 23 | if(String(data) == 'bury 9 10\r\n') { 24 | conn.write("BURIED\r\n"); 25 | } 26 | 27 | if(String(data) == 'peek-buried\r\n') { 28 | conn.write("FOUND 9 8\r\nburytest\r\n"); 29 | } 30 | 31 | if(String(data) == "delete 9\r\n") { 32 | conn.write("DELETED\r\n"); 33 | } 34 | }, true); 35 | var client = helper.getClient(); 36 | 37 | 38 | var success = false; 39 | var error = false; 40 | 41 | client.use('burytest').onSuccess(function(data) { 42 | client.put('burytest').onSuccess(function(data) { 43 | var test_id = data[0]; 44 | 45 | client.watch('burytest').onSuccess(function() { 46 | client.reserve().onSuccess(function(data) { 47 | client.bury(test_id).onSuccess(function(data) { 48 | client.peek_buried().onSuccess(function(data) { 49 | assert.ok(data); 50 | assert.equal(data.id, test_id); 51 | assert.equal(data.data, 'burytest'); 52 | assert.equal(typeof data, 'object'); 53 | success = true; 54 | 55 | client.deleteJob(test_id).onSuccess(function() { 56 | client.disconnect(); 57 | }); 58 | }); 59 | }); 60 | }); 61 | }); 62 | }); 63 | }); 64 | 65 | client.addListener('error', function() { 66 | error = true; 67 | }); 68 | 69 | process.addListener('exit', function() { 70 | assert.ok(!error); 71 | assert.ok(success); 72 | console.log('test passed'); 73 | }); -------------------------------------------------------------------------------- /tests/test_peek_delayed.js: -------------------------------------------------------------------------------- 1 | console.log('testing peek_delayed'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == 'peek-delayed\r\n') { 8 | conn.write("NOT_FOUND\r\n"); 9 | } 10 | }, true); 11 | var client = helper.getClient(); 12 | 13 | 14 | var success = false; 15 | var error = false; 16 | 17 | client.peek_delayed().onSuccess(function(data) { 18 | assert.ok(data); 19 | success = true; 20 | client.disconnect(); 21 | }); 22 | 23 | client.addListener('error', function() { 24 | error = true; 25 | }); 26 | 27 | process.addListener('exit', function() { 28 | assert.ok(!error); 29 | assert.ok(success); 30 | console.log('test passed'); 31 | }); 32 | -------------------------------------------------------------------------------- /tests/test_peek_ready.js: -------------------------------------------------------------------------------- 1 | console.log('testing put, peek_ready, delete'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data).indexOf('put') > -1) { 8 | conn.write("INSERTED 10\r\n"); 9 | } 10 | 11 | if(String(data) == 'peek-ready\r\n') { 12 | conn.write("FOUND 10 7\r\ntest\r\n"); 13 | } 14 | 15 | if(String(data) == 'delete 10\r\n') { 16 | conn.write("DELETED\r\n"); 17 | } 18 | }, true); 19 | var client = helper.getClient(); 20 | 21 | 22 | var success = false; 23 | var error = false; 24 | 25 | client.put('test').onSuccess(function(data) { 26 | console.log(data); 27 | var test_id = data[0]; 28 | 29 | client.peek_ready().onSuccess(function(data) { 30 | console.log(data); 31 | assert.ok(data); 32 | assert.equal(data.id, test_id); 33 | assert.equal(data.data, 'test'); 34 | assert.equal(typeof data, 'object'); 35 | success = true; 36 | 37 | client.deleteJob(test_id).onSuccess(function() { 38 | client.disconnect(); 39 | }); 40 | }); 41 | }); 42 | 43 | client.addListener('error', function() { 44 | error = true; 45 | }); 46 | 47 | process.addListener('exit', function() { 48 | assert.ok(!error); 49 | assert.ok(success); 50 | console.log('test passed'); 51 | }); -------------------------------------------------------------------------------- /tests/test_put_buffer.js: -------------------------------------------------------------------------------- 1 | console.log('testing put buffer'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | var util = require('util'); 6 | 7 | var data1 = Buffer.alloc(4, [1,2,3,4]); 8 | var data2 = Buffer.alloc(4, [1,2,3,4]); 9 | 10 | helper.bind(function(conn, data) { 11 | if(String(data).indexOf('put') > -1) { 12 | var dataBuff = extractDataReserveOutput(data); 13 | 14 | assert(data2.equals(dataBuff), util.inspect(dataBuff) + " !== " + util.inspect(data2)); 15 | 16 | conn.write("INSERTED 1\r\n"); 17 | } 18 | 19 | if(String(data) == "use default\r\n") { 20 | conn.write('USING default\r\n'); 21 | this.close(); 22 | } 23 | }, false); 24 | 25 | // Isn't necessary a raw client to use put with buffers 26 | var client = helper.getClient(); 27 | client.use('default').onSuccess(function(data) { 28 | client.put(data1, 100, 0).onSuccess(function(data) { 29 | client.disconnect(); 30 | }); 31 | }); 32 | 33 | // Copied from BeanstalkCommand.prototype._extractDataReserveOutput 34 | function extractDataReserveOutput(buff) { 35 | var i; 36 | var length = buff.length; 37 | 38 | for(i = 0; i < length - 1; i++) { 39 | if(buff[i] === 0x0d && buff[i+1] === 0x0a) { 40 | return buff.slice(i + 2, length - 2); 41 | } 42 | } 43 | return buff; 44 | } -------------------------------------------------------------------------------- /tests/test_put_in_forloop.js: -------------------------------------------------------------------------------- 1 | console.log('testing put in forloop'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | var cnt = 0; 7 | 8 | helper.bind(function(conn, data) { 9 | if(String(data).indexOf('put') > -1) { 10 | cnt += 1; 11 | conn.write("INSERTED "+cnt+"\r\n"); 12 | } 13 | 14 | if(String(data) == "use default\r\n") { 15 | conn.write('USING default\r\n'); 16 | this.close(); 17 | } 18 | }, false); 19 | var client = helper.getClient(); 20 | 21 | client.use('default').onSuccess(function(data) { 22 | var completed = 0; 23 | 24 | for (var i=0;i<5;i++) { 25 | 26 | client.put("foo", 100, 0).onSuccess(function(data) { 27 | completed += 1; 28 | assert.equal(completed, data); 29 | 30 | 31 | if(completed === 5) { 32 | client.disconnect(); 33 | } 34 | }); 35 | } 36 | }); 37 | 38 | -------------------------------------------------------------------------------- /tests/test_put_peek_delete.js: -------------------------------------------------------------------------------- 1 | console.log('testing put, peek, delete'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data).indexOf('put') > -1) { 8 | conn.write("INSERTED 10\r\n"); 9 | } 10 | 11 | if(String(data) == 'peek 10\r\n') { 12 | conn.write("FOUND 10 7\r\ntest\r\n"); 13 | } 14 | 15 | if(String(data) == 'delete 10\r\n') { 16 | conn.write("DELETED\r\n"); 17 | } 18 | }, true); 19 | var client = helper.getClient(); 20 | 21 | 22 | var success = false; 23 | var error = false; 24 | 25 | client.put('test').onSuccess(function(data) { 26 | console.log(data); 27 | var test_id = data[0]; 28 | 29 | client.peek(test_id).onSuccess(function(data) { 30 | console.log(data); 31 | assert.ok(data); 32 | assert.equal(data.id, test_id); 33 | assert.equal(data.data, 'test'); 34 | assert.equal(typeof data, 'object'); 35 | success = true; 36 | 37 | client.deleteJob(test_id).onSuccess(function() { 38 | client.disconnect(); 39 | }); 40 | }); 41 | }); 42 | 43 | client.addListener('error', function() { 44 | error = true; 45 | }); 46 | 47 | process.addListener('exit', function() { 48 | assert.ok(!error); 49 | assert.ok(success); 50 | console.log('test passed'); 51 | }); -------------------------------------------------------------------------------- /tests/test_put_stats_job_delete.js: -------------------------------------------------------------------------------- 1 | console.log('testing put stats_job'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data).indexOf('put') > -1) { 8 | conn.write("INSERTED 3\r\n"); 9 | } 10 | 11 | if(String(data) == 'stats-job 3\r\n') { 12 | response = ""; 13 | response += "OK 141\r\n"; 14 | response += "---\n"; 15 | response += "id: 3\n"; 16 | response += "tube: default\n"; 17 | response += "state: ready\n"; 18 | response += "pri: 10\n"; 19 | response += "age: 0\n"; 20 | response += "delay: 0\n"; 21 | response += "ttr: 100000\n"; 22 | response += "time-left: 0\n"; 23 | response += "reserves: 0\n"; 24 | response += "timeouts: 0\n"; 25 | response += "releases: 0\n"; 26 | response += "buries: 0\n"; 27 | response += "kicks: 0\n"; 28 | response += "\r\n"; 29 | conn.write(response); 30 | } 31 | 32 | if(String(data) == 'delete 3\r\n') { 33 | conn.write("DELETED\r\n"); 34 | } 35 | }, true); 36 | var client = helper.getClient(); 37 | 38 | 39 | var success = false; 40 | var error = false; 41 | 42 | client.put('test').onSuccess(function(job_data) { 43 | var test_id = job_data[0]; 44 | 45 | client.stats_job(test_id).onSuccess(function(data) { 46 | assert.ok(data); 47 | assert.ok(data.id); 48 | assert.equal(test_id, data.id); 49 | success = true; 50 | 51 | client.deleteJob(test_id).onSuccess(function() { 52 | client.disconnect(); 53 | }); 54 | }); 55 | }); 56 | 57 | client.addListener('error', function() { 58 | error = true; 59 | }); 60 | 61 | process.addListener('exit', function() { 62 | assert.ok(!error); 63 | assert.ok(success); 64 | console.log('test passed'); 65 | }); 66 | -------------------------------------------------------------------------------- /tests/test_quit.js: -------------------------------------------------------------------------------- 1 | console.log('testing quit'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == "use default\r\n") { 8 | conn.write('USING default\r\n'); 9 | } 10 | 11 | if(String(data) == "quit\r\n") { 12 | conn.destroy(); 13 | this.close(); 14 | } 15 | }, false); 16 | var client = helper.getClient(); 17 | 18 | 19 | var success = false; 20 | var closed = false; 21 | 22 | client.use('default').onSuccess(function(data) { 23 | assert.ok(data); 24 | client.quit(); 25 | }); 26 | 27 | client.addListener('close', function() { 28 | closed = true; 29 | }); 30 | 31 | process.addListener('exit', function() { 32 | assert.ok(closed); 33 | console.log('test passed'); 34 | }); 35 | 36 | -------------------------------------------------------------------------------- /tests/test_reserve.js: -------------------------------------------------------------------------------- 1 | console.log('testing watch, reserve, use, put'); 2 | 3 | var port = 11333; 4 | 5 | var disconnected = 0; 6 | 7 | var assert = require('assert'); 8 | var helper = require('./helper'); 9 | 10 | helper.bind(function(conn, data) { 11 | if(String(data) == 'use reservetest\r\n') { 12 | conn.write("USING\r\n"); 13 | } 14 | 15 | if(String(data).indexOf('put') > -1) { 16 | conn.write("INSERTED 9\r\n"); 17 | } 18 | 19 | if(String(data) == 'watch reservetest\r\n') { 20 | conn.write("WATCHING\r\n"); 21 | } 22 | 23 | if(String(data) == 'reserve\r\n') { 24 | conn.write("RESERVED 9 4\r\ntest\r\n"); 25 | } 26 | 27 | if(String(data) == "delete 9\r\n") { 28 | conn.write("DELETED\r\n"); 29 | } 30 | }, function() { 31 | disconnected = disconnected + 1; 32 | 33 | if(disconnected == 2) { 34 | this.close(); 35 | } 36 | }); 37 | 38 | var client = helper.getClient(); 39 | var client2 = helper.getClient(); 40 | 41 | var success = false; 42 | var error = false; 43 | var success2 = false; 44 | var error2 = false; 45 | 46 | var id; 47 | var tube = 'reservetest'; 48 | 49 | client.watch(tube).onSuccess(function(data) { 50 | client.reserve().onSuccess(function(data) { 51 | console.log(data); 52 | assert.ok(data.id); 53 | assert.equal(data.data, 'test'); 54 | success = true; 55 | 56 | client.deleteJob(data.id).onSuccess(function(data) { 57 | client.disconnect(); 58 | }); 59 | }); 60 | }); 61 | 62 | setTimeout(function() { 63 | client2.use(tube).onSuccess(function(data) { 64 | client2.put('test').onSuccess(function(data) { 65 | console.log(data); 66 | assert.ok(data); 67 | success2 = true; 68 | client2.disconnect(); 69 | }); 70 | }); 71 | }, 1000); 72 | 73 | client.addListener('error', function() { 74 | error = true; 75 | }); 76 | 77 | client2.addListener('error', function() { 78 | error2 = true; 79 | }); 80 | 81 | process.addListener('exit', function() { 82 | assert.ok(!error); 83 | assert.ok(success); 84 | assert.ok(!error2); 85 | assert.ok(success2); 86 | console.log('test passed'); 87 | }); 88 | -------------------------------------------------------------------------------- /tests/test_reserve_buffer.js: -------------------------------------------------------------------------------- 1 | console.log('testing reserve buffer'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | var util = require('util'); 6 | 7 | var commandBegin = "RESERVED 1 4\r\n"; 8 | var data1 = Buffer.alloc(4, [1,2,3,4]); 9 | var data2 = Buffer.alloc(4, data1); 10 | var commandEnd = "\r\n"; 11 | 12 | var command = Buffer.alloc(commandBegin.length + data1.length + commandEnd.length); 13 | command.write(commandBegin, 0, commandBegin.length, 'binary'); 14 | data1.copy(command, commandBegin.length, 0, data1.length); 15 | command.write(commandEnd, commandBegin.length + data1.length, commandEnd.length, 'binary'); 16 | 17 | helper.bind(function(conn, data) { 18 | if(String(data) == 'reserve\r\n') { 19 | conn.write(command); 20 | } 21 | }, true); 22 | 23 | var client = helper.getClient(true); 24 | client.reserve().onSuccess(function(data) { 25 | var dataBuff = data.data; 26 | 27 | assert(dataBuff instanceof Buffer, "the job data is not a buffer"); 28 | assert(data2.equals(dataBuff), util.inspect(dataBuff) + " !== " + util.inspect(data2)); 29 | 30 | console.log('test passed'); 31 | client.disconnect(); 32 | }); -------------------------------------------------------------------------------- /tests/test_reserve_jobs_multichunk.js: -------------------------------------------------------------------------------- 1 | console.log('testing reserve with chunked response'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == 'reserve\r\n') { 8 | conn.write("RESERVED 9 10\r\ntest\r\n"); 9 | } 10 | 11 | setTimeout(function () { 12 | conn.write("test\r\n"); 13 | }, 100) 14 | }, true); 15 | var client = helper.getClient(); 16 | 17 | var success = false; 18 | var error = false; 19 | 20 | client.reserve().onSuccess(function(data) { 21 | assert.ok(data); 22 | success = true; 23 | client.disconnect(); 24 | }); 25 | 26 | client.addListener('error', function() { 27 | error = true; 28 | }); 29 | 30 | process.addListener('exit', function() { 31 | assert.ok(!error); 32 | assert.ok(success); 33 | console.log('test passed'); 34 | }); 35 | -------------------------------------------------------------------------------- /tests/test_reserve_jobs_multichunk_timeout.js: -------------------------------------------------------------------------------- 1 | console.log('testing reserve with chunked response that times out'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == 'reserve\r\n') { 8 | conn.write("RESERVED 9 10\r\ntest\r\n"); 9 | } 10 | 11 | }, true); 12 | var client = helper.getClient(); 13 | 14 | var success = false; 15 | var error = false; 16 | 17 | client.reserve().onError(function(data) { 18 | success = true; 19 | client.disconnect(); 20 | }); 21 | 22 | 23 | process.addListener('exit', function() { 24 | assert.ok(success); 25 | console.log('test passed'); 26 | }); 27 | -------------------------------------------------------------------------------- /tests/test_reserve_with_timeout.js: -------------------------------------------------------------------------------- 1 | console.log('testing reserve_with_timeout'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == 'reserve-with-timeout 2\r\n') { 8 | conn.write("RESERVED 9 4\r\ntest\r\n"); 9 | } 10 | }, true); 11 | var client = helper.getClient(); 12 | 13 | 14 | var success = false; 15 | var error = false; 16 | 17 | client.reserve_with_timeout(2).onSuccess(function(data) { 18 | assert.ok(data); 19 | success = true; 20 | client.disconnect(); 21 | }); 22 | 23 | client.addListener('error', function() { 24 | error = true; 25 | }); 26 | 27 | process.addListener('exit', function() { 28 | assert.ok(!error); 29 | assert.ok(success); 30 | console.log('test passed'); 31 | }); 32 | -------------------------------------------------------------------------------- /tests/test_stats.js: -------------------------------------------------------------------------------- 1 | console.log('testing stats'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == 'stats\r\n') { 8 | var response = ""; 9 | response += "OK 813\r\n"; 10 | response += "---\n"; 11 | response += "current-jobs-urgent: 0\n"; 12 | response += "current-jobs-ready: 0\n"; 13 | response += "current-jobs-reserved: 0\n"; 14 | response += "current-jobs-delayed: 0\n"; 15 | response += "current-jobs-buried: 0\n"; 16 | response += "cmd-put: 10\n"; 17 | response += "cmd-peek: 2\n"; 18 | response += "cmd-peek-ready: 0\n"; 19 | response += "cmd-peek-delayed: 0\n"; 20 | response += "cmd-peek-buried: 1\n"; 21 | response += "cmd-reserve: 2\n"; 22 | response += "cmd-reserve-with-timeout: 0\n"; 23 | response += "cmd-delete: 10\n"; 24 | response += "cmd-release: 0\n"; 25 | response += "cmd-use: 2\n"; 26 | response += "cmd-watch: 2\n"; 27 | response += "cmd-ignore: 0\n"; 28 | response += "cmd-bury: 1\n"; 29 | response += "cmd-kick: 0\n"; 30 | response += "cmd-touch: 0\n"; 31 | response += "cmd-stats: 1\n"; 32 | response += "cmd-stats-job: 6\n"; 33 | response += "cmd-stats-tube: 0\n"; 34 | response += "cmd-list-tubes: 15\n"; 35 | response += "cmd-list-tube-used: 0\n"; 36 | response += "cmd-list-tubes-watched: 0\n"; 37 | response += "cmd-pause-tube: 0\n"; 38 | response += "job-timeouts: 0\n"; 39 | response += "total-jobs: 10\n"; 40 | response += "max-job-size: 65535\n"; 41 | response += "current-tubes: 1\n"; 42 | response += "current-connections: 1\n"; 43 | response += "current-producers: 0\n"; 44 | response += "current-workers: 0\n"; 45 | response += "current-waiting: 0\n"; 46 | response += "total-connections: 27\n"; 47 | response += "pid: 2759\n"; 48 | response += "version: 1.4.6\n"; 49 | response += "rusage-utime: 0.000000\n"; 50 | response += "rusage-stime: 0.028001\n"; 51 | response += "uptime: 19109\n"; 52 | response += "binlog-oldest-index: 0\n"; 53 | response += "binlog-current-index: 0\n"; 54 | response += "binlog-max-size: 10485760\n"; 55 | response += "\r\n"; 56 | conn.write(response); 57 | } 58 | }, true); 59 | var client = helper.getClient(); 60 | 61 | 62 | var success = false; 63 | var error = false; 64 | 65 | client.stats().onSuccess(function(data) { 66 | console.log(data); 67 | assert.ok(data); 68 | assert.ok(data.pid); 69 | assert.equal(typeof data, 'object'); 70 | success = true; 71 | client.disconnect(); 72 | }); 73 | 74 | client.addListener('error', function() { 75 | error = true; 76 | }); 77 | 78 | process.addListener('exit', function() { 79 | assert.ok(!error); 80 | assert.ok(success); 81 | console.log('test passed'); 82 | }); 83 | -------------------------------------------------------------------------------- /tests/test_stats_job.js: -------------------------------------------------------------------------------- 1 | console.log('testing stats_job not existing'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == "stats-job 111111111\r\n") { 8 | conn.write('NOT_FOUND\r\n'); 9 | } 10 | }, true); 11 | var client = helper.getClient(); 12 | 13 | 14 | var success = false; 15 | var error = false; 16 | 17 | client.stats_job(111111111).onSuccess(function(data) { 18 | assert.ok(data); 19 | assert.ok(data.length); 20 | assert.equal(data[0], 'NOT_FOUND'); 21 | success = true; 22 | client.disconnect(); 23 | }); 24 | 25 | client.addListener('error', function() { 26 | error = true; 27 | }); 28 | 29 | process.addListener('exit', function() { 30 | assert.ok(!error); 31 | assert.ok(success); 32 | console.log('test passed'); 33 | }); 34 | -------------------------------------------------------------------------------- /tests/test_stats_tube.js: -------------------------------------------------------------------------------- 1 | console.log('testing stats_tube'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == 'stats-tube default\r\n') { 8 | var response = ""; 9 | response += "OK 251\r\n"; 10 | response += "---\n"; 11 | response += "name: default\n"; 12 | response += "current-jobs-urgent: 0\n"; 13 | response += "current-jobs-ready: 0\n"; 14 | response += "current-jobs-reserved: 0\n"; 15 | response += "current-jobs-delayed: 0\n"; 16 | response += "current-jobs-buried: 0\n"; 17 | response += "total-jobs: 8\n"; 18 | response += "current-using: 1\n"; 19 | response += "current-watching: 1\n"; 20 | response += "current-waiting: 0\n"; 21 | response += "cmd-pause-tube: 0\n"; 22 | response += "pause: 0\n"; 23 | response += "pause-time-left: 0\n"; 24 | response += "\r\n"; 25 | conn.write(response); 26 | } 27 | }, true); 28 | var client = helper.getClient(); 29 | 30 | 31 | var success = false; 32 | var error = false; 33 | 34 | client.stats_tube('default').onSuccess(function(data) { 35 | console.log(data); 36 | assert.ok(data); 37 | assert.ok(data.name); 38 | assert.equal(typeof data, 'object'); 39 | success = true; 40 | client.disconnect(); 41 | }); 42 | 43 | client.addListener('error', function() { 44 | error = true; 45 | }); 46 | 47 | process.addListener('exit', function() { 48 | assert.ok(!error); 49 | assert.ok(success); 50 | console.log('test passed'); 51 | }); 52 | -------------------------------------------------------------------------------- /tests/test_stats_tube_notfound.js: -------------------------------------------------------------------------------- 1 | console.log('testing stats_tube'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == 'stats-tube foo\r\n') { 8 | var response = ""; 9 | response += "NOT_FOUND\r\n"; 10 | conn.write(response); 11 | } 12 | }, true); 13 | var client = helper.getClient(); 14 | 15 | 16 | var success = false; 17 | var error = false; 18 | 19 | client.stats_tube('foo').onSuccess(function(data) { 20 | console.log(data); 21 | assert.ok(data); 22 | success = true; 23 | client.disconnect(); 24 | }); 25 | 26 | client.addListener('error', function() { 27 | error = true; 28 | }); 29 | 30 | process.addListener('exit', function() { 31 | assert.ok(!error); 32 | assert.ok(success); 33 | console.log('test passed'); 34 | }); 35 | -------------------------------------------------------------------------------- /tests/test_use.js: -------------------------------------------------------------------------------- 1 | console.log('testing use'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == "use default\r\n") { 8 | conn.write('USING default\r\n'); 9 | this.close(); 10 | } 11 | }, false); 12 | var client = helper.getClient(); 13 | 14 | 15 | var success = false; 16 | var error = false; 17 | 18 | client.use('default').onSuccess(function(data) { 19 | assert.ok(data); 20 | success = true; 21 | client.disconnect(); 22 | }); 23 | 24 | client.addListener('error', function() { 25 | error = true; 26 | }); 27 | 28 | process.addListener('exit', function() { 29 | assert.ok(!error); 30 | assert.ok(success); 31 | console.log('test passed'); 32 | }); 33 | 34 | -------------------------------------------------------------------------------- /tests/test_utf8.js: -------------------------------------------------------------------------------- 1 | console.log('testing utf8'); 2 | 3 | var cnt = 0; 4 | 5 | var assert = require('assert'); 6 | var helper = require('./helper'); 7 | 8 | helper.bind(function(conn, data) { 9 | if(String(data).indexOf('put') > -1) { 10 | var input = data.toString().split('\r\n'); 11 | 12 | assert.equal(input[1], "ééééé"); 13 | assert.equal(Buffer.byteLength(input[1], 'utf8'), Buffer.byteLength("ééééé", 'utf8')); 14 | 15 | cnt += 1; 16 | conn.write("INSERTED "+cnt+"\r\n"); 17 | } 18 | 19 | if(String(data) == "use default\r\n") { 20 | conn.write('USING default\r\n'); 21 | this.close(); 22 | } 23 | }, false); 24 | var client = helper.getClient(); 25 | 26 | client.use('default').onSuccess(function(data) { 27 | client.put("ééééé", 100, 0).onSuccess(function(data) { 28 | assert.ok(!isNaN(data[0])); 29 | client.disconnect(); 30 | }); 31 | }); 32 | 33 | -------------------------------------------------------------------------------- /tests/test_utf8_reserve.js: -------------------------------------------------------------------------------- 1 | console.log('testing reserving jobs with utf8 data'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | // Contains a 2-byte (ı) and 3-byte (n̈) UTF character 7 | // for a total of 13 bytes in 10 characters 8 | var utfstr = "Spın̈al Tap"; 9 | 10 | helper.bind(function(conn, data) { 11 | if(String(data) == "reserve\r\n") { 12 | conn.write( 13 | "RESERVED 1234 " + Buffer.byteLength(utfstr, 'utf8') + "\r\n" + 14 | utfstr + "\r\n" 15 | ); 16 | } 17 | }, true); 18 | var client = helper.getClient(); 19 | 20 | var success = false; 21 | var error = false; 22 | 23 | client.reserve().onSuccess(function(job) { 24 | assert.equal(job.data,utfstr) 25 | success = true; 26 | client.disconnect(); 27 | }).onError(function(job) { 28 | success = false; 29 | client.disconnect(); 30 | }); 31 | 32 | client.addListener('error', function() { 33 | error = true; 34 | }); 35 | 36 | process.addListener('exit', function() { 37 | assert.ok(!error); 38 | assert.ok(success); 39 | console.log('test passed'); 40 | }); 41 | 42 | -------------------------------------------------------------------------------- /tests/test_watch.js: -------------------------------------------------------------------------------- 1 | console.log('testing watch'); 2 | 3 | var assert = require('assert'); 4 | var helper = require('./helper'); 5 | 6 | helper.bind(function(conn, data) { 7 | if(String(data) == "watch default\r\n") { 8 | conn.write('WATCHING 1\r\n'); 9 | this.close(); 10 | } 11 | }); 12 | var client = helper.getClient(); 13 | 14 | var success = false; 15 | var error = false; 16 | 17 | client.watch('default').onSuccess(function(data) { 18 | assert.ok(data); 19 | success = true; 20 | client.disconnect(); 21 | }); 22 | 23 | client.addListener('error', function() { 24 | error = true; 25 | }); 26 | 27 | process.addListener('exit', function() { 28 | assert.ok(!error); 29 | assert.ok(success); 30 | console.log('test passed'); 31 | }); 32 | --------------------------------------------------------------------------------