<commit_before>'use strict';

describe('BavariaIpsum', function () {
    beforeEach(function () {
        this.BavariaIpsum = require('../src/bavaria-ipsum');
    });

    describe('constructor', function () {
        describe('no options given', function () {
            beforeEach(function () {
                this.bavariaIpsum = new this.BavariaIpsum();
            });

            it('initializes source to array of words', function () {
                expect(this.bavariaIpsum.source).toBeArrayOfStrings();
            });

            it('initializes startSentence', function () {
                expect(this.bavariaIpsum.startSentence).toBe(
                    'Bavaria ipsum dolor sit amet'
                );
            });

            it('initializes minSentenceWords', function () {
                expect(this.bavariaIpsum.minSentenceWords).toBe(2);
            });

            it('initializes maxSentenceWords', function () {
                expect(this.bavariaIpsum.maxSentenceWords).toBe(20);
            });

            it('initializes showCommaChance', function () {
                expect(this.bavariaIpsum.showCommaChance).toBe(0.1);
            });

            it('initializes minParagraphSentences', function () {
                expect(this.bavariaIpsum.minParagraphSentences).toBe(2);
            });

            it('initializes minParagraphSentences', function () {
                expect(this.bavariaIpsum.maxParagraphSentences).toBe(20);
            });
        });

        describe('options given', function () {
            beforeEach(function () {
                this.bavariaIpsum = new this.BavariaIpsum({
                    startSentence: 'foo',
                    minSentenceWords: 1,
                    maxSentenceWords: 2,
                    showCommaChance: 0.01,
                    minParagraphSentences: 3,
                    maxParagraphSentences: 4
                });
            });

            it('initializes startSentence', function () {
                expect(this.bavariaIpsum.startSentence).toBe(
                    'foo'
                );
            });

            it('initializes minSentenceWords', function () {
                expect(this.bavariaIpsum.minSentenceWords).toBe(1);
            });

            it('initializes maxSentenceWords', function () {
                expect(this.bavariaIpsum.maxSentenceWords).toBe(2);
            });

            it('initializes showCommaChance', function () {
                expect(this.bavariaIpsum.showCommaChance).toBe(0.01);
            });

            it('initializes minParagraphSentences', function () {
                expect(this.bavariaIpsum.minParagraphSentences).toBe(3);
            });

            it('initializes minParagraphSentences', function () {
                expect(this.bavariaIpsum.maxParagraphSentences).toBe(4);
            });
        });
    });

    describe('generateWord method', function () {
        beforeEach(function () {
            this.bavariaIpsum = new this.BavariaIpsum();
        });

        it('returns random word from source array', function () {
            spyOn(this.bavariaIpsum, '_getRandomInt').and.returnValue(10);

            expect(this.bavariaIpsum.generateWord()).toBe(
                this.bavariaIpsum.source[10]
            );

            expect(this.bavariaIpsum._getRandomInt).toHaveBeenCalledWith(
                0,
                this.bavariaIpsum.source.length
            );
        });
    });
});
<commit_msg>Add more specs<commit_after>'use strict';

describe('BavariaIpsum', function () {
    beforeEach(function () {
        this.BavariaIpsum = require('../src/bavaria-ipsum');
    });

    describe('constructor', function () {
        describe('no options given', function () {
            beforeEach(function () {
                this.bavariaIpsum = new this.BavariaIpsum();
            });

            it('initializes source to array of words', function () {
                expect(this.bavariaIpsum.source).toBeArrayOfStrings();
            });

            it('initializes startSentence', function () {
                expect(this.bavariaIpsum.startSentence).toBe(
                    'Bavaria ipsum dolor sit amet'
                );
            });

            it('initializes minSentenceWords', function () {
                expect(this.bavariaIpsum.minSentenceWords).toBe(2);
            });

            it('initializes maxSentenceWords', function () {
                expect(this.bavariaIpsum.maxSentenceWords).toBe(20);
            });

            it('initializes showCommaChance', function () {
                expect(this.bavariaIpsum.showCommaChance).toBe(0.1);
            });

            it('initializes minParagraphSentences', function () {
                expect(this.bavariaIpsum.minParagraphSentences).toBe(2);
            });

            it('initializes minParagraphSentences', function () {
                expect(this.bavariaIpsum.maxParagraphSentences).toBe(20);
            });
        });

        describe('options given', function () {
            beforeEach(function () {
                this.bavariaIpsum = new this.BavariaIpsum({
                    startSentence: 'foo',
                    minSentenceWords: 1,
                    maxSentenceWords: 2,
                    showCommaChance: 0.01,
                    minParagraphSentences: 3,
                    maxParagraphSentences: 4
                });
            });

            it('initializes startSentence', function () {
                expect(this.bavariaIpsum.startSentence).toBe(
                    'foo'
                );
            });

            it('initializes minSentenceWords', function () {
                expect(this.bavariaIpsum.minSentenceWords).toBe(1);
            });

            it('initializes maxSentenceWords', function () {
                expect(this.bavariaIpsum.maxSentenceWords).toBe(2);
            });

            it('initializes showCommaChance', function () {
                expect(this.bavariaIpsum.showCommaChance).toBe(0.01);
            });

            it('initializes minParagraphSentences', function () {
                expect(this.bavariaIpsum.minParagraphSentences).toBe(3);
            });

            it('initializes minParagraphSentences', function () {
                expect(this.bavariaIpsum.maxParagraphSentences).toBe(4);
            });
        });
    });

    describe('instance methods', function () {
        beforeEach(function () {
            this.bavariaIpsum = new this.BavariaIpsum();
        });

        describe('generateWord', function () {
            it('returns random word from source array', function () {
                spyOn(this.bavariaIpsum, '_getRandomInt').and.returnValue(10);

                expect(this.bavariaIpsum.generateWord()).toBe(
                    this.bavariaIpsum.source[10]
                );

                expect(this.bavariaIpsum._getRandomInt).toHaveBeenCalledWith(
                    0,
                    this.bavariaIpsum.source.length
                );
            });
        });

        describe('generateSentence', function () {
            it('generates sentence', function () {
                expect(this.bavariaIpsum.generateSentence()).toBeString();
            });

            it('generates sentence of given length', function () {
                var i = 500;

                while (i-- > 0) {
                    expect(this.bavariaIpsum.generateSentence(1)).toMatch(
                        /^.+[.?!]$/i
                    );

                    expect(this.bavariaIpsum.generateSentence(2)).toMatch(
                        /^.+(\s|,)+.+[.?!]$/i
                    );
                }
            });

            it('starts with capitalized letter', function () {
                var i = 500,
                    firstLetter;

                while (i-- > 0) {
                    firstLetter = this.bavariaIpsum.generateSentence()[0];
                    expect(firstLetter).toEqual(
                        firstLetter.toUpperCase()
                    );
                }
            });

            it('ends with ? . or !', function () {
                var i = 500,
                    sentence,
                lastLetter;

                while (i-- > 0) {
                    sentence = this.bavariaIpsum.generateSentence();
                    lastLetter = sentence[sentence.length - 1];

                    expect(lastLetter).toMatch(
                        /^[?.!]$/
                    );
                }
            });

            it('adds comma', function () {
                this.bavariaIpsum.showCommaChance = 1; // 100%

                var i = 500;

                while (i-- > 0) {
                    expect(this.bavariaIpsum.generateSentence(2)).toMatch(
                        /^.+,\s.+[.?!]$/i
                    );

                    expect(
                        this.bavariaIpsum.generateSentence(2).indexOf(',') > 0
                    ).toBe(true);
                }
            });
        });

        describe('generateParagraph', function () {
            it('returns string', function () {
                expect(this.bavariaIpsum.generateParagraph()).toBeString();
            });

            it('generates given count of sentences', function () {
                var i = 500;

                while (i-- > 0) {
                    expect(this.bavariaIpsum.generateParagraph(1)).toMatch(
                        /^.+[.?!]$/
                    );

                    expect(this.bavariaIpsum.generateParagraph(2)).toMatch(
                        /^.+[.?!]\s.+[.?!]$/
                    );
                }
            });

            it('starts with startingSentence if option given', function () {
                var i = 500;

                while (i-- > 0) {
                    expect(this.bavariaIpsum.generateParagraph({
                        useStartingSentence: true
                    }).indexOf(this.bavariaIpsum.startSentence))
                        .toEqual(0);
                }
            });

            it('throws an error when length is invalid', function () {
                var self = this;

                expect(function () {
                    self.bavariaIpsum.generateParagraph('foo');
                }).toThrowError('Length must be an Integer');

                expect(function () {
                    self.bavariaIpsum.generateParagraph(5.5);
                }).toThrowError('Length must be an Integer');
            });

            it('throws an error when opts is invalid', function () {
                var self = this;

                expect(function () {
                    self.bavariaIpsum.generateParagraph(1, 1);
                }).toThrowError('Opts must be an Object');
            });
        });
    });
});
<|endoftext|>


<commit_before>
/* globals describe, it, before, after */
const jsonpMock = function (url, cb) {
  requestCount += 1;

  cb(false, {
    ping: 'pong'
  });
};

var proxyquire = require('proxyquireify')(require);
const {makeJSONPDriver} = proxyquire('@cycle/jsonp', {'jsonp': jsonpMock, '@noCallThru': true});

import assert from 'assert';
import {run} from '@cycle/core';

import {restart, restartable} from '../../src/restart';

import {Observable} from 'rx';

import $ from 'jquery';

let requestCount = 0;

describe('restarting a cycle app that makes jsonp requests', () => {
  function main ({JSONP}) {
    const responses$ = JSONP.mergeAll();

    const request$ = JSONP.flatMap(res$ => res$, (outer, inner) => {
      console.log('iTSsgfdgapp');
      return outer.request;
    });

    return {
      responses$: responses$.shareReplay(1),
      JSONP: Observable.just('/hello'),
      request$
    };
  }

  it('replays responses', (done) => {
    const drivers = {
      JSONP: restartable(makeJSONPDriver())
    };

    assert.equal(requestCount, 0);

    const {sources, sinks} = run(main, drivers);

    setTimeout(() => {
      let responseText;

      sinks.responses$.take(1).subscribe(text => {
        responseText = text;
        assert.deepEqual(text, {ping: 'pong'});

        assert.equal(
          requestCount, 1,
          `Expected requestCount to be 1 prior to restart, was ${requestCount}.`
        );

        const restartedSinks = restart(main, drivers, {sources, sinks}).sinks;

        restartedSinks.responses$.take(1).subscribe(text => {
          assert.equal(text, responseText);
          assert.equal(
            requestCount, 1,
            `Expected requestCount to be 1 after restart, was ${requestCount}.`
          );

          done();
        });
      });
    }, 50);
  });

  it('allows access to the request', (done) => {
    console.log('begin!');
    const drivers = {
      JSONP: restartable(makeJSONPDriver())
    };

    const {sources, sinks} = run(main, drivers);

    sinks.request$.take(1).subscribe(text => {
      assert.equal('/hello', text);

      restart(main, drivers, {sources, sinks}).sinks.request$.take(1).subscribe(request => {
        assert.equal('/hello', request);

        done();
      });
    });
  });
});
<commit_msg>Remove errant console.logs<commit_after>
/* globals describe, it, before, after */
const jsonpMock = function (url, cb) {
  requestCount += 1;

  cb(false, {
    ping: 'pong'
  });
};

var proxyquire = require('proxyquireify')(require);
const {makeJSONPDriver} = proxyquire('@cycle/jsonp', {'jsonp': jsonpMock, '@noCallThru': true});

import assert from 'assert';
import {run} from '@cycle/core';

import {restart, restartable} from '../../src/restart';

import {Observable} from 'rx';

import $ from 'jquery';

let requestCount = 0;

describe('restarting a cycle app that makes jsonp requests', () => {
  function main ({JSONP}) {
    const responses$ = JSONP.mergeAll();

    const request$ = JSONP.flatMap(res$ => res$, (outer, inner) => {
      return outer.request;
    });

    return {
      responses$: responses$.shareReplay(1),
      JSONP: Observable.just('/hello'),
      request$
    };
  }

  it('replays responses', (done) => {
    const drivers = {
      JSONP: restartable(makeJSONPDriver())
    };

    assert.equal(requestCount, 0);

    const {sources, sinks} = run(main, drivers);

    setTimeout(() => {
      let responseText;

      sinks.responses$.take(1).subscribe(text => {
        responseText = text;
        assert.deepEqual(text, {ping: 'pong'});

        assert.equal(
          requestCount, 1,
          `Expected requestCount to be 1 prior to restart, was ${requestCount}.`
        );

        const restartedSinks = restart(main, drivers, {sources, sinks}).sinks;

        restartedSinks.responses$.take(1).subscribe(text => {
          assert.equal(text, responseText);
          assert.equal(
            requestCount, 1,
            `Expected requestCount to be 1 after restart, was ${requestCount}.`
          );

          done();
        });
      });
    }, 50);
  });

  it('allows access to the request', (done) => {
    const drivers = {
      JSONP: restartable(makeJSONPDriver())
    };

    const {sources, sinks} = run(main, drivers);

    sinks.request$.take(1).subscribe(text => {
      assert.equal('/hello', text);

      restart(main, drivers, {sources, sinks}).sinks.request$.take(1).subscribe(request => {
        assert.equal('/hello', request);

        done();
      });
    });
  });
});
<|endoftext|>


<commit_before>const { noIndent } = require('./common/configs')
const {
  assertNoErrors,
  assertErrorCount,
  assertWarnsCount,
  assertErrorMessage
} = require('./common/asserts')
const linter = require('./../lib/index')

describe('Linter', () => {
  describe('Comment Directives', () => {
    it('should disable fixed compiler error', () => {
      const report = linter.processStr('pragma solidity ^0.4.4; // solhint-disable-line')

      assertNoErrors(report)
    })

    it('should disable fixed compiler error using multiline comment', () => {
      const report = linter.processStr('pragma solidity ^0.4.4; /* solhint-disable-line */')

      assertNoErrors(report)
    })

    it('should disable only one compiler error', () => {
      const report = linter.processStr(
        `
                // solhint-disable-next-line
                pragma solidity ^0.4.4;
                pragma solidity 0.3.4;
            `,
        noIndent()
      )

      assertErrorCount(report, 1)
    })

    it('should disable only one compiler error using multiline comment', () => {
      const report = linter.processStr(
        `
                /* solhint-disable-next-line */
                pragma solidity ^0.4.4;
                pragma solidity 0.3.4;
            `,
        noIndent()
      )

      assertErrorCount(report, 1)
    })

    it('should disable only compiler version error', () => {
      const report = linter.processStr(
        `
                // solhint-disable compiler-gt-0_4
                pragma solidity ^0.4.4;
                pragma solidity 0.3.4; // disabled error: Compiler version must be greater that 0.4
            `,
        noIndent()
      )

      assertWarnsCount(report, 1)
      assertErrorMessage(report, 'Compiler version must be fixed')
    })

    it('should disable only one compiler version error', () => {
      const report = linter.processStr(
        `
                /* solhint-disable compiler-gt-0_4 */
                pragma solidity 0.3.4;
                /* solhint-enable compiler-gt-0_4 */
                pragma solidity 0.3.4;
            `,
        noIndent()
      )

      assertErrorCount(report, 1)
      assertErrorMessage(report, '0.4')
    })

    it('should not disable fixed compiler error', () => {
      const report = linter.processStr(
        `
                /* solhint-disable compiler-gt-0_4 */
                pragma solidity ^0.4.4;
                /* solhint-enable compiler-gt-0_4 */
                pragma solidity ^0.4.4;
            `,
        noIndent()
      )

      assertWarnsCount(report, 2)
      assertErrorMessage(report, 'fixed')
    })

    it('should disable all errors', () => {
      const report = linter.processStr(
        `
                /* solhint-disable */
                pragma solidity ^0.4.4;
                pragma solidity 0.3.4;
            `,
        noIndent()
      )

      assertNoErrors(report)
    })

    it('should disable then enable all errors', () => {
      const report = linter.processStr(
        `
                /* solhint-disable */
                pragma solidity ^0.4.4;
                /* solhint-enable */
                pragma solidity ^0.4.4;
            `,
        noIndent()
      )

      assertWarnsCount(report, 1)
      assertErrorMessage(report, 'fixed')
    })

    it('should not erase error', () => {
      const report = linter.processStr('/* solhint-disable-next-line */')

      assertNoErrors(report)
    })
  })
})
<commit_msg>Fixed some comment directive tests.<commit_after>const { noIndent } = require('./common/configs')
const {
  assertNoErrors,
  assertErrorCount,
  assertWarnsCount,
  assertErrorMessage
} = require('./common/asserts')
const linter = require('./../lib/index')

describe('Linter', () => {
  describe('Comment Directives', () => {
    it('should disable fixed compiler error', () => {
      const report = linter.processStr('pragma solidity ^0.4.4; // solhint-disable-line')

      assertNoErrors(report)
    })

    it('should disable fixed compiler error using multiline comment', () => {
      const report = linter.processStr('pragma solidity ^0.4.4; /* solhint-disable-line */')

      assertNoErrors(report)
    })

    it('should disable only one compiler error', () => {
      const report = linter.processStr(
        `
                // solhint-disable-next-line
                pragma solidity 0.3.4;
                pragma solidity 0.3.4;
            `,
        noIndent()
      )

      assertErrorCount(report, 1)
    })

    it('should disable only one compiler error using multiline comment', () => {
      const report = linter.processStr(
        `
                /* solhint-disable-next-line */
                pragma solidity 0.3.4;
                pragma solidity 0.3.4;
            `,
        noIndent()
      )

      assertErrorCount(report, 1)
    })

    it('should disable only compiler version error', () => {
      const report = linter.processStr(
        `
                // solhint-disable compiler-gt-0_4
                pragma solidity ^0.4.4;
                pragma solidity 0.3.4; // disabled error: Compiler version must be greater that 0.4
            `,
        noIndent()
      )

      assertWarnsCount(report, 1)
      assertErrorMessage(report, 'Compiler version must be fixed')
    })

    it('should disable only one compiler version error', () => {
      const report = linter.processStr(
        `
                /* solhint-disable compiler-gt-0_4 */
                pragma solidity 0.3.4;
                /* solhint-enable compiler-gt-0_4 */
                pragma solidity 0.3.4;
            `,
        noIndent()
      )

      assertErrorCount(report, 1)
      assertErrorMessage(report, '0.4')
    })

    it('should not disable fixed compiler error', () => {
      const report = linter.processStr(
        `
                /* solhint-disable compiler-gt-0_4 */
                pragma solidity ^0.4.4;
                /* solhint-enable compiler-gt-0_4 */
                pragma solidity ^0.4.4;
            `,
        noIndent()
      )

      assertWarnsCount(report, 2)
      assertErrorMessage(report, 'fixed')
    })

    it('should disable all errors', () => {
      const report = linter.processStr(
        `
                /* solhint-disable */
                pragma solidity ^0.4.4;
                pragma solidity 0.3.4;
            `,
        noIndent()
      )

      assertNoErrors(report)
    })

    it('should disable then enable all errors', () => {
      const report = linter.processStr(
        `
                /* solhint-disable */
                pragma solidity ^0.4.4;
                /* solhint-enable */
                pragma solidity ^0.4.4;
            `,
        noIndent()
      )

      assertWarnsCount(report, 1)
      assertErrorMessage(report, 'fixed')
    })

    it('should not erase error', () => {
      const report = linter.processStr('/* solhint-disable-next-line */')

      assertNoErrors(report)
    })
  })
})
<|endoftext|>


<commit_before>
let a = { id_sistema: '7',
  nomeperfilacesso: 'felipe 1629',
  functionalities: [ '1', '4', '12' ] }

//let values = []
let lastIDCreated = 50
let b = a.functionalities.map(function(e){
  let item = []
  new Array().push.call(item,lastIDCreated, parseInt(e))
  return item
})
console.log(b);
// console.log(values);
<commit_msg>Test add bulk query ok<commit_after>
let a = { id_sistema: '7',
  nomeperfilacesso: 'felipe 1629',
  functionalities: [ '1', '4', '12' ] }

//let values = []
let lastIDCreated = 50
let b = a.functionalities.map(function(e){
  let item = []
  new Array().push.call(item,lastIDCreated, parseInt(e))
  return item
})
console.log(b);
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var chai = require('chai');
var expect = chai.expect;
var path = require('path');
var sinon = require('sinon'); chai.use(require('sinon-chai'));
var BluebirdPromise = require('bluebird');

var Migration = require('../../lib/db/migration');
var EntryQuery = require('../../lib/db/query/entry');
var Schema = require('../../lib/db/schema');
var MockAdapter = require('../mocks/adapter');
var migration, schema, adapter, query;

describe('Migration', function() {
  before(function() {
    adapter = MockAdapter.create({});
    query = EntryQuery.create(adapter);
    schema = Schema.create(adapter);
    migration = Migration.create(query, schema,
      path.join(__dirname, '../fixtures/migrations/blog'));
  });

  beforeEach(function() {
    var results = {};
    sinon.spy(schema, 'begin');
    sinon.stub(adapter, '_execute', function(client, sql/*, args*/) {
      var rows, fields;
      if (sql.match(/select/i)) {
        rows = results.select;
        fields = ['id', 'name', 'batch'];
      }
      return {
        rows: rows || [],
        fields: fields || []
      };
    });
    adapter._execute.selectReturnsExecutedMigrations = function(names) {
      results.select = names.map(function(name, index) {
        return { id: index + 1, name: name, batch: 1 };
      });
    };
    adapter._execute.sqlCalls = function() {
      return _.times(adapter._execute.callCount, function(index) {
        return adapter._execute.getCall(index).args.slice(1);
      });
    };
  });

  afterEach(function() {
    schema.begin.restore();
    adapter._execute.restore();
  });

  describe('#_readMigrations', function() {

    it('reads migrations in order', function(done) {
      migration._readMigrations().then(function(migrations) {
        expect(migrations).to.eql([
          { name: '20141022202234_create_articles' },
          { name: '20141022202634_create_comments' }
        ]);
      })
      .done(done, done);
    });

  });

  describe('#_loadMigrations', function() {

    it('loads migrations in order', function(done) {
      migration._loadMigrations().then(function(migrations) {
        expect(migrations).to.eql([
          _.extend({
            name: '20141022202234_create_articles'
          }, require('../fixtures/migrations/blog/' +
            '20141022202234_create_articles')),
          _.extend({
            name: '20141022202634_create_comments'
          }, require('../fixtures/migrations/blog/' +
            '20141022202634_create_comments'))
        ]);
      })
      .done(done, done);
    });

  });

  describe('#_readPendingMigrations', function() {

    it('reads migrations in order', function(done) {
      migration._readPendingMigrations().bind(this)
      .then(function(migrations) {
        expect(migrations).to.eql([
          { name: '20141022202234_create_articles', batch: 1 },
          { name: '20141022202634_create_comments', batch: 1 }
        ]);
      })
      .done(done, done);
    });

    it('does not include executed migrations', function(done) {
      adapter._execute.selectReturnsExecutedMigrations([
        '20141022202234_create_articles'
      ]);

      migration._readPendingMigrations().bind(this)
      .then(function(migrations) {
        expect(migrations).to.eql([
          { name: '20141022202634_create_comments', batch: 2 }
        ]);
      })
      .done(done, done);
    });

  });

  describe('#_loadPendingMigrations', function() {

    it('loads pending migrations', function(done) {
      adapter._execute.selectReturnsExecutedMigrations([
        '20141022202234_create_articles'
      ]);

      migration._loadPendingMigrations().bind(this)
      .then(function(migrations) {
        expect(migrations).to.eql([
          _.extend({
            name: '20141022202634_create_comments',
            batch: 2
          }, require('../fixtures/migrations/blog/' +
            '20141022202634_create_comments')),
        ]);
      })
      .done(done, done);
    });

  });

  describe('#_readExecutedMigrations', function() {

    it('reads migrations in order', function(done) {
      adapter._execute.selectReturnsExecutedMigrations([
        '20141022202634_create_comments',
        '20141022202234_create_articles'
      ]);

      migration._readExecutedMigrations().bind(this)
      .then(function(migrations) {
        expect(migrations).to.eql([
          { name: '20141022202234_create_articles', batch: 1 },
          { name: '20141022202634_create_comments', batch: 1 }
        ]);
      })
      .done(done, done);
    });

  });

  describe('#_loadExecutedMigrations', function() {

    it('loads migrations in order', function(done) {
      adapter._execute.selectReturnsExecutedMigrations([
        '20141022202234_create_articles'
      ]);

      migration._loadExecutedMigrations().bind(this)
      .then(function(migrations) {
        expect(migrations).to.eql([
          _.extend({
            name: '20141022202234_create_articles',
            batch: 1
          }, require('../fixtures/migrations/blog/' +
            '20141022202234_create_articles')),
        ]);
      })
      .done(done, done);
    });

  });

  describe('with pending migrations stubbed', function() {
    beforeEach(function() {
      var mod1 = this.mod1 = {
        up: sinon.spy(), down: sinon.spy(),
        name: 'migration_file_1', batch: 1
      };
      var mod2 = this.mod2 = {
        up: sinon.spy(), down: sinon.spy(),
        name: 'migration_file_2', batch: 1
      };
      sinon.stub(migration, '_loadPendingMigrations')
        .returns(BluebirdPromise.resolve([mod1, mod2]));
    });
    afterEach(function() {
      migration._loadPendingMigrations.restore();
    });

    describe('#migrate', function() {

      it('calls the up methods', function(done) {
        migration.migrate().bind(this).then(function() {
          expect(this.mod1.up).to.have.been.calledOnce;
          expect(this.mod2.up).to.have.been.calledOnce;
        })
        .done(done, done);
      });

      it('calls the up methods with the schema as a transaction', function(done) {
        migration.migrate().bind(this).then(function() {
          var schemaTransaction = schema.begin.returnValues[0];
          expect(this.mod1.up).to.have.been
            .calledWithExactly(schemaTransaction);
          expect(this.mod2.up).to.have.been
            .calledWithExactly(schemaTransaction);
        })
        .done(done, done);
      });

      it('does not call the down methods', function(done) {
        migration.migrate().bind(this).then(function() {
          expect(this.mod1.down).to.not.have.been.called;
          expect(this.mod2.down).to.not.have.been.called;
        })
        .done(done, done);
      });

      it('respects migration promises', function(done) {
        var sequence = 0;
        var up1Sequence;
        var up2Sequence;

        this.mod1.up = function() {
          return BluebirdPromise.delay(5).then(function() {
            up1Sequence = sequence++;
          });
        };
        this.mod2.up = function() {
          return BluebirdPromise.delay(0).then(function() {
            up2Sequence = sequence++;
          });
        };

        migration.migrate().then(function() {
          expect(up1Sequence).to.eql(0);
          expect(up2Sequence).to.eql(1);
        })
        .done(done, done);
      });

      it('records migrations in database', function(done) {
        migration.migrate().bind(this).then(function() {
          expect(adapter._execute.sqlCalls()).to.eql([
            ['BEGIN', []],
            [
              'INSERT INTO "azul_migrations" ("name", "batch") ' +
              'VALUES (?, ?), (?, ?)',
              ['migration_file_1', 1, 'migration_file_2', 1]
            ],
            ['COMMIT', []]
          ]);
        })
        .done(done, done);
      });
    });
  });

  describe('with pending migrations stubbed as empty', function() {
    beforeEach(function() {
      sinon.stub(migration, '_loadPendingMigrations')
        .returns(BluebirdPromise.resolve([]));
    });
    afterEach(function() {
      migration._loadPendingMigrations.restore();
    });

    describe('#migrate', function() {

      it('does not record migrations in database', function(done) {
        migration.migrate().bind(this).then(function() {
          expect(adapter._execute.sqlCalls()).to.eql([
            ['BEGIN', []],
            ['COMMIT', []]
          ]);
        })
        .done(done, done);
      });

    });

  });

  describe('with executed migrations stubbed', function() {
    beforeEach(function() {
      var mod1 = this.mod1 = {
        up: sinon.spy(), down: sinon.spy(),
        name: 'migration_file_1', batch: 1
      };
      var mod2 = this.mod2 = {
        up: sinon.spy(), down: sinon.spy(),
        name: 'migration_file_2', batch: 1
      };
      sinon.stub(migration, '_loadExecutedMigrations')
        .returns(BluebirdPromise.resolve([mod1, mod2]));
    });
    afterEach(function() {
      migration._loadExecutedMigrations.restore();
    });

    describe('#rollback', function() {

      it('calls the down methods', function(done) {
        migration.rollback().bind(this).then(function() {
          expect(this.mod1.down).to.have.been.calledOnce;
          expect(this.mod2.down).to.have.been.calledOnce;
        })
        .done(done, done);
      });

      it('calls the down methods with the schema as a transaction', function(done) {
        migration.rollback().bind(this).then(function() {
          var schemaTransaction = schema.begin.returnValues[0];
          expect(this.mod1.down).to.have.been
            .calledWithExactly(schemaTransaction);
          expect(this.mod2.down).to.have.been
            .calledWithExactly(schemaTransaction);
        })
        .done(done, done);
      });

      it('does not call the up methods', function(done) {
        migration.rollback().bind(this).then(function() {
          expect(this.mod1.up).to.not.have.been.called;
          expect(this.mod2.up).to.not.have.been.called;
        })
        .done(done, done);
      });

      it('respects migration promises', function(done) {
        var sequence = 0;
        var down1Sequence;
        var down2Sequence;

        this.mod1.down = function() {
          return BluebirdPromise.delay(5).then(function() {
            down1Sequence = sequence++;
          });
        };
        this.mod2.down = function() {
          return BluebirdPromise.delay(0).then(function() {
            down2Sequence = sequence++;
          });
        };

        migration.rollback().then(function() {
          expect(down1Sequence).to.eql(0);
          expect(down2Sequence).to.eql(1);
        })
        .done(done, done);
      });

      it('removes migrations recorded in database', function(done) {
        migration.rollback().bind(this).then(function() {
          expect(adapter._execute.sqlCalls()).to.eql([
            ['BEGIN', []],
            ['DELETE FROM "azul_migrations" WHERE "batch" = ?', [1]],
            ['COMMIT', []]
          ]);
        })
        .done(done, done);
      });
    });
  });

  describe('#_determineReverseAction', function() {
    // to make this happen, we'll probably want to pass a fake object off to
    // the migration's `change` method and record any calls that are made on
    // it. from there, the reverse actions can be built.

    // a possibly simpler way to do this would be to create a ReverseSchema
    // class that basically just has a bunch of functions that map to the
    // opposite of what they are. so `createTable` would map to a
    // `DropTableQuery` and (as long as the arguments match), that would be
    // all that was required. imposing a rule that reversible actions have
    // arguments that directly overlap with their reverse action's arguments
    // (drop table needs only the table name, but no more of create table's
    // arguments) may be easy. it'd also be easy to say it's _only_ the first
    // argument of the call through `createTable` that should be passed off to
    // the creation of a `DropTableQuery`. argument mapping may be more
    // complicated, but still could be decently easy.
    it('knows the reverse of creating a table');
  });

  describe('#migrate', function() {
    it('rolls back transaction for failed migration forward');
    it('rolls back transaction for failed migration backward');
  });

  // ADD FEATURE: hash migrations when they are run so we're able to warn the
  // user about migrations that have been altered after they've been applied.
  // store the hash in the migration table & any time migrations are run, check
  // that all previously run migrations still match their current values when
  // read from the disk. this could be extended to ensure that when rolling
  // back we prompt the user that this could potentially break and/or not
  // reverse the migration as intended.
});
<commit_msg>Ensuring rollback is called when migrations fail.<commit_after>'use strict';

var _ = require('lodash');
var chai = require('chai');
var expect = chai.expect;
var path = require('path');
var sinon = require('sinon'); chai.use(require('sinon-chai'));
var BluebirdPromise = require('bluebird');

var Migration = require('../../lib/db/migration');
var EntryQuery = require('../../lib/db/query/entry');
var Schema = require('../../lib/db/schema');
var MockAdapter = require('../mocks/adapter');
var migration, schema, adapter, query;

describe('Migration', function() {
  before(function() {
    adapter = MockAdapter.create({});
    query = EntryQuery.create(adapter);
    schema = Schema.create(adapter);
    migration = Migration.create(query, schema,
      path.join(__dirname, '../fixtures/migrations/blog'));
  });

  beforeEach(function() {
    var results = {};
    sinon.spy(schema, 'begin');
    sinon.stub(adapter, '_execute', function(client, sql/*, args*/) {
      var rows, fields;
      if (sql.match(/select/i)) {
        rows = results.select;
        fields = ['id', 'name', 'batch'];
      }
      return {
        rows: rows || [],
        fields: fields || []
      };
    });
    adapter._execute.selectReturnsExecutedMigrations = function(names) {
      results.select = names.map(function(name, index) {
        return { id: index + 1, name: name, batch: 1 };
      });
    };
    adapter._execute.sqlCalls = function() {
      return _.times(adapter._execute.callCount, function(index) {
        return adapter._execute.getCall(index).args.slice(1);
      });
    };
  });

  afterEach(function() {
    schema.begin.restore();
    adapter._execute.restore();
  });

  describe('#_readMigrations', function() {

    it('reads migrations in order', function(done) {
      migration._readMigrations().then(function(migrations) {
        expect(migrations).to.eql([
          { name: '20141022202234_create_articles' },
          { name: '20141022202634_create_comments' }
        ]);
      })
      .done(done, done);
    });

  });

  describe('#_loadMigrations', function() {

    it('loads migrations in order', function(done) {
      migration._loadMigrations().then(function(migrations) {
        expect(migrations).to.eql([
          _.extend({
            name: '20141022202234_create_articles'
          }, require('../fixtures/migrations/blog/' +
            '20141022202234_create_articles')),
          _.extend({
            name: '20141022202634_create_comments'
          }, require('../fixtures/migrations/blog/' +
            '20141022202634_create_comments'))
        ]);
      })
      .done(done, done);
    });

  });

  describe('#_readPendingMigrations', function() {

    it('reads migrations in order', function(done) {
      migration._readPendingMigrations().bind(this)
      .then(function(migrations) {
        expect(migrations).to.eql([
          { name: '20141022202234_create_articles', batch: 1 },
          { name: '20141022202634_create_comments', batch: 1 }
        ]);
      })
      .done(done, done);
    });

    it('does not include executed migrations', function(done) {
      adapter._execute.selectReturnsExecutedMigrations([
        '20141022202234_create_articles'
      ]);

      migration._readPendingMigrations().bind(this)
      .then(function(migrations) {
        expect(migrations).to.eql([
          { name: '20141022202634_create_comments', batch: 2 }
        ]);
      })
      .done(done, done);
    });

  });

  describe('#_loadPendingMigrations', function() {

    it('loads pending migrations', function(done) {
      adapter._execute.selectReturnsExecutedMigrations([
        '20141022202234_create_articles'
      ]);

      migration._loadPendingMigrations().bind(this)
      .then(function(migrations) {
        expect(migrations).to.eql([
          _.extend({
            name: '20141022202634_create_comments',
            batch: 2
          }, require('../fixtures/migrations/blog/' +
            '20141022202634_create_comments')),
        ]);
      })
      .done(done, done);
    });

  });

  describe('#_readExecutedMigrations', function() {

    it('reads migrations in order', function(done) {
      adapter._execute.selectReturnsExecutedMigrations([
        '20141022202634_create_comments',
        '20141022202234_create_articles'
      ]);

      migration._readExecutedMigrations().bind(this)
      .then(function(migrations) {
        expect(migrations).to.eql([
          { name: '20141022202234_create_articles', batch: 1 },
          { name: '20141022202634_create_comments', batch: 1 }
        ]);
      })
      .done(done, done);
    });

  });

  describe('#_loadExecutedMigrations', function() {

    it('loads migrations in order', function(done) {
      adapter._execute.selectReturnsExecutedMigrations([
        '20141022202234_create_articles'
      ]);

      migration._loadExecutedMigrations().bind(this)
      .then(function(migrations) {
        expect(migrations).to.eql([
          _.extend({
            name: '20141022202234_create_articles',
            batch: 1
          }, require('../fixtures/migrations/blog/' +
            '20141022202234_create_articles')),
        ]);
      })
      .done(done, done);
    });

  });

  describe('with pending migrations stubbed', function() {
    beforeEach(function() {
      var mod1 = this.mod1 = {
        up: sinon.spy(), down: sinon.spy(),
        name: 'migration_file_1', batch: 1
      };
      var mod2 = this.mod2 = {
        up: sinon.spy(), down: sinon.spy(),
        name: 'migration_file_2', batch: 1
      };
      sinon.stub(migration, '_loadPendingMigrations')
        .returns(BluebirdPromise.resolve([mod1, mod2]));
    });
    afterEach(function() {
      migration._loadPendingMigrations.restore();
    });

    describe('#migrate', function() {

      it('calls the up methods', function(done) {
        migration.migrate().bind(this).then(function() {
          expect(this.mod1.up).to.have.been.calledOnce;
          expect(this.mod2.up).to.have.been.calledOnce;
        })
        .done(done, done);
      });

      it('calls the up methods with the schema as a transaction', function(done) {
        migration.migrate().bind(this).then(function() {
          var schemaTransaction = schema.begin.returnValues[0];
          expect(this.mod1.up).to.have.been
            .calledWithExactly(schemaTransaction);
          expect(this.mod2.up).to.have.been
            .calledWithExactly(schemaTransaction);
        })
        .done(done, done);
      });

      it('does not call the down methods', function(done) {
        migration.migrate().bind(this).then(function() {
          expect(this.mod1.down).to.not.have.been.called;
          expect(this.mod2.down).to.not.have.been.called;
        })
        .done(done, done);
      });

      it('respects migration promises', function(done) {
        var sequence = 0;
        var up1Sequence;
        var up2Sequence;

        this.mod1.up = function() {
          return BluebirdPromise.delay(5).then(function() {
            up1Sequence = sequence++;
          });
        };
        this.mod2.up = function() {
          return BluebirdPromise.delay(0).then(function() {
            up2Sequence = sequence++;
          });
        };

        migration.migrate().then(function() {
          expect(up1Sequence).to.eql(0);
          expect(up2Sequence).to.eql(1);
        })
        .done(done, done);
      });

      it('rolls back transaction for failed migration', function(done) {
        this.mod2.up = function() {
          throw new Error('Intentional Error');
        };
        migration.migrate().throw('Migration should have been rolled back.')
        .catch(function(e) {
          expect(e.message).to.eql('Intentional Error');
          expect(adapter._execute.sqlCalls()).to.eql([
            ['BEGIN', []],
            ['ROLLBACK', []]
          ]);
        })
        .done(done, done);
      });

      it('records migrations in database', function(done) {
        migration.migrate().bind(this).then(function() {
          expect(adapter._execute.sqlCalls()).to.eql([
            ['BEGIN', []],
            [
              'INSERT INTO "azul_migrations" ("name", "batch") ' +
              'VALUES (?, ?), (?, ?)',
              ['migration_file_1', 1, 'migration_file_2', 1]
            ],
            ['COMMIT', []]
          ]);
        })
        .done(done, done);
      });
    });
  });

  describe('with pending migrations stubbed as empty', function() {
    beforeEach(function() {
      sinon.stub(migration, '_loadPendingMigrations')
        .returns(BluebirdPromise.resolve([]));
    });
    afterEach(function() {
      migration._loadPendingMigrations.restore();
    });

    describe('#migrate', function() {

      it('does not record migrations in database', function(done) {
        migration.migrate().bind(this).then(function() {
          expect(adapter._execute.sqlCalls()).to.eql([
            ['BEGIN', []],
            ['COMMIT', []]
          ]);
        })
        .done(done, done);
      });

    });

  });

  describe('with executed migrations stubbed', function() {
    beforeEach(function() {
      var mod1 = this.mod1 = {
        up: sinon.spy(), down: sinon.spy(),
        name: 'migration_file_1', batch: 1
      };
      var mod2 = this.mod2 = {
        up: sinon.spy(), down: sinon.spy(),
        name: 'migration_file_2', batch: 1
      };
      sinon.stub(migration, '_loadExecutedMigrations')
        .returns(BluebirdPromise.resolve([mod1, mod2]));
    });
    afterEach(function() {
      migration._loadExecutedMigrations.restore();
    });

    describe('#rollback', function() {

      it('calls the down methods', function(done) {
        migration.rollback().bind(this).then(function() {
          expect(this.mod1.down).to.have.been.calledOnce;
          expect(this.mod2.down).to.have.been.calledOnce;
        })
        .done(done, done);
      });

      it('calls the down methods with the schema as a transaction', function(done) {
        migration.rollback().bind(this).then(function() {
          var schemaTransaction = schema.begin.returnValues[0];
          expect(this.mod1.down).to.have.been
            .calledWithExactly(schemaTransaction);
          expect(this.mod2.down).to.have.been
            .calledWithExactly(schemaTransaction);
        })
        .done(done, done);
      });

      it('does not call the up methods', function(done) {
        migration.rollback().bind(this).then(function() {
          expect(this.mod1.up).to.not.have.been.called;
          expect(this.mod2.up).to.not.have.been.called;
        })
        .done(done, done);
      });

      it('respects migration promises', function(done) {
        var sequence = 0;
        var down1Sequence;
        var down2Sequence;

        this.mod1.down = function() {
          return BluebirdPromise.delay(5).then(function() {
            down1Sequence = sequence++;
          });
        };
        this.mod2.down = function() {
          return BluebirdPromise.delay(0).then(function() {
            down2Sequence = sequence++;
          });
        };

        migration.rollback().then(function() {
          expect(down1Sequence).to.eql(0);
          expect(down2Sequence).to.eql(1);
        })
        .done(done, done);
      });

      it('rolls back transaction for failed migration', function(done) {
        this.mod2.down = function() {
          throw new Error('Intentional Error');
        };
        migration.rollback().throw('Migration should have been rolled back.')
        .catch(function(e) {
          expect(e.message).to.eql('Intentional Error');
          expect(adapter._execute.sqlCalls()).to.eql([
            ['BEGIN', []],
            ['ROLLBACK', []]
          ]);
        })
        .done(done, done);
      });

      it('removes migrations recorded in database', function(done) {
        migration.rollback().bind(this).then(function() {
          expect(adapter._execute.sqlCalls()).to.eql([
            ['BEGIN', []],
            ['DELETE FROM "azul_migrations" WHERE "batch" = ?', [1]],
            ['COMMIT', []]
          ]);
        })
        .done(done, done);
      });
    });
  });

  describe('#_determineReverseAction', function() {
    // to make this happen, we'll probably want to pass a fake object off to
    // the migration's `change` method and record any calls that are made on
    // it. from there, the reverse actions can be built.

    // a possibly simpler way to do this would be to create a ReverseSchema
    // class that basically just has a bunch of functions that map to the
    // opposite of what they are. so `createTable` would map to a
    // `DropTableQuery` and (as long as the arguments match), that would be
    // all that was required. imposing a rule that reversible actions have
    // arguments that directly overlap with their reverse action's arguments
    // (drop table needs only the table name, but no more of create table's
    // arguments) may be easy. it'd also be easy to say it's _only_ the first
    // argument of the call through `createTable` that should be passed off to
    // the creation of a `DropTableQuery`. argument mapping may be more
    // complicated, but still could be decently easy.
    it('knows the reverse of creating a table');
  });

  // ADD FEATURE: hash migrations when they are run so we're able to warn the
  // user about migrations that have been altered after they've been applied.
  // store the hash in the migration table & any time migrations are run, check
  // that all previously run migrations still match their current values when
  // read from the disk. this could be extended to ensure that when rolling
  // back we prompt the user that this could potentially break and/or not
  // reverse the migration as intended.
});
<|endoftext|>


<commit_before>/* test/device_routes_test.js -- test Device routes
 * Copyright 2014 Sergei Ianovich
 *
 * Licensed under AGPL-3.0 or later, see LICENSE
 * Process Control Service Web Interface
 */

var expect = require('expect.js');
var Device = require('../models/device');
var Routes = require('../routes/device');
var router = require('./support/router');

var deviceAttrs = {
  name: "Some device",
};

describe('Device routes', function() {
  var device, count;
  before(function(done) {
    Factory.create('device', 26, function (l) {
      device = l[0];
      Device.count(function (err, c) {
        if (err) throw err;
        count = c;
        done();
      });
    });
  });

  var operator;
  before(function(done) {
    Factory.create('user', function (u) { operator = u; done(); });
  });

  var admin;
  before(function(done) {
    Factory.create('admin', function (a) { admin = a; done(); });
  });

  describe("#load", function() {
    it("should find by id and assign device to req", function(done) {
      var req = { },
      id = device._id;

      Routes.load(req, {}, function() {
        expect(req.device.toJSON()).to.eql(device.toJSON());
        done();
      }, id);
    });

    it("should respond with not found code", function(done) {
      var res = {
        send: function(code) {
          expect(code).to.eql(404);
          done();
        }
      };
      Routes.load({}, res, null, 0);
    });
  });

  describe("#show", function() {
    it("should deny access to non-signed-in users", function(done) {
      var req = { session: {} },
      res = { redirect: function(url) {
        expect(url).to.eql("/signin");
        done();
      }};
      router(Routes.show, req, res);
    });

    describe("when operator logged in", function() {
      var req;

      beforeEach(function() {
        req = { session: { operatorId: operator._id } };
      });

      it("should return 404 if no device", function(done) {
        var res = {
          locals: {},
          send: function(code) {
            expect(code).to.be(404);
            done();
          },
        };
        router(Routes.show, req, res);
      });

      it("should return only accessible fields", function(done) {
        var res = {
          locals: {},
          json_ng: function(dev) {
            expect(Object.keys(dev)).to.eql(['_id', 'name']);
            expect(dev._id).to.eql(device._id);
            expect(dev.name).to.eql(device.name);
            done();
          },
        };
        req.device = device;
        req.device.some_field = true;
        router(Routes.show, req, res);
      });
    });
  });

  describe("#update", function() {
    it("should deny access to non-signed-in users", function(done) {
      var req = { session: {} },
      res = { redirect: function(url) {
        expect(url).to.eql("/signin");
        done();
      }};
      router(Routes.update, req, res);
    });

    describe("when operator signed in", function() {
      var req;

      beforeEach(function() {
        req = { session: { operatorId: operator._id } };
      });

      it("should deny non-admins", function(done) {
        res = {
          locals: {},
          send: function(code) {
            expect(code).to.eql(403);
            done();
          },
        };
        router(Routes.update, req, res);
      });
    });

    describe("when administrator signed in", function() {
      var req;

      beforeEach(function() {
        req = { session: { operatorId: admin._id } };
      });

      it("should fail", function(done) {
        var res = {
          locals: {},
          json: function(code) {
            expect(code).to.eql(500);
            done();
          },
        };
        req.body = {
          name: "Some name",
        };
        req.device = device;
        router(Routes.update, req, res);
      });
    });
  });

  describe("#index", function() {
    it("should deny access to non-signed-in users", function(done) {
      var req = { session: {} },
      res = { redirect: function(url) {
        expect(url).to.eql("/signin");
        done();
      }};
      router(Routes.index, req, res);
    });

    describe("when operator signed in", function() {
      var req;

      beforeEach(function() {
        req = { session: { operatorId: operator._id } };
        req.query = {};
        res = {
          locals: {},
        };
      });

      it("should retrieve first page if not specified", function(done) {
        res.json_ng = function(devices) {
          expect(devices.length).to.be(26);
          expect(devices[25].count).to.be(count);
          done();
        };
        router(Routes.index, req, res);
      });

      it("should sort results by name", function(done) {
        var original = [];
        res.json_ng = function(devices) {
          var fetched = devices.slice(0, -1).map(function(item) {
            return item._id.toString();
          });
          expect(fetched).to.eql(original);
          done();
        };
        Device.find({}, "_id").sort({name: 1}).limit(25).exec(function(err, devices) {
          original = devices.map(function(item) { return item._id.toString(); });
          router(Routes.index, req, res);
        });
      });

      it("should retrieve requested page", function(done) {
        var original = [];
        res.json_ng = function(devices) {
          var fetched = devices.slice(0, -1).map(function(item) {
            return item._id.toString();
          });
          expect(fetched).to.eql(original);
          done();
        };
        req.query.page = 2;
        Device.find({}, "_id").sort({name: 1}).skip(25).limit(25).exec(function(err, devices) {
          original = devices.map(function(item) { return item._id.toString(); });
          router(Routes.index, req, res);
        });
      });

      it("should retrieve first one if page is less then 1", function(done) {
        var original = [];
        res.json_ng = function(devices) {
          var fetched = devices.slice(0, -1).map(function(item) {
            return item._id.toString();
          });
          expect(fetched).to.eql(original);
          done();
        };
        req.query.page = 0;
        Device.find({}, "_id").sort({name: 1}).limit(25).exec(function(err, devices) {
          original = devices.map(function(item) { return item._id.toString(); });
          router(Routes.index, req, res);
        });
      });

      it("should retrieve last one if page is too big", function(done) {
        var original = [];
        res.json_ng = function(devices) {
          var fetched = devices.slice(0, -1).map(function(item) {
            return item._id.toString();
          });
          expect(fetched).to.eql(original);
          done();
        };
        req.query.page = 3;
        Device.find({}, "_id").sort({name: 1}).skip(25).limit(25).exec(function(err, devices) {
          original = devices.map(function(item) { return item._id.toString(); });
          router(Routes.index, req, res);
        });
      });
    });
  });

  describe("#create", function() {
    it("should deny access to non-signed-in users", function(done) {
      var req = { session: {} },
      res = { redirect: function(url) {
        expect(url).to.eql("/signin");
        done();
      }};
      router(Routes.index, req, res);
    });

    describe("when operator signed in", function() {
      var req;

      beforeEach(function() {
        req = { session: { operatorId: operator._id } };
      });

      it("should deny non-admins", function(done) {
        res = {
          locals: {},
          send: function(code) {
            expect(code).to.eql(403);
            done();
          },
        };
        router(Routes.create, req, res);
      });
    });
  });
});

// vim:ts=2 sts=2 sw=2 et:
<commit_msg>tests: routes: device created by administrator<commit_after>/* test/device_routes_test.js -- test Device routes
 * Copyright 2014 Sergei Ianovich
 *
 * Licensed under AGPL-3.0 or later, see LICENSE
 * Process Control Service Web Interface
 */

var expect = require('expect.js');
var Device = require('../models/device');
var Routes = require('../routes/device');
var router = require('./support/router');

var deviceAttrs = {
  name: "Some device",
};

describe('Device routes', function() {
  var device, count;
  before(function(done) {
    Factory.create('device', 26, function (l) {
      device = l[0];
      Device.count(function (err, c) {
        if (err) throw err;
        count = c;
        done();
      });
    });
  });

  var operator;
  before(function(done) {
    Factory.create('user', function (u) { operator = u; done(); });
  });

  var admin;
  before(function(done) {
    Factory.create('admin', function (a) { admin = a; done(); });
  });

  describe("#load", function() {
    it("should find by id and assign device to req", function(done) {
      var req = { },
      id = device._id;

      Routes.load(req, {}, function() {
        expect(req.device.toJSON()).to.eql(device.toJSON());
        done();
      }, id);
    });

    it("should respond with not found code", function(done) {
      var res = {
        send: function(code) {
          expect(code).to.eql(404);
          done();
        }
      };
      Routes.load({}, res, null, 0);
    });
  });

  describe("#show", function() {
    it("should deny access to non-signed-in users", function(done) {
      var req = { session: {} },
      res = { redirect: function(url) {
        expect(url).to.eql("/signin");
        done();
      }};
      router(Routes.show, req, res);
    });

    describe("when operator logged in", function() {
      var req;

      beforeEach(function() {
        req = { session: { operatorId: operator._id } };
      });

      it("should return 404 if no device", function(done) {
        var res = {
          locals: {},
          send: function(code) {
            expect(code).to.be(404);
            done();
          },
        };
        router(Routes.show, req, res);
      });

      it("should return only accessible fields", function(done) {
        var res = {
          locals: {},
          json_ng: function(dev) {
            expect(Object.keys(dev)).to.eql(['_id', 'name']);
            expect(dev._id).to.eql(device._id);
            expect(dev.name).to.eql(device.name);
            done();
          },
        };
        req.device = device;
        req.device.some_field = true;
        router(Routes.show, req, res);
      });
    });
  });

  describe("#update", function() {
    it("should deny access to non-signed-in users", function(done) {
      var req = { session: {} },
      res = { redirect: function(url) {
        expect(url).to.eql("/signin");
        done();
      }};
      router(Routes.update, req, res);
    });

    describe("when operator signed in", function() {
      var req;

      beforeEach(function() {
        req = { session: { operatorId: operator._id } };
      });

      it("should deny non-admins", function(done) {
        res = {
          locals: {},
          send: function(code) {
            expect(code).to.eql(403);
            done();
          },
        };
        router(Routes.update, req, res);
      });
    });

    describe("when administrator signed in", function() {
      var req;

      beforeEach(function() {
        req = { session: { operatorId: admin._id } };
      });

      it("should fail", function(done) {
        var res = {
          locals: {},
          json: function(code) {
            expect(code).to.eql(500);
            done();
          },
        };
        req.body = {
          name: "Some name",
        };
        req.device = device;
        router(Routes.update, req, res);
      });
    });
  });

  describe("#index", function() {
    it("should deny access to non-signed-in users", function(done) {
      var req = { session: {} },
      res = { redirect: function(url) {
        expect(url).to.eql("/signin");
        done();
      }};
      router(Routes.index, req, res);
    });

    describe("when operator signed in", function() {
      var req;

      beforeEach(function() {
        req = { session: { operatorId: operator._id } };
        req.query = {};
        res = {
          locals: {},
        };
      });

      it("should retrieve first page if not specified", function(done) {
        res.json_ng = function(devices) {
          expect(devices.length).to.be(26);
          expect(devices[25].count).to.be(count);
          done();
        };
        router(Routes.index, req, res);
      });

      it("should sort results by name", function(done) {
        var original = [];
        res.json_ng = function(devices) {
          var fetched = devices.slice(0, -1).map(function(item) {
            return item._id.toString();
          });
          expect(fetched).to.eql(original);
          done();
        };
        Device.find({}, "_id").sort({name: 1}).limit(25).exec(function(err, devices) {
          original = devices.map(function(item) { return item._id.toString(); });
          router(Routes.index, req, res);
        });
      });

      it("should retrieve requested page", function(done) {
        var original = [];
        res.json_ng = function(devices) {
          var fetched = devices.slice(0, -1).map(function(item) {
            return item._id.toString();
          });
          expect(fetched).to.eql(original);
          done();
        };
        req.query.page = 2;
        Device.find({}, "_id").sort({name: 1}).skip(25).limit(25).exec(function(err, devices) {
          original = devices.map(function(item) { return item._id.toString(); });
          router(Routes.index, req, res);
        });
      });

      it("should retrieve first one if page is less then 1", function(done) {
        var original = [];
        res.json_ng = function(devices) {
          var fetched = devices.slice(0, -1).map(function(item) {
            return item._id.toString();
          });
          expect(fetched).to.eql(original);
          done();
        };
        req.query.page = 0;
        Device.find({}, "_id").sort({name: 1}).limit(25).exec(function(err, devices) {
          original = devices.map(function(item) { return item._id.toString(); });
          router(Routes.index, req, res);
        });
      });

      it("should retrieve last one if page is too big", function(done) {
        var original = [];
        res.json_ng = function(devices) {
          var fetched = devices.slice(0, -1).map(function(item) {
            return item._id.toString();
          });
          expect(fetched).to.eql(original);
          done();
        };
        req.query.page = 3;
        Device.find({}, "_id").sort({name: 1}).skip(25).limit(25).exec(function(err, devices) {
          original = devices.map(function(item) { return item._id.toString(); });
          router(Routes.index, req, res);
        });
      });
    });
  });

  describe("#create", function() {
    it("should deny access to non-signed-in users", function(done) {
      var req = { session: {} },
      res = { redirect: function(url) {
        expect(url).to.eql("/signin");
        done();
      }};
      router(Routes.index, req, res);
    });

    describe("when operator signed in", function() {
      var req;

      beforeEach(function() {
        req = { session: { operatorId: operator._id } };
      });

      it("should deny non-admins", function(done) {
        res = {
          locals: {},
          send: function(code) {
            expect(code).to.eql(403);
            done();
          },
        };
        router(Routes.create, req, res);
      });
    });

    describe("when administrator signed in", function() {
      var req;

      beforeEach(function() {
        req = { session: { operatorId: admin._id } };
        res = {
          locals: {},
        };
      });

      it("should create device with valid params", function(done) {
        req.body = {
          name: 'created device',
        }
        res.json = function(device) {
          expect(device._id).not.to.be.an('undefined');
          expect(device.name).to.be(req.body.name);
          done();
        };
        router(Routes.create, req, res);
      });
    });
  });
});

// vim:ts=2 sts=2 sw=2 et:
<|endoftext|>


<commit_before>var ErrorDataSource = require("../../data/ErrorDataSource");
var clean = require("../../cleanData").clean;
var falcor = require("./../../../lib/");
var Model = falcor.Model;
var chai = require("chai");
var expect = chai.expect;
var sinon = require('sinon');
var noOp = function() {};
var InvalidSourceError = require('../../../lib/errors/InvalidSourceError');
var errorOnCompleted = require('./../../errorOnCompleted');
var doneOnError = require('./../../doneOnError');

describe("Error", function() {
    it("should get a hard error from the DataSource with _treatDataSourceErrorsAsJSONGraphErrors.", function(done) {
        var model = new Model({
            source: new ErrorDataSource(503, "Timeout"),
            _treatDataSourceErrorsAsJSONGraphErrors: true
        });
        toObservable(model.
            get(["test", {to: 5}, "summary"])).
            doAction(noOp, function(err) {
                expect(err.length).to.equal(6);
                // not in boxValue mode
                var expected = {
                    path: [],
                    value: {
                        status: 503,
                        message: "Timeout"
                    }
                };
                err.forEach(function(e, i) {
                    expected.path = ["test", i, "summary"];
                    expect(e).to.deep.equals(expected);
                });
            }).
            subscribe(function() {
                done('Should not onNext');
            },
            function(e) {
                if (isAssertionError(e)) {
                    done(e);
                } else {
                    done();
                }
            },
            function() {
                done('Should not onComplete');
            });
    });

    it("should get a hard error from the DataSource.", function(done) {
        var model = new Model({
            source: new ErrorDataSource(503, "Timeout")
        });
        toObservable(model.
            get(["test", {to: 5}, "summary"])).
            doAction(noOp, function(err) {
                // not in boxValue mode
                var expected = {
                    $type: "error",
                    value: {
                        status: 503,
                        message: "Timeout"
                    }
                };

                expect(err).to.deep.equals(expected);
            }).
            subscribe(function() {
                done('Should not onNext');
            },
            function(e) {
                if (isAssertionError(e)) {
                    done(e);
                } else {
                    done();
                }
            },
            function() {
                done('Should not onComplete');
            });
    });

    it("should get a hard error from the DataSource with some data found in the cache with _treatDataSourceErrorsAsJSONGraphErrors.", function(done) {
        var model = new Model({
            _treatDataSourceErrorsAsJSONGraphErrors: true,
            source: new ErrorDataSource(503, "Timeout"),
            cache: {
                test: {
                    0: {
                        summary: "in cache"
                    },
                    5: {
                        summary: "in cache"
                    }
                }
            }
        });
        var onNext = sinon.spy();
        toObservable(model.
            get(["test", {to: 5}, "summary"])).
            doAction(onNext, function(err) {

                // Ensure onNext is called correctly
                expect(onNext.calledOnce, 'onNext called').to.be.ok;
                expect(clean(onNext.getCall(0).args[0]), 'json from onNext').to.deep.equals({
                    json: {
                        test: {
                            0: {summary: "in cache"},
                            5: {summary: "in cache"}
                        }
                    }
                });

                expect(err.length).to.equal(4);
                // not in boxValue mode
                var expected = {
                    path: [],
                    value: {
                        status: 503,
                        message: "Timeout"
                    }
                };
                err.forEach(function(e, i) {
                    expected.path = ["test", i + 1, "summary"];
                    expect(e).to.deep.equals(expected);
                });
            }).
            subscribe(noOp, doneOnError(done), errorOnCompleted(done));
    });

    it("should get a hard error from the DataSource with some data found in the cache.", function(done) {
        var model = new Model({
            source: new ErrorDataSource(503, "Timeout"),
            cache: {
                test: {
                    0: {
                        summary: "in cache"
                    },
                    5: {
                        summary: "in cache"
                    }
                }
            }
        });
        var onNext = sinon.spy();
        toObservable(model.
            get(["test", {to: 5}, "summary"])).
            doAction(onNext, function(err) {

                // Ensure onNext is not called
                expect(onNext.callCount, 'onNext called').to.equal(0);
                expect(clean(onNext.getCall(0).args[0]), 'json from onNext').to.deep.equals({
                    json: {
                        test: {
                            0: {summary: "in cache"},
                            5: {summary: "in cache"}
                        }
                    }
                });

                // not in boxValue mode
                var expected = {
                    $type: "error",
                    value: {
                        status: 503,
                        message: "Timeout"
                    }
                };
                expect(err).to.deep.equals(expected);
            }).
            subscribe(noOp, doneOnError(done), errorOnCompleted(done));
    });

    it('should allow for dataSources to immediately throw an error (set)', function(done) {
        var routes = {
            set: function() {
                return thisVarDoesNotExistAndThatsAFact;
            }
        };
        var model = new falcor.Model({ source: routes });
        var onNext = sinon.spy();
        var onError = sinon.spy();
        toObservable(model.
            set({
                paths: [['titlesById', 242, 'rating']],
                jsonGraph: {
                    titlesById: {
                        242: {
                            rating: 5
                        }
                    }
                }
            })).
            doAction(onNext, onError).
            doAction(noOp, function() {
                expect(onNext.callCount).to.equal(0);
                expect(onError.calledOnce).to.be.ok;
                expect(onError.getCall(0).args[0].name).to.equals(InvalidSourceError.name);
            }).
            subscribe(noOp, function(e) {
                if (isAssertionError(e)) {
                    return done(e);
                }
                return done();
            }, done.bind('should not complete'));
    });

    it('should allow for dataSources to immediately throw an error (get)', function(done) {
        var routes = {
            get: function() {
                return thisVarDoesNotExistAndThatsAFact;
            }
        };
        var model = new falcor.Model({ source: routes });
        var onNext = sinon.spy();
        var onError = sinon.spy();
        toObservable(model.
            get(['path', 'to', 'value'])).
            doAction(onNext, function(e) {
                expect(onNext.callCount).to.equal(0);
                expect(e.name, 'Expect error to be an InvalidSourceError').to.equals(InvalidSourceError.name);
            }).
            subscribe(noOp, function(e) {
                if (isAssertionError(e)) {
                    return done(e);
                }
                return done();
            }, done.bind('should not complete'));
    });

    it('should allow for dataSources to immediately throw an error (call)', function(done) {
        var routes = {
            call: function() {
                return thisVarDoesNotExistAndThatsAFact;
            }
        };
        var model = new falcor.Model({ source: routes });
        var onNext = sinon.spy();
        toObservable(model.
            call(['videos', 1234, 'rating'], 5)).
            doAction(onNext).
            doAction(noOp, function(err) {
                expect(onNext.callCount).to.equal(0);
                expect(err.name).to.equals(InvalidSourceError.name);
            }).
            subscribe(noOp, function(e) {
                if (isAssertionError(e)) {
                    return done(e);
                }
                return done();
            }, done.bind('should not complete'));
    });
});

function isAssertionError(e) {
    return e.hasOwnProperty('expected') && e.hasOwnProperty('actual');
}<commit_msg>Fix merged test<commit_after>var ErrorDataSource = require("../../data/ErrorDataSource");
var clean = require("../../cleanData").clean;
var falcor = require("./../../../lib/");
var Model = falcor.Model;
var chai = require("chai");
var expect = chai.expect;
var sinon = require('sinon');
var noOp = function() {};
var InvalidSourceError = require('../../../lib/errors/InvalidSourceError');
var errorOnCompleted = require('./../../errorOnCompleted');
var doneOnError = require('./../../doneOnError');

describe("Error", function() {
    it("should get a hard error from the DataSource with _treatDataSourceErrorsAsJSONGraphErrors.", function(done) {
        var model = new Model({
            source: new ErrorDataSource(503, "Timeout"),
            _treatDataSourceErrorsAsJSONGraphErrors: true
        });
        toObservable(model.
            get(["test", {to: 5}, "summary"])).
            doAction(noOp, function(err) {
                expect(err.length).to.equal(6);
                // not in boxValue mode
                var expected = {
                    path: [],
                    value: {
                        status: 503,
                        message: "Timeout"
                    }
                };
                err.forEach(function(e, i) {
                    expected.path = ["test", i, "summary"];
                    expect(e).to.deep.equals(expected);
                });
            }).
            subscribe(noOp,
            function(e) {
                if (isAssertionError(e)) {
                    done(e);
                } else {
                    done();
                }
            },
            function() {
                done('Should not onComplete');
            });
    });

    it("should get a hard error from the DataSource.", function(done) {
        var model = new Model({
            source: new ErrorDataSource(503, "Timeout")
        });
        toObservable(model.
            get(["test", {to: 5}, "summary"])).
            doAction(noOp, function(err) {
                // not in boxValue mode
                var expected = {
                    $type: "error",
                    value: {
                        status: 503,
                        message: "Timeout"
                    }
                };

                expect(err).to.deep.equals(expected);
            }).
            subscribe(function() {
                done('Should not onNext');
            },
            function(e) {
                if (isAssertionError(e)) {
                    done(e);
                } else {
                    done();
                }
            },
            function() {
                done('Should not onComplete');
            });
    });

    it("should get a hard error from the DataSource with some data found in the cache with _treatDataSourceErrorsAsJSONGraphErrors.", function(done) {
        var model = new Model({
            _treatDataSourceErrorsAsJSONGraphErrors: true,
            source: new ErrorDataSource(503, "Timeout"),
            cache: {
                test: {
                    0: {
                        summary: "in cache"
                    },
                    5: {
                        summary: "in cache"
                    }
                }
            }
        });
        var onNext = sinon.spy();
        toObservable(model.
            get(["test", {to: 5}, "summary"])).
            doAction(onNext, function(err) {

                // Ensure onNext is called correctly
                expect(onNext.calledOnce, 'onNext called').to.be.ok;
                expect(clean(onNext.getCall(0).args[0]), 'json from onNext').to.deep.equals({
                    json: {
                        test: {
                            0: {summary: "in cache"},
                            5: {summary: "in cache"}
                        }
                    }
                });

                expect(err.length).to.equal(4);
                // not in boxValue mode
                var expected = {
                    path: [],
                    value: {
                        status: 503,
                        message: "Timeout"
                    }
                };
                err.forEach(function(e, i) {
                    expected.path = ["test", i + 1, "summary"];
                    expect(e).to.deep.equals(expected);
                });
            }).
            subscribe(noOp, doneOnError(done), errorOnCompleted(done));
    });

    it("should get a hard error from the DataSource with some data found in the cache.", function(done) {
        var model = new Model({
            source: new ErrorDataSource(503, "Timeout"),
            cache: {
                test: {
                    0: {
                        summary: "in cache"
                    },
                    5: {
                        summary: "in cache"
                    }
                }
            }
        });
        var onNext = sinon.spy();
        toObservable(model.
            get(["test", {to: 5}, "summary"])).
            doAction(onNext, function(err) {

                // Ensure onNext is not called
                expect(onNext.callCount, 'onNext called').to.equal(0);
                expect(clean(onNext.getCall(0).args[0]), 'json from onNext').to.deep.equals({
                    json: {
                        test: {
                            0: {summary: "in cache"},
                            5: {summary: "in cache"}
                        }
                    }
                });

                // not in boxValue mode
                var expected = {
                    $type: "error",
                    value: {
                        status: 503,
                        message: "Timeout"
                    }
                };
                expect(err).to.deep.equals(expected);
            }).
            subscribe(noOp, doneOnError(done), errorOnCompleted(done));
    });

    it('should allow for dataSources to immediately throw an error (set)', function(done) {
        var routes = {
            set: function() {
                return thisVarDoesNotExistAndThatsAFact;
            }
        };
        var model = new falcor.Model({ source: routes });
        var onNext = sinon.spy();
        var onError = sinon.spy();
        toObservable(model.
            set({
                paths: [['titlesById', 242, 'rating']],
                jsonGraph: {
                    titlesById: {
                        242: {
                            rating: 5
                        }
                    }
                }
            })).
            doAction(onNext, onError).
            doAction(noOp, function() {
                expect(onNext.callCount).to.equal(0);
                expect(onError.calledOnce).to.be.ok;
                expect(onError.getCall(0).args[0].name).to.equals(InvalidSourceError.name);
            }).
            subscribe(noOp, function(e) {
                if (isAssertionError(e)) {
                    return done(e);
                }
                return done();
            }, done.bind('should not complete'));
    });

    it('should allow for dataSources to immediately throw an error (get)', function(done) {
        var routes = {
            get: function() {
                return thisVarDoesNotExistAndThatsAFact;
            }
        };
        var model = new falcor.Model({ source: routes });
        var onNext = sinon.spy();
        var onError = sinon.spy();
        toObservable(model.
            get(['path', 'to', 'value'])).
            doAction(onNext, function(e) {
                expect(onNext.callCount).to.equal(0);
                expect(e.name, 'Expect error to be an InvalidSourceError').to.equals(InvalidSourceError.name);
            }).
            subscribe(noOp, function(e) {
                if (isAssertionError(e)) {
                    return done(e);
                }
                return done();
            }, done.bind('should not complete'));
    });

    it('should allow for dataSources to immediately throw an error (call)', function(done) {
        var routes = {
            call: function() {
                return thisVarDoesNotExistAndThatsAFact;
            }
        };
        var model = new falcor.Model({ source: routes });
        var onNext = sinon.spy();
        toObservable(model.
            call(['videos', 1234, 'rating'], 5)).
            doAction(onNext).
            doAction(noOp, function(err) {
                expect(onNext.callCount).to.equal(0);
                expect(err.name).to.equals(InvalidSourceError.name);
            }).
            subscribe(noOp, function(e) {
                if (isAssertionError(e)) {
                    return done(e);
                }
                return done();
            }, done.bind('should not complete'));
    });
});

function isAssertionError(e) {
    return e.hasOwnProperty('expected') && e.hasOwnProperty('actual');
}<|endoftext|>


<commit_before>// @ts-check
//
// The line above enables type checking for this file. Various IDEs interpret
// the @ts-check directive. It will give you helpful autocompletion when
// implementing this exercise. You don't need to understand it in order to
// benefit from it.
//
// In your own projects, files, and code, you can play with @ts-check as well.

/**
 * Respond with the correct character, given the blurb, if this were said at
 * the front door.
 *
 * @param {string} blurb
 * @returns {string}
 */
export function frontDoorResponse(blurb) {
  throw new Error('Implement the frontDoorResponse function');
}

/**
 * Respond with the correct character, given the blurb, if this were said at
 * the back door.
 *
 * @param {string} blurb
 * @returns {string}
 */
export function backDoorResponse(blurb) {
  throw new Error('Implement the backDoorResponse function');
}

/**
 * Capitalizes a word, meaning only the first character is a capital, and the
 * remaining letters are lower case.
 *
 * @param {string} word
 * @returns {string}
 */
function capitalize(word) {
  throw new Error('Implement the capitalize function');
}

/**
 * Give the password for the front-door, given the responses.
 *
 * @param {string} responses the responses
 * @returns {string} the password
 */
export function frontDoorPassword(responses) {
  return capitalize(responses);
}

/**
 * Give the password for the back-door, given the responses.
 *
 * @param {string} responses the responses
 * @returns {string} the password
 */
export function backDoorPassword(responses) {
  return capitalize(responses);
}
<commit_msg>Add welcome block<commit_after>// @ts-check
//
// ☝🏽 The line above enables type checking for this file. Various IDEs interpret
// the @ts-check directive. It will give you helpful autocompletion on the web
// and supported IDEs when implementing this exercise. You don't need to
// understand types, JSDoc, or TypeScript in order to complete this JavaScript
// exercise, and can completely ignore this comment block and directive.
//
// 👋🏽 Hi again!
//
// A quick reminder about exercise stubs:
//
// 💡 You're allowed to completely clear any stub before you get started. Often
// we recommend using the stub, because they are already set-up correctly to
// work with the tests, which you can find in ./freelancer-rates.spec.js.
//
// 💡 You don't need to write JSDoc comment blocks yourself; it is not expected
// in idiomatic JavaScript, but some companies and style-guides do enforce them.
//
// Good luck with that door policy!

/**
 * Respond with the correct character, given the blurb, if this were said at
 * the front door.
 *
 * @param {string} blurb
 * @returns {string}
 */
export function frontDoorResponse(blurb) {
  throw new Error('Implement the frontDoorResponse function');
}

/**
 * Respond with the correct character, given the blurb, if this were said at
 * the back door.
 *
 * @param {string} blurb
 * @returns {string}
 */
export function backDoorResponse(blurb) {
  throw new Error('Implement the backDoorResponse function');
}

/**
 * Capitalizes a word, meaning only the first character is a capital, and the
 * remaining letters are lower case.
 *
 * @param {string} word
 * @returns {string}
 */
function capitalize(word) {
  throw new Error('Implement the capitalize function');
}

/**
 * Give the password for the front-door, given the responses.
 *
 * @param {string} responses the responses
 * @returns {string} the password
 */
export function frontDoorPassword(responses) {
  return capitalize(responses);
}

/**
 * Give the password for the back-door, given the responses.
 *
 * @param {string} responses the responses
 * @returns {string} the password
 */
export function backDoorPassword(responses) {
  return capitalize(responses);
}
<|endoftext|>