<commit_before>/**
 * Testing dependencies
 */

var should = require('should')
  , mqtt = require('..')
  , spawn = require('child_process').spawn;

/**
 * Modules to be tested
 */

var MqttClient = require('../lib/client');

/**
 * Testing options
 */

var port = 9876;

describe('MqttClient', function () {
  before(function () {
    this.server = mqtt.createServer();
    this.server.listen(port);
  });

  describe('connecting', function() {
    it('should connect to the broker', function (done) {
      var client = new MqttClient(port);

      this.server.once('client', function(client) {
        done();
      });

    });

    it('should send a default client id', function (done) {
      var client = new MqttClient(port);

      this.server.once('client', function (client) {
        client.once('connect', function(packet) {
          packet.clientId.should.match(/mqttjs.*/);
          done();
        });
      });

    });

    it('should connect with the given client id', function (done) {
      var client =
        new MqttClient(port, 'localhost', {clientId: 'testclient'});

      this.server.once('client', function (client) {
        client.once('connect', function(packet) {
          packet.clientId.should.match(/testclient/);
          done();
        });
      });
    });

    it('should default to localhost', function (done) {
      var client = new MqttClient(port, {clientId: 'testclient'});

      this.server.once('client', function (client) {
        client.once('connect', function(packet) {
          packet.clientId.should.match(/testclient/);
          done();
        });
      });
    });

    it('should emit connect', function (done) {
      var client = new MqttClient(port);
      client.once('connect', done);
      client.once('error', done);

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
      });
    });

    it('should emit error', function (done) {
      var client = new MqttClient(port);
      client.once('connect', function () {
        done(new Error('Should not emit connect'));
      });
      client.once('error', function(error) {
        done();
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 2});
        });
      });

    });
  });

  describe('publishing', function() {
    it('should publish a message', function (done) {
      var client = new MqttClient(port)
        , payload = 'test'
        , topic = 'test';

      client.once('connect', function() {
        client.publish(topic, payload);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });

        client.once('publish', function (packet) {
          packet.topic.should.equal(topic);
          packet.payload.should.equal(payload);
          packet.qos.should.equal(0);
          packet.retain.should.equal(false);
          done();
        });
      });
    });

    it('should accept options', function (done) {
      var client = new MqttClient(port)
        , payload = 'test'
        , topic = 'test';

      var opts = {
        retain: true,
        qos: 1
      }

      client.once('connect', function() {
        client.publish(topic, payload, opts);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });

        client.once('publish', function (packet) {
          packet.topic.should.equal(topic);
          packet.payload.should.equal(payload);
          packet.qos.should.equal(opts.qos, 'incorrect qos');
          packet.retain.should.equal(opts.retain, 'incorrect ret');
          done();
        });
      });
    });

    it('should fire a callback (qos 0)', function (done) {
      var client = new MqttClient(port);

      client.once('connect', function() {
        client.publish('a', 'b', done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
      });

    });

    it('should fire a callback (qos 1)', function (done) {
      var client = new MqttClient(port);

      var opts = {qos: 1};

      client.once('connect', function() {
        client.publish('a', 'b', done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
        client.once('publish', client.puback.bind(client));
      });
    });

    it('should fire a callback (qos 2)', function (done) {
      var client = new MqttClient(port);

      var opts = {qos: 2};

      client.once('connect', function() {
        client.publish('a', 'b', opts, done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
        client.once('publish', client.pubrec.bind(client));
        client.once('pubrel', client.pubcomp.bind(client));
      });
    });
  });

  describe('pinging', function () {
    it('should ping every half keep alive time', function (done) {
      var keepalive = 1000;
      this.timeout(keepalive / 2);

      var client = new MqttClient(port, {keepalive: keepalive/2});

      this.server.once('client', function(client) {
        client.once('pingreq', function(packet) {
          client.pingresp();
          done();
        });
      });
    });
  });

  describe('subscribing', function () {
    it('should send a subscribe message', function(done) {
      var client = new MqttClient(port);

      var topic = 'test';

      client.subscribe(topic);

      this.server.once('client', function(client) {
        client.once('subscribe', function(packet) {
          packet.subscriptions.should.includeEql({
            topic: topic,
            qos: 0
          });
          done();
        });
      });
    });

    it('should accept an array of subscriptions', function(done) {
      var client = new MqttClient(port);

      var subs = ['test1', 'test2'];

      client.subscribe(subs);

      this.server.once('client', function(client) {
        client.once('subscribe', function(packet) {
          // i.e. [{topic: 'a', qos: 0}, {topic: 'b', qos: 0}]
          var expected = subs.map(function (i) {
            return {topic: i, qos: 0};
          });

          packet.subscriptions.should.eql(expected);
          done();
        });
      });
    });

    it('should accept an options parameter', function(done) {
      var client = new MqttClient(port);

      var topic = 'test'
        , opts = {qos: 1};

      client.subscribe(topic, opts);

      this.server.once('client', function(client) {
        client.once('subscribe', function(packet) {
          var expected = [{topic: topic, qos: 1}]

          packet.subscriptions.should.eql(expected);
          done();
        });
      });
    });

    it('should fire a callback on suback', function(done) {
      var client = new MqttClient(port);

      var topic = 'test';

      client.subscribe(topic, done);

      this.server.once('client', function(client) {
        client.once('subscribe', client.suback.bind(client));
      });
    });
  });

  describe('receiving messages', function() {
    it('should fire the message event ', function(done) {
      var client = new MqttClient(port)
        , test_topic = 'test'
        , test_message = 'message';

      client.subscribe(test_topic);
      client.on('message', function(topic, message) {
        topic.should.equal(test_topic);
        message.should.equal(test_message);
        done();
      });

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            qos: 0,
            retain: false
          });
        });
      });
    });
  });
  describe('qos handling', function() {

    it('should follow qos 0 semantics (trivial)', function(done) {
      var client = new MqttClient(port)
        , test_topic = 'test'
        , test_message = 'message';

      client.subscribe(test_topic, {qos: 0});

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            qos: 0,
            retain: false
          });
          done();
        });
      });
    });

    it('should follow qos 1 semantics', function(done) {
      var client = new MqttClient(port)
        , test_topic = 'test'
        , test_message = 'message'
        , mid = 50;

      client.subscribe(test_topic, {qos: 1});

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            messageId: mid,
            qos: 1
          });
        });

        client.once('puback', function(packet) {
          packet.messageId.should.equal(mid);
          done();
        });
      });
    });

    it('should follow qos 2 semantics', function(done) {
      var client = new MqttClient(port)
        , test_topic = 'test'
        , test_message = 'message'
        , mid = 253;

      client.subscribe(test_topic, {qos: 2});

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            qos: 2,
            messageId: mid
          });
        });

        client.once('pubrec', function (packet) {
          packet.messageId.should.equal(mid);
          client.pubrel({messageId: packet.messageId});
        });
        client.once('pubcomp', function(packet) {
          packet.messageId.should.equal(mid);
          done();
        });
      });
    });
  });

  after(function () {
    this.server.close();
  });
});
<commit_msg>Corrected faulty test<commit_after>/**
 * Testing dependencies
 */

var should = require('should')
  , mqtt = require('..')
  , spawn = require('child_process').spawn;

/**
 * Modules to be tested
 */

var MqttClient = require('../lib/client');

/**
 * Testing options
 */

var port = 9876;

describe('MqttClient', function () {
  before(function () {
    this.server = mqtt.createServer();
    this.server.listen(port);
  });

  describe('connecting', function() {
    it('should connect to the broker', function (done) {
      var client = new MqttClient(port);

      this.server.once('client', function(client) {
        done();
      });

    });

    it('should send a default client id', function (done) {
      var client = new MqttClient(port);

      this.server.once('client', function (client) {
        client.once('connect', function(packet) {
          packet.clientId.should.match(/mqttjs.*/);
          done();
        });
      });

    });

    it('should connect with the given client id', function (done) {
      var client =
        new MqttClient(port, 'localhost', {clientId: 'testclient'});

      this.server.once('client', function (client) {
        client.once('connect', function(packet) {
          packet.clientId.should.match(/testclient/);
          done();
        });
      });
    });

    it('should default to localhost', function (done) {
      var client = new MqttClient(port, {clientId: 'testclient'});

      this.server.once('client', function (client) {
        client.once('connect', function(packet) {
          packet.clientId.should.match(/testclient/);
          done();
        });
      });
    });

    it('should emit connect', function (done) {
      var client = new MqttClient(port);
      client.once('connect', done);
      client.once('error', done);

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
      });
    });

    it('should emit error', function (done) {
      var client = new MqttClient(port);
      client.once('connect', function () {
        done(new Error('Should not emit connect'));
      });
      client.once('error', function(error) {
        done();
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 2});
        });
      });

    });
  });

  describe('publishing', function() {
    it('should publish a message', function (done) {
      var client = new MqttClient(port)
        , payload = 'test'
        , topic = 'test';

      client.once('connect', function() {
        client.publish(topic, payload);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });

        client.once('publish', function (packet) {
          packet.topic.should.equal(topic);
          packet.payload.should.equal(payload);
          packet.qos.should.equal(0);
          packet.retain.should.equal(false);
          done();
        });
      });
    });

    it('should accept options', function (done) {
      var client = new MqttClient(port)
        , payload = 'test'
        , topic = 'test';

      var opts = {
        retain: true,
        qos: 1
      }

      client.once('connect', function() {
        client.publish(topic, payload, opts);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });

        client.once('publish', function (packet) {
          packet.topic.should.equal(topic);
          packet.payload.should.equal(payload);
          packet.qos.should.equal(opts.qos, 'incorrect qos');
          packet.retain.should.equal(opts.retain, 'incorrect ret');
          done();
        });
      });
    });

    it('should fire a callback (qos 0)', function (done) {
      var client = new MqttClient(port);

      client.once('connect', function() {
        client.publish('a', 'b', done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
      });

    });

    it('should fire a callback (qos 1)', function (done) {
      var client = new MqttClient(port);

      var opts = {qos: 1, messageId: 10};

      client.once('connect', function() {
        client.publish('a', 'b', opts, done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
        client.on('publish', function(packet) {
          client.puback({messageId: packet.messageId});
        });
      });
    });

    it('should fire a callback (qos 2)', function (done) {
      var client = new MqttClient(port);

      var opts = {qos: 2};

      client.once('connect', function() {
        client.publish('a', 'b', opts, done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
        client.once('publish', client.pubrec.bind(client));
        client.once('pubrel', client.pubcomp.bind(client));
      });
    });
  });

  describe('pinging', function () {
    it('should ping every half keep alive time', function (done) {
      var keepalive = 1000;
      this.timeout(keepalive / 2);

      var client = new MqttClient(port, {keepalive: keepalive/2});

      this.server.once('client', function(client) {
        client.once('pingreq', function(packet) {
          client.pingresp();
          done();
        });
      });
    });
  });

  describe('subscribing', function () {
    it('should send a subscribe message', function(done) {
      var client = new MqttClient(port);

      var topic = 'test';

      client.subscribe(topic);

      this.server.once('client', function(client) {
        client.once('subscribe', function(packet) {
          packet.subscriptions.should.includeEql({
            topic: topic,
            qos: 0
          });
          done();
        });
      });
    });

    it('should accept an array of subscriptions', function(done) {
      var client = new MqttClient(port);

      var subs = ['test1', 'test2'];

      client.subscribe(subs);

      this.server.once('client', function(client) {
        client.once('subscribe', function(packet) {
          // i.e. [{topic: 'a', qos: 0}, {topic: 'b', qos: 0}]
          var expected = subs.map(function (i) {
            return {topic: i, qos: 0};
          });

          packet.subscriptions.should.eql(expected);
          done();
        });
      });
    });

    it('should accept an options parameter', function(done) {
      var client = new MqttClient(port);

      var topic = 'test'
        , opts = {qos: 1};

      client.subscribe(topic, opts);

      this.server.once('client', function(client) {
        client.once('subscribe', function(packet) {
          var expected = [{topic: topic, qos: 1}]

          packet.subscriptions.should.eql(expected);
          done();
        });
      });
    });

    it('should fire a callback on suback', function(done) {
      var client = new MqttClient(port);

      var topic = 'test';

      client.subscribe(topic, done);

      this.server.once('client', function(client) {
        client.once('subscribe', client.suback.bind(client));
      });
    });
  });

  describe('receiving messages', function() {
    it('should fire the message event ', function(done) {
      var client = new MqttClient(port)
        , test_topic = 'test'
        , test_message = 'message';

      client.subscribe(test_topic);
      client.on('message', function(topic, message) {
        topic.should.equal(test_topic);
        message.should.equal(test_message);
        done();
      });

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            qos: 0,
            retain: false
          });
        });
      });
    });
  });
  describe('qos handling', function() {

    it('should follow qos 0 semantics (trivial)', function(done) {
      var client = new MqttClient(port)
        , test_topic = 'test'
        , test_message = 'message';

      client.subscribe(test_topic, {qos: 0});

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            qos: 0,
            retain: false
          });
          done();
        });
      });
    });

    it('should follow qos 1 semantics', function(done) {
      var client = new MqttClient(port)
        , test_topic = 'test'
        , test_message = 'message'
        , mid = 50;

      client.subscribe(test_topic, {qos: 1});

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            messageId: mid,
            qos: 1
          });
        });

        client.once('puback', function(packet) {
          packet.messageId.should.equal(mid);
          done();
        });
      });
    });

    it('should follow qos 2 semantics', function(done) {
      var client = new MqttClient(port)
        , test_topic = 'test'
        , test_message = 'message'
        , mid = 253;

      client.subscribe(test_topic, {qos: 2});

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            qos: 2,
            messageId: mid
          });
        });

        client.once('pubrec', function (packet) {
          packet.messageId.should.equal(mid);
          client.pubrel({messageId: packet.messageId});
        });
        client.once('pubcomp', function(packet) {
          packet.messageId.should.equal(mid);
          done();
        });
      });
    });
  });

  after(function () {
    this.server.close();
  });
});
<|endoftext|>


<commit_before>/**
 * Testing dependencies
 */

var should = require('should')
  , mqtt = require('..');

/**
 * Modules to be tested
 */
var createClient = require('../lib/mqtt').createClient;

/**
 * Testing options
 */

var port = 9876;

describe('MqttClient', function () {
  before(function () {
    this.server = mqtt.createServer();
    this.server.listen(port);
  });

  describe('errors', function() {
    it('should emit an error if unable to connect',
        function(done) {
      var client = createClient(9767);

      client.once('error', function(error) {
        if (/ECONNREFUSED/.test(error.message)) {
          done()
        } else {
          done(error);
        }
      });
    });
  });

  describe('closing', function() {
    it('should emit close if stream closes', function(done) {
      var client = createClient(port);

      client.stream.end();
      client.on('close', function() {
        done();
      });
    });

    it('should emit close after end called', function(done) {
      var client = createClient(port);

      client.end();
      client.on('close', function() {
        done();
      });
    });
  });

  describe('connecting', function() {
    it('should connect to the broker', function (done) {
      var client = createClient(port);

      this.server.once('client', function(client) {
        done();
      });
    });

    it('should send a default client id', function (done) {
      var client = createClient(port);

      this.server.once('client', function (client) {
        client.once('connect', function(packet) {
          packet.clientId.should.match(/mqttjs.*/);
          done();
        });
      });

    });

    it('should connect with the given client id', function (done) {
      var client = createClient(port, 'localhost',
        {clientId: 'testclient'});

      this.server.once('client', function (client) {
        client.once('connect', function(packet) {
          packet.clientId.should.match(/testclient/);
          done();
        });
      });
    });

    it('should default to localhost', function (done) {
      var client = createClient(port, {clientId: 'testclient'});

      this.server.once('client', function (client) {
        client.once('connect', function(packet) {
          packet.clientId.should.match(/testclient/);
          done();
        });
      });
    });

    it('should emit connect', function (done) {
      var client = createClient(port);
      client.once('connect', done);
      client.once('error', done);

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
      });
    });

    it('should emit error', function (done) {
      var client = createClient(port);
      client.once('connect', function () {
        done(new Error('Should not emit connect'));
      });
      client.once('error', function(error) {
        done();
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 2});
        });
      });
    });

    it('should have different client ids', function() {
      var client1 = createClient(port).options.clientId
        , client2 = createClient(port).options.clientId;

      client1.should.not.equal(client2);
    });
  });

  describe('publishing', function() {
    it('should publish a message', function (done) {
      var client = createClient(port)
        , payload = 'test'
        , topic = 'test';

      client.once('connect', function() {
        client.publish(topic, payload);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });

        client.once('publish', function (packet) {
          packet.topic.should.equal(topic);
          packet.payload.should.equal(payload);
          packet.qos.should.equal(0);
          packet.retain.should.equal(false);
          done();
        });
      });
    });

    it('should accept options', function (done) {
      var client = createClient(port)
        , payload = 'test'
        , topic = 'test';

      var opts = {
        retain: true,
        qos: 1
      }

      client.once('connect', function() {
        client.publish(topic, payload, opts);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });

        client.once('publish', function (packet) {
          packet.topic.should.equal(topic);
          packet.payload.should.equal(payload);
          packet.qos.should.equal(opts.qos, 'incorrect qos');
          packet.retain.should.equal(opts.retain, 'incorrect ret');
          done();
        });
      });
    });

    it('should fire a callback (qos 0)', function (done) {
      var client = createClient(port);

      client.once('connect', function() {
        client.publish('a', 'b', done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
      });

    });

    it('should fire a callback (qos 1)', function (done) {
      var client = createClient(port);

      var opts = {qos: 1};

      client.once('connect', function() {
        client.publish('a', 'b', opts, done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
        client.on('publish', function(packet) {
          client.puback({messageId: packet.messageId});
        });
      });
    });

    it('should fire a callback (qos 2)', function (done) {
      var client = createClient(port);

      var opts = {qos: 2};

      client.once('connect', function() {
        client.publish('a', 'b', opts, done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
        client.once('publish', client.pubrec.bind(client));
        client.once('pubrel', client.pubcomp.bind(client));
      });
    });
  });

  describe('unsubscribing', function() {
    it('should send an unsubscribe packet', function(done) {
      var client = createClient(port);
      var topic = 'topic';

      client.once('connect', function() {
        client.unsubscribe(topic);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });

        client.once('unsubscribe', function(packet) {
          packet.unsubscriptions.should.include(topic);
          done();
        });
      });
    });

    it('should accept an array of unsubs', function(done) {
      var client = createClient(port);

      var topics = ['topic1', 'topic2'];

      client.once('connect', function() {
        client.unsubscribe(topics);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });

        client.once('unsubscribe', function(packet) {
          packet.unsubscriptions.should.eql(topics);
          done();
        });
      });
    });

    it('should fire a callback on unsuback', function(done) {
      var client = createClient(port);

      var topic = 'topic';

      client.once('connect', function() {
        client.unsubscribe(topic, done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
        client.once('unsubscribe', function(packet) {
          client.unsuback(packet);
        });
      });
    });
  });

  describe('pinging', function () {
    it('should ping before <keepalive> sec', function (done) {
      var keepalive = 3;
      this.timeout(keepalive * 1000);

      var client = createClient(port, {keepalive: keepalive});

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
        client.once('pingreq', function(packet) {
          client.pingresp();
          done();
        });
      });
    });
    it('should not set a ping timer keepalive=0', function() {
      var client = createClient(port, {keepalive:0});
      should.not.exist(client.pingTimer);
    });
  });

  describe('subscribing', function () {
    it('should send a subscribe message', function(done) {
      var client = createClient(port);

      var topic = 'test';

      client.subscribe(topic);

      this.server.once('client', function(client) {
        client.once('subscribe', function(packet) {
          packet.subscriptions.should.includeEql({
            topic: topic,
            qos: 0
          });
          done();
        });
      });
    });

    it('should accept an array of subscriptions', function(done) {
      var client = createClient(port);

      var subs = ['test1', 'test2'];

      client.subscribe(subs);

      this.server.once('client', function(client) {
        client.once('subscribe', function(packet) {
          // i.e. [{topic: 'a', qos: 0}, {topic: 'b', qos: 0}]
          var expected = subs.map(function (i) {
            return {topic: i, qos: 0};
          });

          packet.subscriptions.should.eql(expected);
          done();
        });
      });
    });

    it('should accept an options parameter', function(done) {
      var client = createClient(port);

      var topic = 'test'
        , opts = {qos: 1};

      client.subscribe(topic, opts);

      this.server.once('client', function(client) {
        client.once('subscribe', function(packet) {
          var expected = [{topic: topic, qos: 1}]

          packet.subscriptions.should.eql(expected);
          done();
        });
      });
    });

    it('should fire a callback on suback', function(done) {
      var client = createClient(port);

      var topic = 'test';

      client.subscribe(topic, {qos:2}, function (err, granted) {
        if (err) {
          done(err);
        } else {
          should.exist(granted, 'granted not given');
          granted.should.includeEql({topic: 'test', qos: 2});
          done();
        }
      });

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.suback({
            messageId: packet.messageId,
            granted: packet.subscriptions.map(function (e) {
              return e.qos;
            })
          });
        });
      });
    });
  });

  describe('receiving messages', function() {
    it('should fire the message event ', function(done) {
      var client = createClient(port)
        , test_topic = 'test'
        , test_message = 'message';

      client.subscribe(test_topic);
      client.on('message', function(topic, message) {
        topic.should.equal(test_topic);
        message.should.equal(test_message);
        done();
      });

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            qos: 0,
            retain: false
          });
        });
      });
    });
  });
  describe('qos handling', function() {

    it('should follow qos 0 semantics (trivial)', function(done) {
      var client = createClient(port)
        , test_topic = 'test'
        , test_message = 'message';

      client.subscribe(test_topic, {qos: 0});

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            qos: 0,
            retain: false
          });
          done();
        });
      });
    });

    it('should follow qos 1 semantics', function(done) {
      var client = createClient(port)
        , test_topic = 'test'
        , test_message = 'message'
        , mid = 50;

      client.subscribe(test_topic, {qos: 1});

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            messageId: mid,
            qos: 1
          });
        });

        client.once('puback', function(packet) {
          packet.messageId.should.equal(mid);
          done();
        });
      });
    });

    it('should follow qos 2 semantics', function(done) {
      var client = createClient(port)
        , test_topic = 'test'
        , test_message = 'message'
        , mid = 253;

      client.subscribe(test_topic, {qos: 2});

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            qos: 2,
            messageId: mid
          });
        });

        client.once('pubrec', function (packet) {
          packet.messageId.should.equal(mid);
          client.pubrel({messageId: packet.messageId});
        });
        client.once('pubcomp', function(packet) {
          packet.messageId.should.equal(mid);
          done();
        });
      });
    });
  });

  after(function () {
    this.server.close();
  });
});
<commit_msg>Amend test for expanded 'message' event args<commit_after>/**
 * Testing dependencies
 */

var should = require('should')
  , mqtt = require('..');

/**
 * Modules to be tested
 */
var createClient = require('../lib/mqtt').createClient;

/**
 * Testing options
 */

var port = 9876;

describe('MqttClient', function () {
  before(function () {
    this.server = mqtt.createServer();
    this.server.listen(port);
  });

  describe('errors', function() {
    it('should emit an error if unable to connect',
        function(done) {
      var client = createClient(9767);

      client.once('error', function(error) {
        if (/ECONNREFUSED/.test(error.message)) {
          done()
        } else {
          done(error);
        }
      });
    });
  });

  describe('closing', function() {
    it('should emit close if stream closes', function(done) {
      var client = createClient(port);

      client.stream.end();
      client.on('close', function() {
        done();
      });
    });

    it('should emit close after end called', function(done) {
      var client = createClient(port);

      client.end();
      client.on('close', function() {
        done();
      });
    });
  });

  describe('connecting', function() {
    it('should connect to the broker', function (done) {
      var client = createClient(port);

      this.server.once('client', function(client) {
        done();
      });
    });

    it('should send a default client id', function (done) {
      var client = createClient(port);

      this.server.once('client', function (client) {
        client.once('connect', function(packet) {
          packet.clientId.should.match(/mqttjs.*/);
          done();
        });
      });

    });

    it('should connect with the given client id', function (done) {
      var client = createClient(port, 'localhost',
        {clientId: 'testclient'});

      this.server.once('client', function (client) {
        client.once('connect', function(packet) {
          packet.clientId.should.match(/testclient/);
          done();
        });
      });
    });

    it('should default to localhost', function (done) {
      var client = createClient(port, {clientId: 'testclient'});

      this.server.once('client', function (client) {
        client.once('connect', function(packet) {
          packet.clientId.should.match(/testclient/);
          done();
        });
      });
    });

    it('should emit connect', function (done) {
      var client = createClient(port);
      client.once('connect', done);
      client.once('error', done);

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
      });
    });

    it('should emit error', function (done) {
      var client = createClient(port);
      client.once('connect', function () {
        done(new Error('Should not emit connect'));
      });
      client.once('error', function(error) {
        done();
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 2});
        });
      });
    });

    it('should have different client ids', function() {
      var client1 = createClient(port).options.clientId
        , client2 = createClient(port).options.clientId;

      client1.should.not.equal(client2);
    });
  });

  describe('publishing', function() {
    it('should publish a message', function (done) {
      var client = createClient(port)
        , payload = 'test'
        , topic = 'test';

      client.once('connect', function() {
        client.publish(topic, payload);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });

        client.once('publish', function (packet) {
          packet.topic.should.equal(topic);
          packet.payload.should.equal(payload);
          packet.qos.should.equal(0);
          packet.retain.should.equal(false);
          done();
        });
      });
    });

    it('should accept options', function (done) {
      var client = createClient(port)
        , payload = 'test'
        , topic = 'test';

      var opts = {
        retain: true,
        qos: 1
      }

      client.once('connect', function() {
        client.publish(topic, payload, opts);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });

        client.once('publish', function (packet) {
          packet.topic.should.equal(topic);
          packet.payload.should.equal(payload);
          packet.qos.should.equal(opts.qos, 'incorrect qos');
          packet.retain.should.equal(opts.retain, 'incorrect ret');
          done();
        });
      });
    });

    it('should fire a callback (qos 0)', function (done) {
      var client = createClient(port);

      client.once('connect', function() {
        client.publish('a', 'b', done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
      });

    });

    it('should fire a callback (qos 1)', function (done) {
      var client = createClient(port);

      var opts = {qos: 1};

      client.once('connect', function() {
        client.publish('a', 'b', opts, done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
        client.on('publish', function(packet) {
          client.puback({messageId: packet.messageId});
        });
      });
    });

    it('should fire a callback (qos 2)', function (done) {
      var client = createClient(port);

      var opts = {qos: 2};

      client.once('connect', function() {
        client.publish('a', 'b', opts, done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
        client.once('publish', client.pubrec.bind(client));
        client.once('pubrel', client.pubcomp.bind(client));
      });
    });
  });

  describe('unsubscribing', function() {
    it('should send an unsubscribe packet', function(done) {
      var client = createClient(port);
      var topic = 'topic';

      client.once('connect', function() {
        client.unsubscribe(topic);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });

        client.once('unsubscribe', function(packet) {
          packet.unsubscriptions.should.include(topic);
          done();
        });
      });
    });

    it('should accept an array of unsubs', function(done) {
      var client = createClient(port);

      var topics = ['topic1', 'topic2'];

      client.once('connect', function() {
        client.unsubscribe(topics);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });

        client.once('unsubscribe', function(packet) {
          packet.unsubscriptions.should.eql(topics);
          done();
        });
      });
    });

    it('should fire a callback on unsuback', function(done) {
      var client = createClient(port);

      var topic = 'topic';

      client.once('connect', function() {
        client.unsubscribe(topic, done);
      });

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
        client.once('unsubscribe', function(packet) {
          client.unsuback(packet);
        });
      });
    });
  });

  describe('pinging', function () {
    it('should ping before <keepalive> sec', function (done) {
      var keepalive = 3;
      this.timeout(keepalive * 1000);

      var client = createClient(port, {keepalive: keepalive});

      this.server.once('client', function(client) {
        client.once('connect', function(packet) {
          client.connack({returnCode: 0});
        });
        client.once('pingreq', function(packet) {
          client.pingresp();
          done();
        });
      });
    });
    it('should not set a ping timer keepalive=0', function() {
      var client = createClient(port, {keepalive:0});
      should.not.exist(client.pingTimer);
    });
  });

  describe('subscribing', function () {
    it('should send a subscribe message', function(done) {
      var client = createClient(port);

      var topic = 'test';

      client.subscribe(topic);

      this.server.once('client', function(client) {
        client.once('subscribe', function(packet) {
          packet.subscriptions.should.includeEql({
            topic: topic,
            qos: 0
          });
          done();
        });
      });
    });

    it('should accept an array of subscriptions', function(done) {
      var client = createClient(port);

      var subs = ['test1', 'test2'];

      client.subscribe(subs);

      this.server.once('client', function(client) {
        client.once('subscribe', function(packet) {
          // i.e. [{topic: 'a', qos: 0}, {topic: 'b', qos: 0}]
          var expected = subs.map(function (i) {
            return {topic: i, qos: 0};
          });

          packet.subscriptions.should.eql(expected);
          done();
        });
      });
    });

    it('should accept an options parameter', function(done) {
      var client = createClient(port);

      var topic = 'test'
        , opts = {qos: 1};

      client.subscribe(topic, opts);

      this.server.once('client', function(client) {
        client.once('subscribe', function(packet) {
          var expected = [{topic: topic, qos: 1}]

          packet.subscriptions.should.eql(expected);
          done();
        });
      });
    });

    it('should fire a callback on suback', function(done) {
      var client = createClient(port);

      var topic = 'test';

      client.subscribe(topic, {qos:2}, function (err, granted) {
        if (err) {
          done(err);
        } else {
          should.exist(granted, 'granted not given');
          granted.should.includeEql({topic: 'test', qos: 2});
          done();
        }
      });

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.suback({
            messageId: packet.messageId,
            granted: packet.subscriptions.map(function (e) {
              return e.qos;
            })
          });
        });
      });
    });
  });

  describe('receiving messages', function() {
    it('should fire the message event ', function(done) {
      var client = createClient(port)
        , test_topic = 'test'
        , test_message = 'message'
        , test_retain = true
        , test_qos = 1
        , test_mid = 5;

      client.subscribe(test_topic);
      client.on('message',
          function(topic, message, qos, mid, retain) {
        topic.should.equal(test_topic);
        message.should.equal(test_message);
        qos.should.equal(test_qos);
        mid.should.equal(test_mid);
        retain.should.equal(test_retain);
        done();
      });

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            qos: test_qos,
            retain: test_retain,
            messageId: test_mid
          });
        });
      });
    });
  });
  describe('qos handling', function() {

    it('should follow qos 0 semantics (trivial)', function(done) {
      var client = createClient(port)
        , test_topic = 'test'
        , test_message = 'message';

      client.subscribe(test_topic, {qos: 0});

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            qos: 0,
            retain: false
          });
          done();
        });
      });
    });

    it('should follow qos 1 semantics', function(done) {
      var client = createClient(port)
        , test_topic = 'test'
        , test_message = 'message'
        , mid = 50;

      client.subscribe(test_topic, {qos: 1});

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            messageId: mid,
            qos: 1
          });
        });

        client.once('puback', function(packet) {
          packet.messageId.should.equal(mid);
          done();
        });
      });
    });

    it('should follow qos 2 semantics', function(done) {
      var client = createClient(port)
        , test_topic = 'test'
        , test_message = 'message'
        , mid = 253;

      client.subscribe(test_topic, {qos: 2});

      this.server.once('client', function(client) {
        client.once('subscribe', function (packet) {
          client.publish({
            topic: test_topic,
            payload: test_message,
            qos: 2,
            messageId: mid
          });
        });

        client.once('pubrec', function (packet) {
          packet.messageId.should.equal(mid);
          client.pubrel({messageId: packet.messageId});
        });
        client.once('pubcomp', function(packet) {
          packet.messageId.should.equal(mid);
          done();
        });
      });
    });
  });

  after(function () {
    this.server.close();
  });
});
<|endoftext|>


<commit_before>var tape = require('tape')
var pull = require('pull-stream')
var Pushable = require('pull-pushable')
var mux = require('../')

module.exports = function(serializer) {
  var client = {
    hello  : 'async',
    goodbye: 'async',
    stuff  : 'source',
    bstuff : 'source',
    things : 'sink',
    suchstreamwow: 'duplex'
  }

  tape('async handle closed gracefully', function (t) {

    var A = mux(client, null, serializer) ()
    var B = mux(null, client, serializer) ({
      hello: function (a, cb) {
        cb(null, 'hello, '+a)
      }
    })

    var s = A.createStream()
    pull(s, pull.through(console.log), B.createStream(), pull.through(console.log), s)

    A.hello('world', function (err, value) {
      if(err) throw err
      console.log(value)
      t.equal(value, 'hello, world')

      A.close(function (err) {
        if (err) throw err
        A.hello('world', function (err, value) {
          console.log(err)
          t.ok(err)
          t.end()
        })
      })
    })

  })

  tape('source handle closed gracefully', function (t) {

    var A = mux(client, null, serializer) ()
    var B = mux(null, client, serializer) ({
      stuff: function (b) {
        return pull.values([1, 2, 3, 4, 5].map(function (a) {
          return a * b
        }))
      }
    })

    var s = A.createStream()
    pull(s, pull.through(console.log), B.createStream(), pull.through(console.log), s)

    pull(A.stuff(5), pull.collect(function (err, ary) {
      if(err) throw err
      console.log(ary)
      t.deepEqual(ary, [5, 10, 15, 20, 25])

      A.close(function (err) {
        if (err) throw err
        pull(A.stuff(5), pull.collect(function (err, ary) {
          t.ok(err)
          console.log(err)
          t.end()
        }))
      })
    }))

  })

  tape('sink handle closed gracefully', function (t) {

    var A = mux(client, null, serializer) ()
    var B = mux(null, client, serializer) ({
      things: function (someParam) {
        throw "should not be called"
      }
    })

    var s = A.createStream()
    pull(s, pull.through(console.log), B.createStream(), pull.through(console.log), s)
    A.close(function (err) {
      if (err) throw err
      pull(pull.values([1,2,3,4,5]), A.things(5))

      // sinks are hard to test
      // once closed, the sink (A.things) just aborts early
      // the creator of the sink (this block) has no cb after that abort
      // so we'll just make sure 100ms passes without anything exploding

      setTimeout(function () {
        t.end()
      }, 100)
    })
  })

  tape('close twice', function (t) {

    var A = mux(client, null, serializer) ()
    var B = mux(null, client, serializer) ({
      hello: function (a, cb) {
        cb(null, 'hello, '+a)
      }
    })

    var s = A.createStream()
    pull(s, pull.through(console.log), B.createStream(), pull.through(console.log), s)

    A.hello('world', function (err, value) {
      if(err) throw err
      console.log(value)
      t.equal(value, 'hello, world')

      A.close(function (err) {
        if (err) throw err

        A.close(function (err) {
          if (err) throw err
          t.end()
        })
      })
    })
  })

  tape('wait for streams to end before closing', function (t) {

    var pushable = Pushable()
    var closed = false, n = 2, drained = []

    var A = mux(client, null, serializer) ()
    var B = mux(null, client, serializer) ({
      stuff: function () { return pushable }
    })

    var s = A.createStream()
    pull(s, B.createStream(), s)

    pull(
      A.stuff(),
      pull.drain(function (data) {
        drained.push(data)
        t.notOk(closed)
      }, function (err) {
        next()
      })
    )

    B.close(function (closed) {
      closed = true
      next()
    })

    function next () {
      if(--n) return
      t.deepEqual(drained, [1,2,3])
      t.end()
    }

    pushable.push(1)
    setTimeout(function () {
      //this should have already gotten through,
      //but should not have closed yet.
      t.deepEqual(drained, [1])
      pushable.push(2)
      setTimeout(function () {
        t.deepEqual(drained, [1, 2])
        pushable.push(3)
        setTimeout(function () {
          t.deepEqual(drained, [1, 2, 3])
          pushable.end()
        })
      })
    })
  })

  tape('wait for streams to end before closing', function (t) {

    var closed = false, n = 3, drained = []

    var pushable = Pushable(function () {
      next()
    })
    var A = mux(client, null, serializer) ()
    var B = mux(null, client, serializer) ({
      stuff: function () { return pushable }
    })

    var s = A.createStream()
    pull(s, B.createStream(), s)

    pull(
      A.stuff(),
      pull.drain(function (data) {
        drained.push(data)
        t.notOk(closed)
      }, function (err) {
        t.ok(err)
        next()
      })
    )

    function next () {
      if(--n) return
      t.deepEqual(drained, [1])
      t.end()
    }

    pushable.push(1)
    setTimeout(function () {
      //this should have already gotten through,
      //but should not have closed yet.
      t.deepEqual(drained, [1])
      B.close(true, function (closed) {
        closed = true
        next()
      })

      pushable.push(2)
    })
  })

}

if(!module.parent)
  module.exports();
<commit_msg>fix test name<commit_after>var tape = require('tape')
var pull = require('pull-stream')
var Pushable = require('pull-pushable')
var mux = require('../')

module.exports = function(serializer) {
  var client = {
    hello  : 'async',
    goodbye: 'async',
    stuff  : 'source',
    bstuff : 'source',
    things : 'sink',
    suchstreamwow: 'duplex'
  }

  tape('async handle closed gracefully', function (t) {

    var A = mux(client, null, serializer) ()
    var B = mux(null, client, serializer) ({
      hello: function (a, cb) {
        cb(null, 'hello, '+a)
      }
    })

    var s = A.createStream()
    pull(s, pull.through(console.log), B.createStream(), pull.through(console.log), s)

    A.hello('world', function (err, value) {
      if(err) throw err
      console.log(value)
      t.equal(value, 'hello, world')

      A.close(function (err) {
        if (err) throw err
        A.hello('world', function (err, value) {
          console.log(err)
          t.ok(err)
          t.end()
        })
      })
    })

  })

  tape('source handle closed gracefully', function (t) {

    var A = mux(client, null, serializer) ()
    var B = mux(null, client, serializer) ({
      stuff: function (b) {
        return pull.values([1, 2, 3, 4, 5].map(function (a) {
          return a * b
        }))
      }
    })

    var s = A.createStream()
    pull(s, pull.through(console.log), B.createStream(), pull.through(console.log), s)

    pull(A.stuff(5), pull.collect(function (err, ary) {
      if(err) throw err
      console.log(ary)
      t.deepEqual(ary, [5, 10, 15, 20, 25])

      A.close(function (err) {
        if (err) throw err
        pull(A.stuff(5), pull.collect(function (err, ary) {
          t.ok(err)
          console.log(err)
          t.end()
        }))
      })
    }))

  })

  tape('sink handle closed gracefully', function (t) {

    var A = mux(client, null, serializer) ()
    var B = mux(null, client, serializer) ({
      things: function (someParam) {
        throw "should not be called"
      }
    })

    var s = A.createStream()
    pull(s, pull.through(console.log), B.createStream(), pull.through(console.log), s)
    A.close(function (err) {
      if (err) throw err
      pull(pull.values([1,2,3,4,5]), A.things(5))

      // sinks are hard to test
      // once closed, the sink (A.things) just aborts early
      // the creator of the sink (this block) has no cb after that abort
      // so we'll just make sure 100ms passes without anything exploding

      setTimeout(function () {
        t.end()
      }, 100)
    })
  })

  tape('close twice', function (t) {

    var A = mux(client, null, serializer) ()
    var B = mux(null, client, serializer) ({
      hello: function (a, cb) {
        cb(null, 'hello, '+a)
      }
    })

    var s = A.createStream()
    pull(s, pull.through(console.log), B.createStream(), pull.through(console.log), s)

    A.hello('world', function (err, value) {
      if(err) throw err
      console.log(value)
      t.equal(value, 'hello, world')

      A.close(function (err) {
        if (err) throw err

        A.close(function (err) {
          if (err) throw err
          t.end()
        })
      })
    })
  })

  tape('wait for streams to end before closing', function (t) {

    var pushable = Pushable()
    var closed = false, n = 2, drained = []

    var A = mux(client, null, serializer) ()
    var B = mux(null, client, serializer) ({
      stuff: function () { return pushable }
    })

    var s = A.createStream()
    pull(s, B.createStream(), s)

    pull(
      A.stuff(),
      pull.drain(function (data) {
        drained.push(data)
        t.notOk(closed)
      }, function (err) {
        next()
      })
    )

    B.close(function (closed) {
      closed = true
      next()
    })

    function next () {
      if(--n) return
      t.deepEqual(drained, [1,2,3])
      t.end()
    }

    pushable.push(1)
    setTimeout(function () {
      //this should have already gotten through,
      //but should not have closed yet.
      t.deepEqual(drained, [1])
      pushable.push(2)
      setTimeout(function () {
        t.deepEqual(drained, [1, 2])
        pushable.push(3)
        setTimeout(function () {
          t.deepEqual(drained, [1, 2, 3])
          pushable.end()
        })
      })
    })
  })

  tape('destroy streams when close(immediate, cb) is used', function (t) {

    var closed = false, n = 3, drained = []

    var pushable = Pushable(function () {
      next()
    })
    var A = mux(client, null, serializer) ()
    var B = mux(null, client, serializer) ({
      stuff: function () { return pushable }
    })

    var s = A.createStream()
    pull(s, B.createStream(), s)

    pull(
      A.stuff(),
      pull.drain(function (data) {
        drained.push(data)
        t.notOk(closed)
      }, function (err) {
        t.ok(err)
        next()
      })
    )

    function next () {
      if(--n) return
      t.deepEqual(drained, [1])
      t.end()
    }

    pushable.push(1)
    setTimeout(function () {
      //this should have already gotten through,
      //but should not have closed yet.
      t.deepEqual(drained, [1])
      B.close(true, function (closed) {
        closed = true
        next()
      })

      pushable.push(2)
    })
  })

}

if(!module.parent)
  module.exports();
<|endoftext|>


<commit_before>import test from 'ava';
import { getGithubClient } from './_stubs';
import Column from '../lib/column';
import sinon from 'sinon';

// Ensure data stores are not invalidated.
test.before((t) => {
    t.context.clock = sinon.useFakeTimers();
});
test.after((t) => {
    t.context.clock.restore();
});

test('constructor', (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const id = 1;
    const name = 'test';
    const cards = new Map();
    const column = new Column(client, id, name, cards);

    t.is(column.githubClient, client);
    t.is(column.id, id);
    t.is(column.name, name);
    t.is(column.allCards, cards);

    t.true("issues" in column);
    t.true("cards" in column);

    t.true("then" in column.issues);
    t.true("then" in column.cards);
});

test('move', async (t) => {
    const client = getGithubClient();

    const column = new Column(client, 1);

    await column.move('start');

    const opts = client.options.pop();
    t.is(opts.id, 1);
    t.is(opts.position, 'start');
});

test('create', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: {
            id: 1
        }
    });
    const projectId = 2;
    const name = 'test';
    const cards = new Map();

    const column = await Column.create(client, projectId, name, cards);

    t.true(column instanceof Column);
    t.is(column.id, 1);
    t.is(column.name, name);
    t.is(column.allCards, cards);
    t.is(column.githubClient, client);

    const opts = client.options.pop();
    t.is(opts.project_id, projectId);
    t.is(opts.name, name);
});

test('add card localonly that does not exist remotely', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const allCards = new Map();
    allCards.isReady = true;
    allCards.ready = Promise.resolve();
    const column = new Column(client, 1, 'test', allCards);
    const card = {
        id: 1,
        issue: {
            number: 1
        }
    };

    const addedCard = await column.addCard(card, true);

    t.deepEqual(addedCard, card);
    t.is(card.column, column);
    t.is(client.options.length, 1);

    const cards = await column.cards;

    t.true(cards.has(card));

    const issues = await column.issues;

    t.false(card.issue.number in issues);
});

test('add card that is already assigned to the column', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const allCards = new Map();
    allCards.isReady = true;
    allCards.ready = Promise.resolve();
    const column = new Column(client, 1, 'test', allCards);
    const card = {
        id: 1,
        issue: {
            number: 1
        },
        column
    };

    const addedCard = await column.addCard(card, true);

    t.deepEqual(addedCard, card);
    t.is(client.options.length, 0);

    const cards = await column.cards;

    t.false(cards.has(card));
});

test('add card throws when card has no id and local only', (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const column = new Column(client, 1, 'test', new Map());
    const card = {
        issue: {
            number: 1
        }
    };

    return t.throwsAsync(column.addCard(card, true), Error);
});

test('add card remotely', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    client.queueResponse({
        data: {
            id: 2
        }
    });

    const allCards = new Map();
    allCards.ready = Promise.resolve();
    allCards.isReady = true;
    const column = new Column(client, 1, 'test', allCards);
    const card = {
        issue: {
            number: 3,
            id: 4
        }
    };

    const addedCard = await column.addCard(card);

    t.deepEqual(addedCard, card);
    t.is(card.id, 2);
    t.is(card.column, column);
    const opts = client.options.pop();
    t.is(opts.column_id, column.id);
    t.is(opts.content_id, card.issue.id);
    t.is(opts.content_type, 'Issue');

    const issues = await column.issues;

    t.true(card.issue.number in issues);
    t.deepEqual(issues[card.issue.number], {
        id: 2
    });

    const cards = await column.cards;

    t.true(cards.has(card));
});

test('add card that is already in the column', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [
            {
                id: 2,
                content_url: 'https://github.com/mozillach/gh-projects-content-queue/issues/3'
            }
        ],
        headers: {}
    });
    const allCards = new Map();
    allCards.ready = Promise.resolve();
    allCards.isReady = true;
    const column = new Column(client, 1, 'test', allCards);
    const card = {
        issue: {
            number: 3
        }
    };

    const addedCard = await column.addCard(card);

    t.deepEqual(addedCard, card);
    t.is(card.id, 2);
    t.is(card.column, column);
    t.is(client.options.length, 1);

    const cards = await column.cards;

    t.true(cards.has(card));
});

test('remove card locally and keep the card', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const allCards = new Map();
    const column = new Column(client, 1, 'test', allCards);
    const card = {
        id: 2,
        issue: {
            number: 3
        },
        column
    };
    const cards = await column.cards;
    cards.add(card);
    allCards.set(card.id, card);

    await column.removeCard(card, true, true);

    t.not(card.column, column);

    t.false(cards.has(card));
    t.true(allCards.has(card.id));
});

test('remove card remotely and do not keep it', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const allCards = new Map();
    const column = new Column(client, 1, 'test', allCards);
    const card = {
        id: 2,
        issue: {
            number: 3
        },
        column
    };
    const cards = await column.cards;
    cards.add(card);
    allCards.set(card.id, card);

    await column.removeCard(card);

    const opts = client.options.pop();
    t.is(opts.id, card.id);
    t.is(opts.method, 'DELETE');

    t.false(allCards.has(card.id));
    t.false(cards.has(card));
});

test('get card', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const column = new Column(client, 1, 'test', new Map());
    const card = {
        id: 2,
        issue: {
            number: 3
        },
        column
    };
    const cards = await column.cards;
    cards.add(card);

    const foundCard = await column.getCard(card.issue.id);

    t.deepEqual(foundCard, card);
});

test('move card', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const column = new Column(client, 1, 'test', new Map());
    const card = {
        id: 2,
        column
    };

    await column.moveCard(card, 'start');

    const opts = client.options.pop();
    t.is(opts.id, card.id);
    t.is(opts.position, 'start');
});

test('has issue', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [
            {
                id: 2,
                content_url: 'https://github.com/mozillach/gh-projects-content-queue/issues/3'
            }
        ],
        headers: {}
    });
    const column = new Column(client, 1, 'test', new Map());

    t.true(await column.hasIssue(3));
    t.false(await column.hasIssue(2));
});

test('has card', (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const allCards = new Map();
    const column = new Column(client, 1, 'test', allCards);

    allCards.set(2, {
        column
    });
    allCards.set(3, {});

    t.true(column.hasGithubCardId(2));
    t.false(column.hasGithubCardId(3));
});

test('get card by id', (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const allCards = new Map();
    const column = new Column(client, 1, 'test', allCards);

    const card = {
        id: 2,
        column
    };
    allCards.set(2, card);
    allCards.set(3, {
        id: 3
    });

    t.deepEqual(column.getCardById(2), card);
    t.is(column.getCardById(3), null);
});

test('issues', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [
            {
                id: 2,
                content_url: 'https://github.com/mozillach/gh-projects-content-queue/issues/3'
            },
            {
                id: 4,
                content_url: 'https://github.com/mozillach/gh-projects-content-queue/pull-requests/5'
            }
        ],
        headers: {}
    });
    const column = new Column(client, 1, 'test', new Map());

    const issues = await column.issues;

    t.true('3' in issues);
    t.true('5' in issues);
    t.is(issues['3'].id, 2);
    t.is(issues['5'].id, 4);
});

test.todo('cards');
test.todo('waits for cards to be ready');
<commit_msg>tests: fix gh param names<commit_after>import test from 'ava';
import { getGithubClient } from './_stubs';
import Column from '../lib/column';
import sinon from 'sinon';

// Ensure data stores are not invalidated.
test.before((t) => {
    t.context.clock = sinon.useFakeTimers();
});
test.after((t) => {
    t.context.clock.restore();
});

test('constructor', (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const id = 1;
    const name = 'test';
    const cards = new Map();
    const column = new Column(client, id, name, cards);

    t.is(column.githubClient, client);
    t.is(column.id, id);
    t.is(column.name, name);
    t.is(column.allCards, cards);

    t.true("issues" in column);
    t.true("cards" in column);

    t.true("then" in column.issues);
    t.true("then" in column.cards);
});

test('move', async (t) => {
    const client = getGithubClient();

    const column = new Column(client, 1);

    await column.move('start');

    const opts = client.options.pop();
    t.is(opts.column_id, 1);
    t.is(opts.position, 'start');
});

test('create', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: {
            id: 1
        }
    });
    const projectId = 2;
    const name = 'test';
    const cards = new Map();

    const column = await Column.create(client, projectId, name, cards);

    t.true(column instanceof Column);
    t.is(column.id, 1);
    t.is(column.name, name);
    t.is(column.allCards, cards);
    t.is(column.githubClient, client);

    const opts = client.options.pop();
    t.is(opts.project_id, projectId);
    t.is(opts.name, name);
});

test('add card localonly that does not exist remotely', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const allCards = new Map();
    allCards.isReady = true;
    allCards.ready = Promise.resolve();
    const column = new Column(client, 1, 'test', allCards);
    const card = {
        id: 1,
        issue: {
            number: 1
        }
    };

    const addedCard = await column.addCard(card, true);

    t.deepEqual(addedCard, card);
    t.is(card.column, column);
    t.is(client.options.length, 1);

    const cards = await column.cards;

    t.true(cards.has(card));

    const issues = await column.issues;

    t.false(card.issue.number in issues);
});

test('add card that is already assigned to the column', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const allCards = new Map();
    allCards.isReady = true;
    allCards.ready = Promise.resolve();
    const column = new Column(client, 1, 'test', allCards);
    const card = {
        id: 1,
        issue: {
            number: 1
        },
        column
    };

    const addedCard = await column.addCard(card, true);

    t.deepEqual(addedCard, card);
    t.is(client.options.length, 0);

    const cards = await column.cards;

    t.false(cards.has(card));
});

test('add card throws when card has no id and local only', (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const column = new Column(client, 1, 'test', new Map());
    const card = {
        issue: {
            number: 1
        }
    };

    return t.throwsAsync(column.addCard(card, true), Error);
});

test('add card remotely', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    client.queueResponse({
        data: {
            id: 2
        }
    });

    const allCards = new Map();
    allCards.ready = Promise.resolve();
    allCards.isReady = true;
    const column = new Column(client, 1, 'test', allCards);
    const card = {
        issue: {
            number: 3,
            id: 4
        }
    };

    const addedCard = await column.addCard(card);

    t.deepEqual(addedCard, card);
    t.is(card.id, 2);
    t.is(card.column, column);
    const opts = client.options.pop();
    t.is(opts.column_id, column.id);
    t.is(opts.content_id, card.issue.id);
    t.is(opts.content_type, 'Issue');

    const issues = await column.issues;

    t.true(card.issue.number in issues);
    t.deepEqual(issues[card.issue.number], {
        id: 2
    });

    const cards = await column.cards;

    t.true(cards.has(card));
});

test('add card that is already in the column', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [
            {
                id: 2,
                content_url: 'https://github.com/mozillach/gh-projects-content-queue/issues/3'
            }
        ],
        headers: {}
    });
    const allCards = new Map();
    allCards.ready = Promise.resolve();
    allCards.isReady = true;
    const column = new Column(client, 1, 'test', allCards);
    const card = {
        issue: {
            number: 3
        }
    };

    const addedCard = await column.addCard(card);

    t.deepEqual(addedCard, card);
    t.is(card.id, 2);
    t.is(card.column, column);
    t.is(client.options.length, 1);

    const cards = await column.cards;

    t.true(cards.has(card));
});

test('remove card locally and keep the card', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const allCards = new Map();
    const column = new Column(client, 1, 'test', allCards);
    const card = {
        id: 2,
        issue: {
            number: 3
        },
        column
    };
    const cards = await column.cards;
    cards.add(card);
    allCards.set(card.id, card);

    await column.removeCard(card, true, true);

    t.not(card.column, column);

    t.false(cards.has(card));
    t.true(allCards.has(card.id));
});

test('remove card remotely and do not keep it', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const allCards = new Map();
    const column = new Column(client, 1, 'test', allCards);
    const card = {
        id: 2,
        issue: {
            number: 3
        },
        column
    };
    const cards = await column.cards;
    cards.add(card);
    allCards.set(card.id, card);

    await column.removeCard(card);

    const opts = client.options.pop();
    t.is(opts.card_id, card.id);
    t.is(opts.method, 'DELETE');

    t.false(allCards.has(card.id));
    t.false(cards.has(card));
});

test('get card', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const column = new Column(client, 1, 'test', new Map());
    const card = {
        id: 2,
        issue: {
            number: 3
        },
        column
    };
    const cards = await column.cards;
    cards.add(card);

    const foundCard = await column.getCard(card.issue.id);

    t.deepEqual(foundCard, card);
});

test('move card', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const column = new Column(client, 1, 'test', new Map());
    const card = {
        id: 2,
        column
    };

    await column.moveCard(card, 'start');

    const opts = client.options.pop();
    t.is(opts.card_id, card.id);
    t.is(opts.position, 'start');
});

test('has issue', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [
            {
                id: 2,
                content_url: 'https://github.com/mozillach/gh-projects-content-queue/issues/3'
            }
        ],
        headers: {}
    });
    const column = new Column(client, 1, 'test', new Map());

    t.true(await column.hasIssue(3));
    t.false(await column.hasIssue(2));
});

test('has card', (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const allCards = new Map();
    const column = new Column(client, 1, 'test', allCards);

    allCards.set(2, {
        column
    });
    allCards.set(3, {});

    t.true(column.hasGithubCardId(2));
    t.false(column.hasGithubCardId(3));
});

test('get card by id', (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [],
        headers: {}
    });
    const allCards = new Map();
    const column = new Column(client, 1, 'test', allCards);

    const card = {
        id: 2,
        column
    };
    allCards.set(2, card);
    allCards.set(3, {
        id: 3
    });

    t.deepEqual(column.getCardById(2), card);
    t.is(column.getCardById(3), null);
});

test('issues', async (t) => {
    const client = getGithubClient();
    client.queueResponse({
        data: [
            {
                id: 2,
                content_url: 'https://github.com/mozillach/gh-projects-content-queue/issues/3'
            },
            {
                id: 4,
                content_url: 'https://github.com/mozillach/gh-projects-content-queue/pull-requests/5'
            }
        ],
        headers: {}
    });
    const column = new Column(client, 1, 'test', new Map());

    const issues = await column.issues;

    t.true('3' in issues);
    t.true('5' in issues);
    t.is(issues['3'].id, 2);
    t.is(issues['5'].id, 4);
});

test.todo('cards');
test.todo('waits for cards to be ready');
<|endoftext|>