<commit_before>import chai, { expect } from 'chai';
import chaiAsPromised from 'chai-as-promised';
import _ from 'underscore';
import { delayPromise } from 'apify-shared/utilities';
import log from 'apify-shared/log';
import AutoscaledPool from '../../build/autoscaling/autoscaled_pool';

/* eslint-disable no-underscore-dangle */

chai.use(chaiAsPromised);

describe('AutoscaledPool', () => {
    let logLevel;
    before(() => {
        logLevel = log.getLevel();
        log.setLevel(log.LEVELS.ERROR);
    });

    after(() => {
        log.setLevel(logLevel);
    });

    it('should work with concurrency 1', async () => {
        const range = _.range(0, 10);
        const result = [];

        let isFinished = false;

        const runTaskFunction = () => {
            if (range.length === 1) {
                isFinished = true;
            }

            return new Promise((resolve) => {
                const item = range.shift();
                result.push(item);
                setTimeout(resolve, 5);
            });
        };

        const pool = new AutoscaledPool({
            minConcurrency: 1,
            maxConcurrency: 1,
            runTaskFunction,
            isFinishedFunction: () => Promise.resolve(isFinished),
            isTaskReadyFunction: () => Promise.resolve(!isFinished),
        });
        const startedAt = Date.now();
        await pool.run();

        expect(result).to.be.eql(_.range(0, 10));
        expect(Date.now() - startedAt).to.be.within(50, 200);
    });

    it('should work with concurrency 10', async () => {
        const range = _.range(0, 100);
        const result = [];

        let isFinished = false;

        const runTaskFunction = () => {
            if (range.length === 1) {
                isFinished = true;
            }

            return new Promise((resolve) => {
                const item = range.shift();
                result.push(item);
                setTimeout(resolve, 5);
            });
        };

        const pool = new AutoscaledPool({
            minConcurrency: 10,
            maxConcurrency: 10,
            runTaskFunction,
            isFinishedFunction: () => Promise.resolve(isFinished),
            isTaskReadyFunction: () => Promise.resolve(!isFinished),
        });

        const startedAt = Date.now();
        await pool.run();

        expect(result).to.be.eql(_.range(0, 100));
        expect(Date.now() - startedAt).to.be.within(50, 200);
    });

    describe('should scale correctly', () => {
        class MockSystemStatus {
            constructor(okNow, okLately) {
                this.okNow = okNow;
                this.okLately = okLately;
                this.getCurrentStatus = () => ({ isSystemIdle: this.okNow });
                this.getHistoricalStatus = () => ({ isSystemIdle: this.okLately });
            }
        }

        let pool;
        let systemStatus;
        const cb = () => {};
        beforeEach(() => {
            systemStatus = new MockSystemStatus(true, true);
            pool = new AutoscaledPool({
                minConcurrency: 1,
                maxConcurrency: 100,
                runTaskFunction: async () => {},
                isFinishedFunction: async () => false,
                isTaskReadyFunction: async () => true,
            });
            pool.systemStatus = systemStatus;
        });

        it('works with low values', () => {
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(2);

            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(2); // because currentConcurrency is not high enough;

            pool.currentConcurrency = 2;
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(3);

            systemStatus.okNow = false; // this should have no effect
            pool.currentConcurrency = 3;
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(4);

            systemStatus.okLately = false;
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(3);
        });

        it('works with high values', () => {
            // Should not scale because current concurrency is too low.
            pool.desiredConcurrency = 50;
            pool.currentConcurrency = Math.floor(pool.desiredConcurrency * pool.desiredConcurrencyRatio) - 1;
            systemStatus.okLately = true;
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(50);

            // Should scale because we bumped up current concurrency.
            pool.currentConcurrency = Math.floor(pool.desiredConcurrency * pool.desiredConcurrencyRatio);
            let newConcurrency = pool.desiredConcurrency + Math.ceil(pool.desiredConcurrency * pool.scaleUpStepRatio);
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(newConcurrency);

            // Should scale down.
            systemStatus.okLately = false;
            newConcurrency = pool.desiredConcurrency - Math.ceil(pool.desiredConcurrency * pool.scaleDownStepRatio);
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(newConcurrency);
        });

        it('works at minConcurrency when currently overloaded', async () => {
            let limit = 5;
            let concurrencyLog = [];
            let count = 0;
            pool.systemStatus.okNow = false;
            pool.runTaskFunction = async () => {
                await delayPromise(10);
                count++;
            };
            pool.isFinishedFunction = async () => count >= limit;
            pool.isTaskReadyFunction = async () => count < limit;
            pool.desiredConcurrency = 10;
            pool._currentConcurrency = pool.currentConcurrency;

            Object.defineProperty(pool, 'currentConcurrency', {
                get() {
                    return this._currentConcurrency;
                },
                set(v) {
                    concurrencyLog.push(v);
                    this._currentConcurrency = v;
                },
            });

            expect(pool.currentConcurrency).to.be.eql(0);

            await pool.run();
            expect(concurrencyLog.some(n => n > 1)).to.be.eql(false);

            limit = 50;
            concurrencyLog = [];
            count = 0;
            pool.minConcurrency = 5;

            await pool.run();
            expect(concurrencyLog.some(n => n > 5)).to.be.eql(false);
        });
    });

    describe('should throw', () => {
        // Turn off unnecessary error logging.
        let originalLevel;
        before(() => {
            originalLevel = log.getLevel();
            log.setLevel(log.LEVELS.OFF);
        });

        after(() => {
            log.setLevel(originalLevel);
        });

        it('when some of the promises throws', async () => {
            let counter = 0;
            const runTaskFunction = () => {
                counter++;

                if (counter > 100) return;

                if (counter === 100) {
                    const err = new Error('some-promise-error');

                    return new Promise((resolve, reject) => setTimeout(reject(err), 3));
                }

                return delayPromise(3);
            };

            const pool = new AutoscaledPool({
                minConcurrency: 10,
                maxConcurrency: 10,
                runTaskFunction,
                isFinishedFunction: () => Promise.resolve(false),
                isTaskReadyFunction: () => Promise.resolve(true),
            });

            await expect(pool.run()).to.be.rejectedWith('some-promise-error');
        });

        it('when runTaskFunction throws', async () => {
            const runTaskFunction = () => {
                throw new Error('some-runtask-error');
            };

            const pool = new AutoscaledPool({
                minConcurrency: 10,
                maxConcurrency: 10,
                runTaskFunction,
                isFinishedFunction: () => Promise.resolve(false),
                isTaskReadyFunction: () => Promise.resolve(true),
            });

            await expect(pool.run()).to.be.rejectedWith('some-runtask-error');
        });

        it('when isFinishedFunction throws', async () => {
            let count = 0;
            const pool = new AutoscaledPool({
                minConcurrency: 10,
                maxConcurrency: 10,
                runTaskFunction: async () => { count++; },
                isFinishedFunction: async () => { throw new Error('some-finished-error'); },
                isTaskReadyFunction: async () => count < 1,
            });

            await expect(pool.run()).to.be.rejectedWith('some-finished-error');
        });

        it('when isTaskReadyFunction throws', async () => {
            let count = 0;
            const pool = new AutoscaledPool({
                minConcurrency: 10,
                maxConcurrency: 10,
                runTaskFunction: async () => { count++; },
                isFinishedFunction: async () => false,
                isTaskReadyFunction: async () => {
                    if (count > 1) throw new Error('some-ready-error');
                    else return true;
                },
            });

            await expect(pool.run()).to.be.rejectedWith('some-ready-error');
        });
    });

    it('should not handle tasks added after isFinishedFunction returned true', async () => {
        const tasks = [];
        const finished = [];

        let isFinished = false;

        // Prepare 3 tasks.
        tasks.push(() => delayPromise(10).then(() => finished.push(0)));
        tasks.push(() => delayPromise(10).then(() => finished.push(1)));
        tasks.push(() => delayPromise(10).then(() => finished.push(2)));

        // Run the pool and close it after 3s.
        const pool = new AutoscaledPool({
            minConcurrency: 3,
            runTaskFunction: () => {
                const task = tasks.shift();
                if (!task) return;
                return task();
            },
            isFinishedFunction: () => Promise.resolve(isFinished),
            isTaskReadyFunction: () => Promise.resolve(!isFinished),
        });
        pool.maybeRunIntervalMillis = 5;

        const poolPromise = pool.run();
        // This is an important part of the test to see if the tasks do not get
        // stuck in a microtask cycle. Do not refactor this to some other scheduling.
        setTimeout(() => {
            isFinished = true;
        }, 50);
        // Add 2 tasks after 70ms.
        setTimeout(() => tasks.push(() => delayPromise(5).then(() => finished.push(3))), 70);
        setTimeout(() => tasks.push(() => delayPromise(5).then(() => finished.push(4))), 70);
        // Make sure tasks were not added.
        await delayPromise(100);

        // Check finished tasks.
        await poolPromise;
        expect(finished).to.be.eql([0, 1, 2]);
    });

    it('should break and resume when the task queue is empty for a while', async () => {
        const finished = [];
        let isFinished = false;
        let isTaskReady = true;

        let counter = 0;
        const pool = new AutoscaledPool({
            maxConcurrency: 1,
            runTaskFunction: async () => {
                await delayPromise(1);
                if (counter === 10) { isTaskReady = false; setTimeout(() => { isTaskReady = true; }, 10); }
                if (counter === 19) { isTaskReady = false; isFinished = true; }
                counter++;
                finished.push(Date.now());
            },
            isFinishedFunction: async () => isFinished,
            isTaskReadyFunction: async () => !isFinished && isTaskReady,
        });
        pool.maybeRunIntervalMillis = 1;
        await pool.run();

        // Check finished tasks.
        expect(finished).to.have.lengthOf(20);
        expect(finished[11] - finished[10]).to.be.above(9);
    });

    it('should work with loggingIntervalMillis = null', async () => {
        const pool = new AutoscaledPool({
            minConcurrency: 1,
            maxConcurrency: 100,
            runTaskFunction: () => Promise.resolve(),
            isFinishedFunction: () => Promise.resolve(false),
            isTaskReadyFunction: () => Promise.resolve(true),
            loggingIntervalMillis: null,
        });
        pool._autoscale(() => {});
        expect(pool.desiredConcurrency).to.be.eql(2);
    });

    it('should abort', async () => {
        let finished = false;
        let aborted = false;
        const pool = new AutoscaledPool({
            runTaskFunction: () => {
                if (!aborted) {
                    return (async () => {
                        await pool.abort();
                        aborted = true;
                    })();
                }
                return null;
            },
            isFinishedFunction: () => { finished = true; },
            isTaskReadyFunction: () => !aborted,
        });
        await pool.run();
        expect(finished).to.be.eql(false);
    });

    it('should only finish after tasks complete', async () => {
        let started = false;
        let completed = false;

        const pool = new AutoscaledPool({
            runTaskFunction: async () => {
                started = true;
                await delayPromise(100);
                completed = true;
            },

            isFinishedFunction: async () => {
                return started;
            },

            isTaskReadyFunction: async () => {
                return !started;
            },
        });

        await pool.run();
        expect(started).to.be.eql(true);
        expect(completed).to.be.eql(true);
    });
});

/* eslint-enable no-underscore-dangle */
<commit_msg>Fix unrelated flaky test<commit_after>import chai, { expect } from 'chai';
import chaiAsPromised from 'chai-as-promised';
import _ from 'underscore';
import { delayPromise } from 'apify-shared/utilities';
import log from 'apify-shared/log';
import AutoscaledPool from '../../build/autoscaling/autoscaled_pool';

/* eslint-disable no-underscore-dangle */

chai.use(chaiAsPromised);

describe('AutoscaledPool', () => {
    let logLevel;
    before(() => {
        logLevel = log.getLevel();
        log.setLevel(log.LEVELS.ERROR);
    });

    after(() => {
        log.setLevel(logLevel);
    });

    it('should work with concurrency 1', async () => {
        const range = _.range(0, 10);
        const result = [];

        let isFinished = false;

        const runTaskFunction = () => {
            if (range.length === 1) {
                isFinished = true;
            }

            return new Promise((resolve) => {
                const item = range.shift();
                result.push(item);
                setTimeout(resolve, 5);
            });
        };

        const pool = new AutoscaledPool({
            minConcurrency: 1,
            maxConcurrency: 1,
            runTaskFunction,
            isFinishedFunction: () => Promise.resolve(isFinished),
            isTaskReadyFunction: () => Promise.resolve(!isFinished),
        });
        const startedAt = Date.now();
        await pool.run();

        expect(result).to.be.eql(_.range(0, 10));
        expect(Date.now() - startedAt).to.be.within(50, 200);
    });

    it('should work with concurrency 10', async () => {
        const range = _.range(0, 100);
        const result = [];

        let isFinished = false;

        const runTaskFunction = () => {
            if (range.length === 1) {
                isFinished = true;
            }

            return new Promise((resolve) => {
                const item = range.shift();
                result.push(item);
                setTimeout(resolve, 5);
            });
        };

        const pool = new AutoscaledPool({
            minConcurrency: 10,
            maxConcurrency: 10,
            runTaskFunction,
            isFinishedFunction: () => Promise.resolve(isFinished),
            isTaskReadyFunction: () => Promise.resolve(!isFinished),
        });

        const startedAt = Date.now();
        await pool.run();

        expect(result).to.be.eql(_.range(0, 100));
        expect(Date.now() - startedAt).to.be.within(50, 200);
    });

    describe('should scale correctly', () => {
        class MockSystemStatus {
            constructor(okNow, okLately) {
                this.okNow = okNow;
                this.okLately = okLately;
                this.getCurrentStatus = () => ({ isSystemIdle: this.okNow });
                this.getHistoricalStatus = () => ({ isSystemIdle: this.okLately });
            }
        }

        let pool;
        let systemStatus;
        const cb = () => {};
        beforeEach(() => {
            systemStatus = new MockSystemStatus(true, true);
            pool = new AutoscaledPool({
                minConcurrency: 1,
                maxConcurrency: 100,
                runTaskFunction: async () => {},
                isFinishedFunction: async () => false,
                isTaskReadyFunction: async () => true,
            });
            pool.systemStatus = systemStatus;
        });

        it('works with low values', () => {
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(2);

            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(2); // because currentConcurrency is not high enough;

            pool.currentConcurrency = 2;
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(3);

            systemStatus.okNow = false; // this should have no effect
            pool.currentConcurrency = 3;
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(4);

            systemStatus.okLately = false;
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(3);
        });

        it('works with high values', () => {
            // Should not scale because current concurrency is too low.
            pool.desiredConcurrency = 50;
            pool.currentConcurrency = Math.floor(pool.desiredConcurrency * pool.desiredConcurrencyRatio) - 1;
            systemStatus.okLately = true;
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(50);

            // Should scale because we bumped up current concurrency.
            pool.currentConcurrency = Math.floor(pool.desiredConcurrency * pool.desiredConcurrencyRatio);
            let newConcurrency = pool.desiredConcurrency + Math.ceil(pool.desiredConcurrency * pool.scaleUpStepRatio);
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(newConcurrency);

            // Should scale down.
            systemStatus.okLately = false;
            newConcurrency = pool.desiredConcurrency - Math.ceil(pool.desiredConcurrency * pool.scaleDownStepRatio);
            pool._autoscale(cb);
            expect(pool.desiredConcurrency).to.be.eql(newConcurrency);
        });

        it('works at minConcurrency when currently overloaded', async () => {
            let limit = 5;
            let concurrencyLog = [];
            let count = 0;
            pool.systemStatus.okNow = false;
            pool.runTaskFunction = async () => {
                await delayPromise(10);
                count++;
            };
            pool.isFinishedFunction = async () => count >= limit;
            pool.isTaskReadyFunction = async () => count < limit;
            pool.desiredConcurrency = 10;
            pool._currentConcurrency = pool.currentConcurrency;

            Object.defineProperty(pool, 'currentConcurrency', {
                get() {
                    return this._currentConcurrency;
                },
                set(v) {
                    concurrencyLog.push(v);
                    this._currentConcurrency = v;
                },
            });

            expect(pool.currentConcurrency).to.be.eql(0);

            await pool.run();
            expect(concurrencyLog.some(n => n > 1)).to.be.eql(false);

            limit = 50;
            concurrencyLog = [];
            count = 0;
            pool.minConcurrency = 5;

            await pool.run();
            expect(concurrencyLog.some(n => n > 5)).to.be.eql(false);
        });
    });

    describe('should throw', () => {
        // Turn off unnecessary error logging.
        let originalLevel;
        before(() => {
            originalLevel = log.getLevel();
            log.setLevel(log.LEVELS.OFF);
        });

        after(() => {
            log.setLevel(originalLevel);
        });

        it('when some of the promises throws', async () => {
            let counter = 0;
            const runTaskFunction = () => {
                counter++;

                if (counter > 100) return;

                if (counter === 100) {
                    const err = new Error('some-promise-error');

                    return new Promise((resolve, reject) => setTimeout(reject(err), 3));
                }

                return delayPromise(3);
            };

            const pool = new AutoscaledPool({
                minConcurrency: 10,
                maxConcurrency: 10,
                runTaskFunction,
                isFinishedFunction: () => Promise.resolve(false),
                isTaskReadyFunction: () => Promise.resolve(true),
            });

            await expect(pool.run()).to.be.rejectedWith('some-promise-error');
        });

        it('when runTaskFunction throws', async () => {
            const runTaskFunction = () => {
                throw new Error('some-runtask-error');
            };

            const pool = new AutoscaledPool({
                minConcurrency: 10,
                maxConcurrency: 10,
                runTaskFunction,
                isFinishedFunction: () => Promise.resolve(false),
                isTaskReadyFunction: () => Promise.resolve(true),
            });

            await expect(pool.run()).to.be.rejectedWith('some-runtask-error');
        });

        it('when isFinishedFunction throws', async () => {
            let count = 0;
            const pool = new AutoscaledPool({
                minConcurrency: 10,
                maxConcurrency: 10,
                runTaskFunction: async () => { count++; },
                isFinishedFunction: async () => { throw new Error('some-finished-error'); },
                isTaskReadyFunction: async () => count < 1,
            });

            await expect(pool.run()).to.be.rejectedWith('some-finished-error');
        });

        it('when isTaskReadyFunction throws', async () => {
            let count = 0;
            const pool = new AutoscaledPool({
                minConcurrency: 10,
                maxConcurrency: 10,
                runTaskFunction: async () => { count++; },
                isFinishedFunction: async () => false,
                isTaskReadyFunction: async () => {
                    if (count > 1) throw new Error('some-ready-error');
                    else return true;
                },
            });

            await expect(pool.run()).to.be.rejectedWith('some-ready-error');
        });
    });

    it('should not handle tasks added after isFinishedFunction returned true', async () => {
        const isFinished = async () => count > 10;
        let count = 0;

        // Run the pool and close it after 3s.
        const pool = new AutoscaledPool({
            minConcurrency: 3,
            runTaskFunction: async () => delayPromise(1).then(() => { count++; }),
            isFinishedFunction: async () => isFinished(),
            isTaskReadyFunction: async () => !await isFinished(),
        });
        pool.maybeRunIntervalMillis = 5;

        await pool.run();
        await delayPromise(10);
        // Check finished tasks.
        expect(count).to.be.within(11, 13);
    });

    it('should break and resume when the task queue is empty for a while', async () => {
        const finished = [];
        let isFinished = false;
        let isTaskReady = true;

        let counter = 0;
        const pool = new AutoscaledPool({
            maxConcurrency: 1,
            runTaskFunction: async () => {
                await delayPromise(1);
                if (counter === 10) { isTaskReady = false; setTimeout(() => { isTaskReady = true; }, 10); }
                if (counter === 19) { isTaskReady = false; isFinished = true; }
                counter++;
                finished.push(Date.now());
            },
            isFinishedFunction: async () => isFinished,
            isTaskReadyFunction: async () => !isFinished && isTaskReady,
        });
        pool.maybeRunIntervalMillis = 1;
        await pool.run();

        // Check finished tasks.
        expect(finished).to.have.lengthOf(20);
        expect(finished[11] - finished[10]).to.be.above(9);
    });

    it('should work with loggingIntervalMillis = null', async () => {
        const pool = new AutoscaledPool({
            minConcurrency: 1,
            maxConcurrency: 100,
            runTaskFunction: () => Promise.resolve(),
            isFinishedFunction: () => Promise.resolve(false),
            isTaskReadyFunction: () => Promise.resolve(true),
            loggingIntervalMillis: null,
        });
        pool._autoscale(() => {});
        expect(pool.desiredConcurrency).to.be.eql(2);
    });

    it('should abort', async () => {
        let finished = false;
        let aborted = false;
        const pool = new AutoscaledPool({
            runTaskFunction: () => {
                if (!aborted) {
                    return (async () => {
                        await pool.abort();
                        aborted = true;
                    })();
                }
                return null;
            },
            isFinishedFunction: () => { finished = true; },
            isTaskReadyFunction: () => !aborted,
        });
        await pool.run();
        expect(finished).to.be.eql(false);
    });

    it('should only finish after tasks complete', async () => {
        let started = false;
        let completed = false;

        const pool = new AutoscaledPool({
            runTaskFunction: async () => {
                started = true;
                await delayPromise(100);
                completed = true;
            },

            isFinishedFunction: async () => {
                return started;
            },

            isTaskReadyFunction: async () => {
                return !started;
            },
        });

        await pool.run();
        expect(started).to.be.eql(true);
        expect(completed).to.be.eql(true);
    });
});

/* eslint-enable no-underscore-dangle */
<|endoftext|>


<commit_before>/* eslint-env mocha */
'use strict'

const ipfsd = require('../src')
const config = require('../src/config')
const exec = require('../src/exec')
const expect = require('chai').expect
const ipfsApi = require('ipfs-api')
const fs = require('fs')
const series = require('run-series')
const rimraf = require('rimraf')
const path = require('path')

describe('disposable node with local api', function () {
  this.timeout(30000)
  let ipfs
  let node

  before((done) => {
    // Remove default exec dir at start, if any
    rimraf.sync(config.defaultExecPath)
    ipfsd.disposable((err, ipfsNode) => {
      if (err) throw err
      node = ipfsNode
      node.startDaemon((err, ignore) => {
        if (err) throw err
        ipfs = ipfsApi(node.apiAddr)
        done()
      })
    })
  })

  it('the binary should be checked', () => {
    expect(node.checked).to.be.true
  })

  it('should have started the daemon and returned an api', () => {
    expect(ipfs).to.be.ok
    expect(ipfs.id).to.be.ok
  })

  it('should have downloaded the binary to the default directory', () => {
    expect(fs.existsSync(config.defaultExecPath)).to.be.true
  })

  let store, retrieve

  before((done) => {
    const blorb = Buffer('blorb')
    ipfs.block.put(blorb, (err, res) => {
      if (err) throw err
      store = res.Key

      ipfs.block.get(res.Key, (err, res) => {
        if (err) throw err
        let buf = ''
        res
          .on('data', (data) => {
            buf += data
          })
          .on('end', () => {
            retrieve = buf
            done()
          })
      })
    })
  })

  it('should be able to store objects', () => {
    expect(store).to.be.equal('QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rAQ')
  })

  it('should be able to retrieve objects', () => {
    expect(retrieve).to.be.equal('blorb')
  })
})

describe('disposable node without being initialized', function () {
  this.timeout(30000)
  let node

  it('binary should not be checked and node should be clean', (done) => {
    ipfsd.disposable({init: false}, (err, ipfsNode) => {
      node = ipfsNode
      expect(err).to.not.exist
      expect(node.checked).to.be.false
      expect(node.clean).to.be.true
      done()
    })
  })

  it('binary should be checked and node should not be clean', (done) => {
    node.init((err, ignore) => {
      expect(err).to.not.exist
      expect(node.checked).to.be.true
      expect(node.clean).to.be.false
      expect(fs.existsSync(config.defaultExecPath)).to.be.true
      done()
    })
  })
})

describe('disposableApi node', function () {
  this.timeout(30000)
  let ipfs
  before((done) => {
    ipfsd.disposableApi((err, api) => {
      if (err) throw err
      ipfs = api
      done()
    })
  })

  it('should have started the daemon and returned an api with host/port', () => {
    expect(ipfs).to.be.ok
    expect(ipfs.id).to.be.ok
    expect(ipfs.apiHost).to.be.ok
    expect(ipfs.apiPort).to.be.ok
  })

  let store, retrieve

  before((done) => {
    const blorb = Buffer('blorb')
    ipfs.block.put(blorb, (err, res) => {
      if (err) throw err
      store = res.Key

      ipfs.block.get(res.Key, (err, res) => {
        if (err) throw err
        let buf = ''
        res
          .on('data', (data) => {
            buf += data
          })
          .on('end', () => {
            retrieve = buf
            done()
          })
      })
    })
  })

  it('should be able to store objects', () => {
    expect(store).to.be.equal('QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rAQ')
  })

  it('should be able to retrieve objects', () => {
    expect(retrieve).to.be.equal('blorb')
  })
})

describe('starting and stopping', function () {
  this.timeout(30000)
  let node

  describe('init', () => {
    before((done) => {
      ipfsd.disposable((err, res) => {
        if (err) throw err
        node = res
        done()
      })
    })

    it('should have returned a node', () => {
      expect(node).to.be.ok
    })

    it('daemon should not be running', () => {
      expect(node.daemonPid()).to.not.be.ok
    })
  })

  let pid

  describe('starting', () => {
    let ipfs
    before((done) => {
      node.startDaemon((err, res) => {
        if (err) throw err

        pid = node.daemonPid()
        ipfs = res

        // actually running?
        exec('kill', ['-0', pid], {}, done)
      })
    })

    it('should be running', () => {
      expect(ipfs.id).to.be.ok
    })
  })

  let stopped = false
  describe('stopping', () => {
    before((done) => {
      node.stopDaemon((err) => {
        if (err) throw err
        stopped = true
      })
      // make sure it's not still running
      const poll = setInterval(() => {
        exec('kill', ['-0', pid], {}, {
          error: () => {
            clearInterval(poll)
            done()
            done = () => {} // so it does not get called again
          }
        })
      }, 100)
    })

    it('should be stopped', () => {
      expect(node.daemonPid()).to.not.be.ok
      expect(stopped).to.be.true
    })
  })
})

describe('setting up and initializing a local node', () => {
  const testpath1 = '/tmp/ipfstestpath1'

  describe('cleanup', () => {
    before((done) => {
      rimraf(testpath1, done)
    })

    it('should not have a directory', () => {
      expect(fs.existsSync('/tmp/ipfstestpath1')).to.be.false
    })
  })

  describe('setup', () => {
    let node
    before((done) => {
      ipfsd.local(testpath1, (err, res) => {
        if (err) throw err
        node = res
        done()
      })
    })

    it('should have returned a node', () => {
      expect(node).to.be.ok
    })

    it('should not be initialized', () => {
      expect(node.initialized).to.be.false
    })

    describe('initialize', function () {
      this.timeout(30000)

      before((done) => {
        node.init((err) => {
          if (err) throw err
          done()
        })
      })

      it('should have made a directory', () => {
        expect(fs.existsSync(testpath1)).to.be.true
      })

      it('should be initialized', () => {
        expect(node.initialized).to.be.true
      })

      it('should be initialized', () => {
        expect(node.initialized).to.be.true
      })
    })
  })
})

describe('change config values of a disposable node', function () {
  this.timeout(30000)

  let ipfsNode

  before((done) => {
    ipfsd.disposable((err, node) => {
      if (err) {
        throw err
      }
      ipfsNode = node
      done()
    })
  })

  it('should return a config value', (done) => {
    ipfsNode.getConfig('Bootstrap', (err, config) => {
      if (err) {
        throw err
      }
      expect(config).to.be.ok
      done()
    })
  })

  it('should set a config value', (done) => {
    ipfsNode.setConfig('Bootstrap', null, (err) => {
      if (err) {
        throw err
      }

      ipfsNode.getConfig('Bootstrap', (err, config) => {
        expect(err).to.not.exist
        expect(config).to.be.null
        done()
      })
    })
  })

  it('should replace the config with new file', (done) => {
    const configPath = path.join(__dirname, 'test-data', 'config.json')
    const expectedConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'))

    ipfsNode.replaceConf(configPath, (err) => {
      expect(err).to.not.exist

      ipfsNode.getConfig('Bootstrap', (err, config) => {
        expect(err).to.not.exist
        expect(config).to.be.deep.equal(expectedConfig.Bootstrap)
        done()
      })
    })
  })

  it('should fail to read a bad config file', (done) => {
    const configPath = path.join(__dirname, 'test-data', 'badconfig')

    ipfsNode.replaceConf(configPath, (err, result) => {
      expect(err).to.exist
      done()
    })
  })
})

describe('external ipfs binaray', () => {
  it('allows passing via $IPFS_EXEC', (done) => {
    process.env.IPFS_EXEC = '/some/path'
    ipfsd.local((err, node) => {
      if (err) throw err

      expect(node.exec).to.be.equal('/some/path/ipfs')

      process.env.IPFS_EXEC = ''
      done()
    })
  })
})

describe('version', () => {
  it('prints the version', (done) => {
    ipfsd.version((err, version) => {
      if (err) throw err

      expect(version).to.be.ok
      done()
    })
  })
})

describe('ipfs-api version', function () {
  this.timeout(30000)

  let ipfs

  before((done) => {
    ipfsd.disposable((err, node) => {
      if (err) throw err
      node.startDaemon((err, ignore) => {
        if (err) throw err
        ipfs = ipfsApi(node.apiAddr)
        done()
      })
    })
  })

  // NOTE: if you change ../src/, the hash will need to be changed
  it('uses the correct ipfs-api', (done) => {
    ipfs.add(path.join(__dirname, '../src'), { recursive: true }, (err, res) => {
      if (err) throw err

      const added = res[res.length - 1]
      expect(added).to.be.ok
      expect(added.Hash).to.be.equal('QmavtFfv9LMHaWBgXvbJgSfpSmtcA7WMNhzeF5J3KEUTKg')
      done()
    })
  })
})
<commit_msg>solving linting issues on tests<commit_after>/* eslint-env mocha */
'use strict'

const ipfsd = require('../src')
const config = require('../src/config')
const exec = require('../src/exec')
const expect = require('chai').expect
const ipfsApi = require('ipfs-api')
const fs = require('fs')
const series = require('run-series')
const rimraf = require('rimraf')
const path = require('path')

describe('disposable node with local api', function () {
  this.timeout(30000)
  let ipfs
  let node

  before((done) => {
    // Remove default exec dir at start, if any
    rimraf.sync(config.defaultExecPath)
    ipfsd.disposable((err, ipfsNode) => {
      if (err) throw err
      node = ipfsNode
      node.startDaemon((err, ignore) => {
        if (err) throw err
        ipfs = ipfsApi(node.apiAddr)
        done()
      })
    })
  })

  it('the binary should be checked', () => {
    expect(node.checked).to.be.true
  })

  it('should have started the daemon and returned an api', () => {
    expect(ipfs).to.be.ok
    expect(ipfs.id).to.be.ok
  })

  it('should have downloaded the binary to the default directory', () => {
    expect(fs.existsSync(config.defaultExecPath)).to.be.true
  })

  let store, retrieve

  before((done) => {
    const blorb = Buffer('blorb')
    series([
      (cb) => {
        ipfs.block.put(blorb, (err, res) => {
          if (err) return cb(err)
          store = res.Key
          cb()
        })
      },
      (cb) => ipfs.block.get(store, cb)
    ], (err, results) => {
      if (err) return done(err)
      const res = results[1]
      let buf = ''
      res
        .on('data', (data) => {
          buf += data
        })
        .on('end', () => {
          retrieve = buf
          done()
        })
    })
  })

  it('should be able to store objects', () => {
    expect(store).to.be.equal('QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rAQ')
  })

  it('should be able to retrieve objects', () => {
    expect(retrieve).to.be.equal('blorb')
  })
})

describe('disposable node without being initialized', function () {
  this.timeout(30000)
  let node

  it('binary should not be checked and node should be clean', (done) => {
    ipfsd.disposable({init: false}, (err, ipfsNode) => {
      node = ipfsNode
      expect(err).to.not.exist
      expect(node.checked).to.be.false
      expect(node.clean).to.be.true
      done()
    })
  })

  it('binary should be checked and node should not be clean', (done) => {
    node.init((err, ignore) => {
      expect(err).to.not.exist
      expect(node.checked).to.be.true
      expect(node.clean).to.be.false
      expect(fs.existsSync(config.defaultExecPath)).to.be.true
      done()
    })
  })
})

describe('disposableApi node', function () {
  this.timeout(30000)
  let ipfs
  before((done) => {
    ipfsd.disposableApi((err, api) => {
      if (err) throw err
      ipfs = api
      done()
    })
  })

  it('should have started the daemon and returned an api with host/port', () => {
    expect(ipfs).to.be.ok
    expect(ipfs.id).to.be.ok
    expect(ipfs.apiHost).to.be.ok
    expect(ipfs.apiPort).to.be.ok
  })

  let store, retrieve

  before((done) => {
    const blorb = Buffer('blorb')
    series([
      (cb) => {
        ipfs.block.put(blorb, (err, res) => {
          if (err) return cb(err)
          store = res.Key
          cb()
        })
      },
      (cb) => ipfs.block.get(store, cb)
    ], (err, results) => {
      if (err) return done(err)
      const res = results[1]
      let buf = ''
      res
        .on('data', (data) => {
          buf += data
        })
        .on('end', () => {
          retrieve = buf
          done()
        })
    })
  })

  it('should be able to store objects', () => {
    expect(store).to.be.equal('QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rAQ')
  })

  it('should be able to retrieve objects', () => {
    expect(retrieve).to.be.equal('blorb')
  })
})

describe('starting and stopping', function () {
  this.timeout(30000)
  let node

  describe('init', () => {
    before((done) => {
      ipfsd.disposable((err, res) => {
        if (err) throw err
        node = res
        done()
      })
    })

    it('should have returned a node', () => {
      expect(node).to.be.ok
    })

    it('daemon should not be running', () => {
      expect(node.daemonPid()).to.not.be.ok
    })
  })

  let pid

  describe('starting', () => {
    let ipfs
    before((done) => {
      node.startDaemon((err, res) => {
        if (err) throw err

        pid = node.daemonPid()
        ipfs = res

        // actually running?
        exec('kill', ['-0', pid], {}, done)
      })
    })

    it('should be running', () => {
      expect(ipfs.id).to.be.ok
    })
  })

  let stopped = false
  describe('stopping', () => {
    before((done) => {
      node.stopDaemon((err) => {
        if (err) throw err
        stopped = true
      })
      // make sure it's not still running
      const poll = setInterval(() => {
        exec('kill', ['-0', pid], {}, {
          error: () => {
            clearInterval(poll)
            done()
            done = () => {} // so it does not get called again
          }
        })
      }, 100)
    })

    it('should be stopped', () => {
      expect(node.daemonPid()).to.not.be.ok
      expect(stopped).to.be.true
    })
  })
})

describe('setting up and initializing a local node', () => {
  const testpath1 = '/tmp/ipfstestpath1'

  describe('cleanup', () => {
    before((done) => {
      rimraf(testpath1, done)
    })

    it('should not have a directory', () => {
      expect(fs.existsSync('/tmp/ipfstestpath1')).to.be.false
    })
  })

  describe('setup', () => {
    let node
    before((done) => {
      ipfsd.local(testpath1, (err, res) => {
        if (err) throw err
        node = res
        done()
      })
    })

    it('should have returned a node', () => {
      expect(node).to.be.ok
    })

    it('should not be initialized', () => {
      expect(node.initialized).to.be.false
    })

    describe('initialize', function () {
      this.timeout(30000)

      before((done) => node.init(done))

      it('should have made a directory', () => {
        expect(fs.existsSync(testpath1)).to.be.true
      })

      it('should be initialized', () => {
        expect(node.initialized).to.be.true
      })

      it('should be initialized', () => {
        expect(node.initialized).to.be.true
      })
    })
  })
})

describe('change config values of a disposable node', function () {
  this.timeout(30000)

  let ipfsNode

  before((done) => {
    ipfsd.disposable((err, node) => {
      if (err) {
        throw err
      }
      ipfsNode = node
      done()
    })
  })

  it('should return a config value', (done) => {
    ipfsNode.getConfig('Bootstrap', (err, config) => {
      if (err) {
        throw err
      }
      expect(config).to.be.ok
      done()
    })
  })

  it('should set a config value', (done) => {
    ipfsNode.setConfig('Bootstrap', null, (err) => {
      if (err) {
        throw err
      }

      ipfsNode.getConfig('Bootstrap', (err, config) => {
        expect(err).to.not.exist
        expect(config).to.be.null
        done()
      })
    })
  })

  it('should replace the config with new file', (done) => {
    const configPath = path.join(__dirname, 'test-data', 'config.json')
    const expectedConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'))

    ipfsNode.replaceConf(configPath, (err) => {
      expect(err).to.not.exist

      ipfsNode.getConfig('Bootstrap', (err, config) => {
        expect(err).to.not.exist
        expect(config).to.be.deep.equal(expectedConfig.Bootstrap)
        done()
      })
    })
  })

  it('should fail to read a bad config file', (done) => {
    const configPath = path.join(__dirname, 'test-data', 'badconfig')

    ipfsNode.replaceConf(configPath, (err, result) => {
      expect(err).to.exist
      done()
    })
  })
})

describe('external ipfs binaray', () => {
  it('allows passing via $IPFS_EXEC', (done) => {
    process.env.IPFS_EXEC = '/some/path'
    ipfsd.local((err, node) => {
      if (err) throw err

      expect(node.exec).to.be.equal('/some/path/ipfs')

      process.env.IPFS_EXEC = ''
      done()
    })
  })
})

describe('version', () => {
  it('prints the version', (done) => {
    ipfsd.version((err, version) => {
      if (err) throw err

      expect(version).to.be.ok
      done()
    })
  })
})

describe('ipfs-api version', function () {
  this.timeout(30000)

  let ipfs

  before((done) => {
    ipfsd.disposable((err, node) => {
      if (err) throw err
      node.startDaemon((err, ignore) => {
        if (err) throw err
        ipfs = ipfsApi(node.apiAddr)
        done()
      })
    })
  })

  // NOTE: if you change ../src/, the hash will need to be changed
  it('uses the correct ipfs-api', (done) => {
    ipfs.add(path.join(__dirname, '../src'), { recursive: true }, (err, res) => {
      if (err) throw err

      const added = res[res.length - 1]
      expect(added).to.be.ok
      expect(added.Hash).to.be.equal('QmavtFfv9LMHaWBgXvbJgSfpSmtcA7WMNhzeF5J3KEUTKg')
      done()
    })
  })
})
<|endoftext|>


<commit_before>import { createCollectionDelegate } from '../../lib/CollectionManager';
import Collection from 'marsdb';
import chai, { expect } from 'chai';
import sinon from 'sinon';
chai.use(require('chai-as-promised'));
chai.use(require('sinon-chai'));
chai.should();

const _defaultDelegate = Collection.defaultDelegate();
describe('CollectionManager', function () {
  let conn, db, manager;
  beforeEach(function () {
    conn = {
      on: sinon.spy(),
      sendResult: sinon.spy(),
      sendUpdated: sinon.spy(),
      methodManager: { apply: sinon.spy(() => ({
        result: () => Promise.resolve([2]),
        then: () => Promise.resolve([2]),
      }))},
    };
    const managerClass = createCollectionDelegate(conn);
    Collection.defaultDelegate(managerClass);
    db = new Collection('test');
    db._lazyInitCollection();
    manager = db.delegate;
  });

  afterEach(function () {
    Collection.defaultDelegate(_defaultDelegate);
  });

  describe('#constructor', function () {
    it('should add listeners to connection', function () {
      conn.on.should.have.callCount(4);
    });
  });

  describe('#update', function () {
    it('should accept no options', function () {
      return db.insert({a: 1, _id: '123'}, {quiet: true}).then(() => {
        return manager.update('123', {$set: {a: 2}}).then(() => {
          conn.methodManager.apply.should.have.callCount(1);
          return db.findOne('123')
        }).then((doc) => {
          doc.should.be.deep.equals({a: 2, _id: '123'});
        });
      });
    });

    it('should call super remove if quiet', function () {
      return db.insert({a: 1, _id: '123'}, {quiet: true}).then(() => {
        return manager.update('123', {$set: {a: 2}}, {quiet: true}).then(() => {
          conn.methodManager.apply.should.have.callCount(0);
          return db.findOne('123')
        }).then((doc) => {
          doc.should.be.deep.equals({a: 2, _id: '123'});
        });
      });
    });

    it('should revert update on update fail', function () {
      conn.methodManager = {
        apply: sinon.spy(() => Promise.reject()),
      };
      return db.insertAll([{_id: 1, a: 1}, {_id: 2, a: 2}], {quiet: true}).then(() => {
        db.update = sinon.spy();
        return manager.update({}, {$set: {a: 3}}, {multi: true});
      }).then(() => {
        return Promise.resolve().then(() => {
          db.update.should.have.callCount(2);
          db.update.getCall(0).args[0].should.be.deep.equal({_id: 1});
          db.update.getCall(0).args[1].should.be.deep.equal({a: 1});
          db.update.getCall(0).args[2].should.be.deep.equal({quiet: true, upsert: true});
          conn.methodManager.apply.should.have.callCount(1);
          conn.methodManager.apply.getCall(0).args[0].should.be.equals('/test/update');
          conn.methodManager.apply.getCall(0).args[1].should.be.deep.equals([{}, {$set: {a: 3}}, {multi: true}]);
        })
      });
    });

    it('should revert upsert update', function () {
      conn.methodManager = {
        apply: sinon.spy(() => Promise.reject()),
      };
      return db.insertAll([{_id: 1, a: 1}, {_id: 2, a: 2}], {quiet: true}).then(() => {
        db.remove = sinon.spy();
        return manager.update({_id: 3}, {$set: {a: 3}}, {multi: true, upsert: true});
      }).then(() => {
        return Promise.resolve().then(() => {
          db.remove.should.have.callCount(1);
          db.remove.getCall(0).args[1].should.be.deep.equal({quiet: true});
          conn.methodManager.apply.should.have.callCount(1);
          conn.methodManager.apply.getCall(0).args[0].should.be.equals('/test/update');
          conn.methodManager.apply.getCall(0).args[1].should.be.deep.equals(
            [{_id: 3}, {$set: {a: 3}}, {multi: true, upsert: true}]);
        })
      });
    });
  });

  describe('#remove', function () {
    it('should accept no options', function () {
      return db.insert({a: 1, _id: '123'}, {quiet: true}).then(() => {
        return manager.remove('123').then(() => {
          conn.methodManager.apply.should.have.callCount(1);
          return db.findOne('123')
        }).then((doc) => {
          expect(doc).to.be.undefined;
        });
      });
    });

    it('should call super remove if quiet', function () {
      return db.insert({a: 1, _id: '123'}, {quiet: true}).then(() => {
        return manager.remove('123', {quiet: true}).then(() => {
          conn.methodManager.apply.should.have.callCount(0);
          return db.findOne('123')
        }).then((doc) => {
          expect(doc).to.be.undefined;
        });
      });
    });

    it('should revert remove on insert fail', function () {
      conn.methodManager = {
        apply: sinon.spy(() => Promise.reject()),
      };
      return db.insertAll([{_id: 1, a: 1}, {_id: 2, a: 2}], {quiet: true}).then(() => {
        db.insertAll = sinon.spy();
        return manager.remove({}, {multi: true});
      }).then(() => {
        return Promise.resolve().then(() => {
          db.insertAll.should.have.callCount(1);
          db.insertAll.getCall(0).args[0].should.be.deep.equal([{_id: 1, a: 1}, {_id: 2, a: 2}]);
          db.insertAll.getCall(0).args[1].should.be.deep.equal({quiet: true});
          conn.methodManager.apply.should.have.callCount(1);
          conn.methodManager.apply.getCall(0).args[0].should.be.equals('/test/remove');
          conn.methodManager.apply.getCall(0).args[1].should.be.deep.equals([{}, {multi: true}]);
        })
      });
    });
  });

  describe('#insert', function () {
    it('should accept no options or random seed', function () {
      return manager.insert({a: 1, _id: '123'}).then(() => {
        conn.methodManager.apply.should.have.callCount(1);
        return db.findOne('123')
      }).then((doc) => {
        doc.should.be.deep.equal({a: 1, _id: '123'});
      });
    });

    it('should call super insert if quiet', function () {
      return manager.insert({a: 1, _id: '123'}, {quiet: true}).then((docId) => {
        conn.methodManager.apply.should.have.callCount(0);
        docId.should.be.equal('123');
        return db.findOne('123')
      }).then((doc) => {
        doc.should.be.deep.equal({a: 1, _id: '123'});
      });
    });

    it('should call insert method', function () {
      db.remove = sinon.spy();
      return manager.insert({_id: 1, a: 1}, {}, {seed: 1}).then(() => {
        db.remove.should.have.callCount(0);
        conn.methodManager.apply.should.have.callCount(1);
      });
    });

    it('should revert insert on insert fail', function () {
      db.remove = sinon.spy();
      conn.methodManager = {
        apply: sinon.spy(() => Promise.reject()),
      };
      return manager.insert({_id: 1, a: 1}, {}, {seed: 1}).then(() => {
        return Promise.resolve().then(() => {
          db.remove.should.have.callCount(1);
          db.remove.getCall(0).args[1].should.be.deep.equal({quiet: true});
          conn.methodManager.apply.should.have.callCount(1);
          conn.methodManager.apply.getCall(0).args[0].should.be.equals('/test/insert');
          conn.methodManager.apply.getCall(0).args[1].should.be.deep.equals([{_id: 1, a: 1}, {}]);
          conn.methodManager.apply.getCall(0).args[2].should.be.deep.equals(1);
        })
      });
    });
  });

  describe('#_handleRemoteAdded', function () {
    it('should insert new document', function () {
      return manager._handleRemoteAdded({id: 1, fields: {a: 1}}).then(() => {
        return db.findOne(1);
      }).then((doc) => {
        doc.should.be.deep.equals({_id: 1, a: 1});
      });
    });

    it('should replace document if it exists', function () {
      return db.insert({_id: 1, a: 1}).then(() => {
        return manager._handleRemoteAdded({id: 1, fields: {a: 2}});
      }).then(() => {
        return db.findOne(1);
      }).then((doc) => {
        doc.should.be.deep.equals({_id: 1, a: 2});
      });
    });

    it('should ignore id in fields', function () {
      return db.insert({_id: 1, a: 1}).then(() => {
        return manager._handleRemoteAdded({id: 1, fields: {_id: 123, a: 2}});
      }).then(() => {
        return Promise.all([db.findOne(1), db.findOne(123)]);
      }).then((docs) => {
        docs.should.have.length(2);
        docs[0].should.be.deep.equals({_id: 1, a: 2});
        expect(docs[1]).to.be.undefined;
      });
    });
  });

  describe('#_handleRemoteChanged', function () {
    it('should set only new fields', function () {
      return db.insert({_id: 1, a: 1, b: 2}).then(() => {
        return manager._handleRemoteChanged({id: 1, fields: {b: 3}})
      }).then(() => {
        return db.findOne(1);
      }).then((doc) => {
        doc.should.be.deep.equals({_id: 1, a: 1, b: 3});
      });
    });

    it('should clear fields', function () {
      return db.insert({_id: 1, a: 1, b: 2}).then(() => {
        return manager._handleRemoteChanged({id: 1, cleared: ['b', 'c']})
      }).then(() => {
        return db.findOne(1);
      }).then((doc) => {
        doc.should.be.deep.equals({_id: 1, a: 1});
      });
    });

    it('should ignore id in fields', function () {
      return db.insert({_id: 1, a: 1, b: 2}).then(() => {
        return manager._handleRemoteChanged({id: 1, fields: {b: 3, _id: 3}})
      }).then(() => {
        return Promise.all([db.findOne(1), db.findOne(3)]);
      }).then((docs) => {
        docs.should.have.length(2);
        docs[0].should.be.deep.equals({_id: 1, a: 1, b: 3});
        expect(docs[1]).to.be.undefined;
      });
    });

    it('should do nothing if fields and clear not presented', function () {
      return db.insert({_id: 1, a: 1, b: 2}).then(() => {
        return manager._handleRemoteChanged({id: 1})
      }).then(() => {
        return db.findOne(1);
      }).then((doc) => {
        doc.should.be.deep.equals({_id: 1, a: 1, b: 2});
      });
    });

    it('should do nothing if object with given id not exists', function () {
      return db.insert({_id: 1, a: 1, b: 2}).then(() => {
        return manager._handleRemoteChanged({id: 2, fields: {b: 2}, cleared: ['b', 'c']})
      }).then(() => {
        return Promise.all([db.findOne(1), db.findOne(2)]);
      }).then((docs) => {
        docs.should.have.length(2);
        docs[0].should.be.deep.equals({_id: 1, a: 1, b: 2});
        expect(docs[1]).to.be.undefined;
      });
    });
  });

  describe('#_handleRemoteRemoved', function () {
    it('should remove a document', function () {
      return db.insert({_id: 1, a: 1, b: 2}).then(() => {
        return manager._handleRemoteRemoved({id: 1})
      }).then(() => {
        return db.findOne(1);
      }).then((doc) => {
        expect(doc).to.be.undefined;
      });
    });
  });

  describe('#_handleConnected', function () {
    it('should sync client side documents with server-side', function () {
      return db.insertAll([{_id: 1, a: 1},{_id: 2, a: 1}], {quiet: true}).then(() => {
        return manager._handleConnected();
      }).then(() => {
        return db.find();
      }).then((docs) => {
        conn.methodManager.apply.should.have.callCount(1);
        conn.methodManager.apply.getCall(0).args.should.be.deep.equals(['/test/sync', [[1,2]]]);
        docs.should.have.length(1);
        docs[0].should.be.deep.equals({_id: 1, a: 1});
      });
    });
  });
});
<commit_msg>added tests for "whenReady" option of collection<commit_after>import { createCollectionDelegate } from '../../lib/CollectionManager';
import Collection from 'marsdb';
import chai, { expect } from 'chai';
import sinon from 'sinon';
chai.use(require('chai-as-promised'));
chai.use(require('sinon-chai'));
chai.should();

const _defaultDelegate = Collection.defaultDelegate();
describe('CollectionManager', function () {
  let conn, db, manager;
  beforeEach(function () {
    conn = {
      on: sinon.spy(),
      sendResult: sinon.spy(),
      sendUpdated: sinon.spy(),
      methodManager: { apply: sinon.spy(() => ({
        result: () => Promise.resolve([2]),
        then: () => Promise.resolve([2]),
      }))},
    };
    const managerClass = createCollectionDelegate(conn);
    Collection.defaultDelegate(managerClass);
    db = new Collection('test');
    db._lazyInitCollection();
    manager = db.delegate;
  });

  afterEach(function () {
    Collection.defaultDelegate(_defaultDelegate);
  });

  describe('#constructor', function () {
    it('should add listeners to connection', function () {
      conn.on.should.have.callCount(4);
    });
  });

  describe('#update', function () {
    it('should accept no options', function () {
      return db.insert({a: 1, _id: '123'}, {quiet: true}).then(() => {
        return manager.update('123', {$set: {a: 2}}).then(() => {
          conn.methodManager.apply.should.have.callCount(1);
          return db.findOne('123')
        }).then((doc) => {
          doc.should.be.deep.equals({a: 2, _id: '123'});
        });
      });
    });

    it('should call super remove if quiet', function () {
      return db.insert({a: 1, _id: '123'}, {quiet: true}).then(() => {
        return manager.update('123', {$set: {a: 2}}, {quiet: true}).then(() => {
          conn.methodManager.apply.should.have.callCount(0);
          return db.findOne('123')
        }).then((doc) => {
          doc.should.be.deep.equals({a: 2, _id: '123'});
        });
      });
    });

    it('should revert update on update fail', function () {
      conn.methodManager = {
        apply: sinon.spy(() => Promise.reject()),
      };
      return db.insertAll([{_id: 1, a: 1}, {_id: 2, a: 2}], {quiet: true}).then(() => {
        db.update = sinon.spy();
        return manager.update({}, {$set: {a: 3}}, {multi: true});
      }).then(() => {
        return Promise.resolve().then(() => {
          db.update.should.have.callCount(2);
          db.update.getCall(0).args[0].should.be.deep.equal({_id: 1});
          db.update.getCall(0).args[1].should.be.deep.equal({a: 1});
          db.update.getCall(0).args[2].should.be.deep.equal({quiet: true, upsert: true});
          conn.methodManager.apply.should.have.callCount(1);
          conn.methodManager.apply.getCall(0).args[0].should.be.equals('/test/update');
          conn.methodManager.apply.getCall(0).args[1].should.be.deep.equals([{}, {$set: {a: 3}}, {multi: true}]);
        })
      });
    });

    it('should revert upsert update', function () {
      conn.methodManager = {
        apply: sinon.spy(() => Promise.reject()),
      };
      return db.insertAll([{_id: 1, a: 1}, {_id: 2, a: 2}], {quiet: true}).then(() => {
        db.remove = sinon.spy();
        return manager.update({_id: 3}, {$set: {a: 3}}, {multi: true, upsert: true});
      }).then(() => {
        return Promise.resolve().then(() => {
          db.remove.should.have.callCount(1);
          db.remove.getCall(0).args[1].should.be.deep.equal({quiet: true});
          conn.methodManager.apply.should.have.callCount(1);
          conn.methodManager.apply.getCall(0).args[0].should.be.equals('/test/update');
          conn.methodManager.apply.getCall(0).args[1].should.be.deep.equals(
            [{_id: 3}, {$set: {a: 3}}, {multi: true, upsert: true}]);
        })
      });
    });

    it('should wait until server result when waitResult options passed', function () {
      return db.insert({a: 1, _id: '123'}, {quiet: true}).then(() => {
        const cb = sinon.spy();
        conn.methodManager = { apply: sinon.spy(() => ({
          then: () => {
            return Promise.all([
              Promise.resolve({
                modified: 1,
                updated: [{a: 3, _id: '123'}],
                original: [{a: 1, _id: '123'}],
              }),
              db.update('123', {$set: {a: 3}}, {quiet: true})
            ])
          },
        }))}
        return manager.update('123', {$set: {a: 2}}, {waitResult: true})
          .then(() => db.findOne('123'))
          .then((res) => {
            res.should.be.deep.equal({a: 3, _id: '123'});
          });
      });
    });
  });

  describe('#remove', function () {
    it('should accept no options', function () {
      return db.insert({a: 1, _id: '123'}, {quiet: true}).then(() => {
        return manager.remove('123').then(() => {
          conn.methodManager.apply.should.have.callCount(1);
          return db.findOne('123')
        }).then((doc) => {
          expect(doc).to.be.undefined;
        });
      });
    });

    it('should call super remove if quiet', function () {
      return db.insert({a: 1, _id: '123'}, {quiet: true}).then(() => {
        return manager.remove('123', {quiet: true}).then(() => {
          conn.methodManager.apply.should.have.callCount(0);
          return db.findOne('123')
        }).then((doc) => {
          expect(doc).to.be.undefined;
        });
      });
    });

    it('should revert remove on insert fail', function () {
      conn.methodManager = {
        apply: sinon.spy(() => Promise.reject()),
      };
      return db.insertAll([{_id: 1, a: 1}, {_id: 2, a: 2}], {quiet: true}).then(() => {
        db.insertAll = sinon.spy();
        return manager.remove({}, {multi: true});
      }).then(() => {
        return Promise.resolve().then(() => {
          db.insertAll.should.have.callCount(1);
          db.insertAll.getCall(0).args[0].should.be.deep.equal([{_id: 1, a: 1}, {_id: 2, a: 2}]);
          db.insertAll.getCall(0).args[1].should.be.deep.equal({quiet: true});
          conn.methodManager.apply.should.have.callCount(1);
          conn.methodManager.apply.getCall(0).args[0].should.be.equals('/test/remove');
          conn.methodManager.apply.getCall(0).args[1].should.be.deep.equals([{}, {multi: true}]);
        })
      });
    });

    it('should wait until server result when waitResult options passed', function () {
      return db.insertAll([
        {a: 1, _id: '123'},
        {a: 2, _id: '321'}
      ], {quiet: true}).then(() => {
        const cb = sinon.spy();
        conn.methodManager = { apply: sinon.spy(() => ({
          then: () => {
            return Promise.all([
              Promise.resolve([{a: 1, _id: '123'}, {a: 2, _id: '321'}]),
              db.remove({}, {quiet: true, multi: true})
            ])
          },
        }))}
        return manager.remove('123', {waitResult: true})
          .then(() => db.find())
          .then((res) => {
            res.should.have.length(0);
          });
      });
    });
  });

  describe('#insert', function () {
    it('should accept no options or random seed', function () {
      return manager.insert({a: 1, _id: '123'}).then(() => {
        conn.methodManager.apply.should.have.callCount(1);
        return db.findOne('123')
      }).then((doc) => {
        doc.should.be.deep.equal({a: 1, _id: '123'});
      });
    });

    it('should call super insert if quiet', function () {
      return manager.insert({a: 1, _id: '123'}, {quiet: true}).then((docId) => {
        conn.methodManager.apply.should.have.callCount(0);
        docId.should.be.equal('123');
        return db.findOne('123')
      }).then((doc) => {
        doc.should.be.deep.equal({a: 1, _id: '123'});
      });
    });

    it('should call insert method', function () {
      db.remove = sinon.spy();
      return manager.insert({_id: 1, a: 1}, {}, {seed: 1}).then(() => {
        db.remove.should.have.callCount(0);
        conn.methodManager.apply.should.have.callCount(1);
      });
    });

    it('should revert insert on insert fail', function () {
      db.remove = sinon.spy();
      conn.methodManager = {
        apply: sinon.spy(() => Promise.reject()),
      };
      return manager.insert({_id: 1, a: 1}, {}, {seed: 1}).then(() => {
        return Promise.resolve().then(() => {
          db.remove.should.have.callCount(1);
          db.remove.getCall(0).args[1].should.be.deep.equal({quiet: true});
          conn.methodManager.apply.should.have.callCount(1);
          conn.methodManager.apply.getCall(0).args[0].should.be.equals('/test/insert');
          conn.methodManager.apply.getCall(0).args[1].should.be.deep.equals([{_id: 1, a: 1}, {}]);
          conn.methodManager.apply.getCall(0).args[2].should.be.deep.equals(1);
        })
      });
    });

    it('should wait until server result when waitResult options passed', function () {
      const cb = sinon.spy();
      conn.methodManager = { apply: sinon.spy(() => ({
        then: () => {
          return Promise.all([
            Promise.resolve('2'),
            db.insert({_id: '2', a: 1}, {quiet: true})
          ])
        },
      }))}
      return manager.insert({_id: '1', a: 2}, {waitResult: true})
        .then(() => db.find())
        .then((res) => {
          res.should.have.length(1);
          res[0].should.be.deep.equal({_id: '2', a: 1});
        });
    });
  });

  describe('#_handleRemoteAdded', function () {
    it('should insert new document', function () {
      return manager._handleRemoteAdded({id: 1, fields: {a: 1}}).then(() => {
        return db.findOne(1);
      }).then((doc) => {
        doc.should.be.deep.equals({_id: 1, a: 1});
      });
    });

    it('should replace document if it exists', function () {
      return db.insert({_id: 1, a: 1}).then(() => {
        return manager._handleRemoteAdded({id: 1, fields: {a: 2}});
      }).then(() => {
        return db.findOne(1);
      }).then((doc) => {
        doc.should.be.deep.equals({_id: 1, a: 2});
      });
    });

    it('should ignore id in fields', function () {
      return db.insert({_id: 1, a: 1}).then(() => {
        return manager._handleRemoteAdded({id: 1, fields: {_id: 123, a: 2}});
      }).then(() => {
        return Promise.all([db.findOne(1), db.findOne(123)]);
      }).then((docs) => {
        docs.should.have.length(2);
        docs[0].should.be.deep.equals({_id: 1, a: 2});
        expect(docs[1]).to.be.undefined;
      });
    });
  });

  describe('#_handleRemoteChanged', function () {
    it('should set only new fields', function () {
      return db.insert({_id: 1, a: 1, b: 2}).then(() => {
        return manager._handleRemoteChanged({id: 1, fields: {b: 3}})
      }).then(() => {
        return db.findOne(1);
      }).then((doc) => {
        doc.should.be.deep.equals({_id: 1, a: 1, b: 3});
      });
    });

    it('should clear fields', function () {
      return db.insert({_id: 1, a: 1, b: 2}).then(() => {
        return manager._handleRemoteChanged({id: 1, cleared: ['b', 'c']})
      }).then(() => {
        return db.findOne(1);
      }).then((doc) => {
        doc.should.be.deep.equals({_id: 1, a: 1});
      });
    });

    it('should ignore id in fields', function () {
      return db.insert({_id: 1, a: 1, b: 2}).then(() => {
        return manager._handleRemoteChanged({id: 1, fields: {b: 3, _id: 3}})
      }).then(() => {
        return Promise.all([db.findOne(1), db.findOne(3)]);
      }).then((docs) => {
        docs.should.have.length(2);
        docs[0].should.be.deep.equals({_id: 1, a: 1, b: 3});
        expect(docs[1]).to.be.undefined;
      });
    });

    it('should do nothing if fields and clear not presented', function () {
      return db.insert({_id: 1, a: 1, b: 2}).then(() => {
        return manager._handleRemoteChanged({id: 1})
      }).then(() => {
        return db.findOne(1);
      }).then((doc) => {
        doc.should.be.deep.equals({_id: 1, a: 1, b: 2});
      });
    });

    it('should do nothing if object with given id not exists', function () {
      return db.insert({_id: 1, a: 1, b: 2}).then(() => {
        return manager._handleRemoteChanged({id: 2, fields: {b: 2}, cleared: ['b', 'c']})
      }).then(() => {
        return Promise.all([db.findOne(1), db.findOne(2)]);
      }).then((docs) => {
        docs.should.have.length(2);
        docs[0].should.be.deep.equals({_id: 1, a: 1, b: 2});
        expect(docs[1]).to.be.undefined;
      });
    });
  });

  describe('#_handleRemoteRemoved', function () {
    it('should remove a document', function () {
      return db.insert({_id: 1, a: 1, b: 2}).then(() => {
        return manager._handleRemoteRemoved({id: 1})
      }).then(() => {
        return db.findOne(1);
      }).then((doc) => {
        expect(doc).to.be.undefined;
      });
    });
  });

  describe('#_handleConnected', function () {
    it('should sync client side documents with server-side', function () {
      return db.insertAll([{_id: 1, a: 1},{_id: 2, a: 1}], {quiet: true}).then(() => {
        return manager._handleConnected();
      }).then(() => {
        return db.find();
      }).then((docs) => {
        conn.methodManager.apply.should.have.callCount(1);
        conn.methodManager.apply.getCall(0).args.should.be.deep.equals(['/test/sync', [[1,2]]]);
        docs.should.have.length(1);
        docs[0].should.be.deep.equals({_id: 1, a: 1});
      });
    });
  });
});
<|endoftext|>


<commit_before>const postcss = require('postcss');
const plugin = require('../index');
const pkg = require('../package.json');
const fs = require('fs');

/**
 * Runs the plugins process function. Tests whether the given input is equal
 * to the expected output with the given options.
 *
 * @param {string} input Input fixture file name.
 * @param {object} opts Options to be used by the plugin.
 * @return {function}
 */
function run(input, opts) {
    const raw = fs.readFileSync(`./test/fixtures/${input}.css`, 'utf8');
    const expected = fs.readFileSync(`./test/fixtures/${input}.expected.css`, 'utf8');

    return postcss([plugin(opts)]).process(raw)
        .then(result => {
            expect(result.css).toEqual(expected);
            expect(result.warnings().length).toBe(0);
        });
}

it('Should replace strings in comments and styles.', () => {
    return run('basic', { data: pkg });
});

it('Should not replace anything in styles when “commentsOnly” option is set to TRUE.', () => {
    return run('commentsOnly', { data: pkg, commentsOnly: true });
});

it('Should not replace anything without data', () => {
    return run('noChanges');
});

it('Should not change unknown variables', () => {
    return run('noChanges', { data: pkg });
});

it('Should work with deep data objects', () => {
    return run('deep', { data: { level1: { level2: 'test' } } });
});

it('Should work with a custom RegEx', () => {
    return run('otherRegEx', { data: pkg, pattern: /%\s?([^\s]+?)\s?%/gi });
});

it('Should work with a custom RegEx object', () => {
    return run('basic', { data: pkg, pattern: new RegExp(/{{\s?([^\s]+?)\s?}}/, 'gi') });
});

it('Should work with a custom RegEx string', () => {
    return run('basic', { data: pkg, pattern: '{{\\s?([^\\s]+?)\\s?}}' });
});

it('Should work with another custom RegEx string', () => {
    return run('otherRegEx', { data: pkg, pattern: '%\\s?([^\\s]+?)\\s?%' });
});
<commit_msg>Fix wrong fixture filename in test<commit_after>const postcss = require('postcss');
const plugin = require('../index');
const pkg = require('../package.json');
const fs = require('fs');

/**
 * Runs the plugins process function. Tests whether the given input is equal
 * to the expected output with the given options.
 *
 * @param {string} input Input fixture file name.
 * @param {object} opts Options to be used by the plugin.
 * @return {function}
 */
function run(input, opts) {
    const raw = fs.readFileSync(`./test/fixtures/${input}.css`, 'utf8');
    const expected = fs.readFileSync(`./test/fixtures/${input}.expected.css`, 'utf8');

    return postcss([plugin(opts)]).process(raw)
        .then(result => {
            expect(result.css).toEqual(expected);
            expect(result.warnings().length).toBe(0);
        });
}

it('Should replace strings in comments and styles.', () => {
    return run('basic', { data: pkg });
});

it('Should not replace anything in styles when “commentsOnly” option is set to TRUE.', () => {
    return run('commentsOnly', { data: pkg, commentsOnly: true });
});

it('Should not replace anything without data', () => {
    return run('noChanges');
});

it('Should not change unknown variables', () => {
    return run('noChanges', { data: pkg });
});

it('Should work with deep data objects', () => {
    return run('deep', { data: { level1: { level2: 'test' } } });
});

it('Should work with a custom RegEx', () => {
    return run('otherRegex', { data: pkg, pattern: /%\s?([^\s]+?)\s?%/gi });
});

it('Should work with a custom RegEx object', () => {
    return run('basic', { data: pkg, pattern: new RegExp(/{{\s?([^\s]+?)\s?}}/, 'gi') });
});

it('Should work with a custom RegEx string', () => {
    return run('basic', { data: pkg, pattern: '{{\\s?([^\\s]+?)\\s?}}' });
});

it('Should work with another custom RegEx string', () => {
    return run('otherRegex', { data: pkg, pattern: '%\\s?([^\\s]+?)\\s?%' });
});
<|endoftext|>


<commit_before>var mj = require('../'),
  assert = require('assert');

describe('mj', function() {
  it('should be requireable', function() {
    assert(mj);
  });
});
<commit_msg>added some tests for mj help<commit_after>var mj = require('../'),
    fs = require('fs'),
    assert = require('assert'),
    exec = require('child_process').exec,
    debug = require('debug')('mj:test');

var BIN_MJ = __dirname + '/../bin/mj.js';
var DOCOPT_DIR = __dirname + '/../docopts/';

function mjWithArgs(args, callback) {
  // e.g. mjWithArgs("create --type cli")
  exec('node ' + BIN_MJ + ' ' + args, callback);
}

function loadHelpText(cmd) {
  return fs.readFileSync(DOCOPT_DIR + cmd + '.docopt', 'utf-8');
}

function containsLineWith(text, str) {
  if (!(str instanceof Array)) {
    str = [str];
  }
  var lines = text.split('\n');
  return str.every(function (s) {
    return lines.some(function (l) {
      return l.indexOf(s) !== -1;
    });
  });
}

function strip(str) {
  // strips leading and trailing whitespace
  return str.replace(/^\s+|\s+$/g, '');
}

describe('mj', function() {
  it('should be requireable', function() {
    assert(mj);
  });

  describe('--help', function (done) {
    it('should contain help for usage, options, commands, pointer to `mj help`', function (done) {
      mjWithArgs('help', function (err, stdout) {
        if (err) throw err;
        // must contain the following lines
        assert.ok(containsLineWith(stdout, [
          'Usage:',
          'Options:',
          'Available commands',
          'mj help <command>'
        ]));
        done();
      });
    });
  });

  describe('help', function (done) {
    it('should return the main --help text if no arguments given', function (done) {
      mjWithArgs('help', function (err, stdout) {
        if (err) throw err;
        assert.equal(strip(loadHelpText('main')), strip(stdout));
        done();
      });
    });
  });
});
<|endoftext|>


<commit_before>/* jshint evil: true, expr: true */
/* global gardr:false */
var extend = require('util-extend');
var expect = require('expect.js');
var proxyquire = require('proxyquireify')(require);
var eventlistener = require('eventlistener');

var bannerAppender = proxyquire('../lib/log/appender/banner.js', {
    '../../timer.js': function(fn) {
        return fn();
    }
});

var triggerOnLoad;
var comClientSpy;
var gardrExt = proxyquire('../lib/index.js', {
    './log/getAppender.js': proxyquire('../lib/log/getAppender.js', {
        './appender/banner.js': bannerAppender
    }),
    './comClient.js': function com(a, b, c){
        return comClientSpy(a, b, c);
    },
    './timer.js': function(fn) {
        return fn();
    },
    eventlistener: {
        add: function fake(ctx, name, fn){
            if (name === 'load') {
                triggerOnLoad = fn;
            } else {
                return eventlistener.add(ctx, name, fn);
            }
        }
    }
});

function getDefaultParams() {
    return {
        logto: 'console',
        id: 'pos-id',
        name: 'posname',
        minSize: 100,
        timeout: 200,
        url: 'http://gardr.github.io/foobar.js?'+(+new Date()),
        height: 225,
        origin: 'http://github.com'
    };
}

var extOpts = {
    allowedDomains: ['gardr.github.io', 'foobar.com']
};

function createIframe() {
    var iframe = document.createElement('iframe');
    iframe.src          = 'about:blank';
    iframe.style.width  = '100px';
    iframe.style.height = '100px';
    iframe.style.overflow = 'hidden';
    document.body.appendChild(iframe);
    return iframe;
}

describe('Garðr ext - gardrExt', function () {
    var orgWrite = document.write;

    beforeEach(function () {

        this.iframe = createIframe();

        this.document = this.iframe.contentDocument;
        this.window = this.iframe.contentWindow;
        this.document.open();

        // head
        this.document.write(['<scr', 'ipt>', 'window.gardr = window.parent.gardr;', '</scr', 'ipt>'].join(''));
        // body
        this.document.write('
');

        // overwrrite iframe write
        var _write = this.document.write;
        this.document.write = sinon.spy(function (str){
            _write.call(this.document, str);
        }.bind(this));

        // overwrite parent write and pass on to iframe write
        document.write = sinon.spy(function (str) {
            this.document.write.call(this.document, str);
        }.bind(this));

        function paramsStr (data) {
            return JSON.stringify(extend(extend({}, getDefaultParams()), data));
        }

        this.setUrlFragment = function (data) {
            this.document.location.hash = '#' + encodeURIComponent(paramsStr(data));
        }.bind(this);

        this.setName = function (data) {
            this.window.name = paramsStr(data);
        };

        this.com = undefined;
        this.comEvents = {};
        comClientSpy = this.comClientSpy = sinon.spy(function () {
            this.com = {
                rendered: sinon.spy(),
                on: function(name, cb) {
                    this.comEvents[name] = cb;
                }.bind(this)
            };
            return this.com;
        }.bind(this));

        gardrExt._mock(this.document, this.window);

        this.setUrlFragment();
    });

    afterEach(function () {
        this.document.close();

        document.body.removeChild(this.iframe);

        try {
            delete window.gardr;
        } catch(e){
            window.gardr = null;
        }
        document.write = orgWrite;
    });

    it('should throw an error if url is not on a valid domain', function () {
        expect(function(){
            gardrExt({allowedDomains: ['example.com']});
        }).to.throwError(/domain/);
    });

    it('should throw an error if url is a data-uri', function () {
        this.setUrlFragment({
            url: 'data:text/javascript;plain,void(0);'
        });
        expect(function(){
            gardrExt();
        }).to.throwError(/protocol/);
    });

    it('should not throw an error if a relative url', function () {
        this.setUrlFragment({
            url: '/foo/bar.js'
        });

        expect(function(){
            gardrExt().inject();
        }).not.to.throwError();
    });

    it('should throw if one of the validDomains contains something else than just the hostname', function () {
        ['http://foobar.com', '//foobar.com', 'https://foobar.com', 'foobar.com/'].forEach(function (domain) {
            expect(function(){
                gardrExt({allowedDomains: [domain]}).inject();
            }).to.throwError(/Invalid domain/);
        });
    });

    it('should not throw an error if url is on a valid domain', function () {
        this.setUrlFragment({
            url: 'http://foobar.com/foo/bar'
        });
        expect(function(){
            gardrExt(extOpts).inject();
        }).not.to.throwError();
    });

    it('should define ‘gardr’ in global scope', function () {
        gardrExt(extOpts);

        expect(window.gardr).to.be.ok();
    });

    it('should read parameters from location.hash', function () {
        this.timeout(5000); // ie8
        this.setUrlFragment({url: 'http://gardr.github.io/ad|123'});
        gardrExt(extOpts);

        expect(gardr.params).to.be.ok();
        expect(gardr.id).to.equal('pos-id');
        expect(gardr.params.origin).to.equal('http://github.com');
        expect(gardr.params.url).to.equal('http://gardr.github.io/ad|123');
        expect(gardr.params.timeout).to.equal(200);
    });

    it('should read parameters from window.name', function () {
        this.document.location.hash = '';
        this.setName({url: 'http://gardr.github.io/ad|123'});
        gardrExt(extOpts);

        expect(gardr.params).to.be.ok();
        expect(gardr.id).to.equal('pos-id');
        expect(gardr.params.origin).to.equal('http://github.com');
        expect(gardr.params.url).to.equal('http://gardr.github.io/ad|123');
        expect(gardr.params.timeout).to.equal(200);
    });

    it('should log to div by default', function () {

        this.setUrlFragment({
            loglevel: 5, logto: 'banner'
        });

        gardrExt(extOpts).inject();

        var logDiv = document.getElementById('logoutput');

        expect(logDiv).to.not.be(null);
        expect(logDiv.children.length).to.equal(1);

        gardr.log.debug('test-with-log-level-4');

        expect(logDiv.children.length).to.equal(2);

        bannerAppender.reset();

    });

    it('should document.write out a gardr container to the document', function () {
        gardrExt(extOpts).inject();
        var assertion = this.document.write.calledWithMatch(/^<scr.pt\s*id=".*"\s*src=".*"\s*><\/scr.pt>$/);
        expect(assertion).to.be.ok();
    });

    it('should assign the gardr container to gardr.container', function () {
        gardrExt(extOpts).inject();
        expect(gardr.container).to.be.ok();
        expect(gardr.container.id).to.equal('gardr');
    }),

    it('should set overflow:hidden on the gardr container', function () {
        gardrExt(extOpts).inject();
        expect(gardr.container.style.overflow).to.equal('hidden');
    });

    it('should document.write a script tag with src equal to the input url', function() {
        var scriptUrl = 'http://gardr.github.io/script.js?q=1';
        this.setUrlFragment({url: scriptUrl});
        gardrExt(extOpts).inject();

        var assertion = this.document.write.calledWithMatch(function (value) {
            return value.indexOf('


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

var events = require('./events');
var util = require('util');
var test2 = require('./test-util').test2;
var dsl = require('./ringpop-assert');
var prepareCluster = require('./test-util').prepareCluster;
var prepareWithStatus = require('./test-util').prepareWithStatus;
var getClusterSizes = require('./it-tests').getClusterSizes;

function joinFakeCluster(n) {
    test2('join cluster of 1+' + n + ' nodes', [n], 20000,
        prepareCluster(function(t, tc, n) { return [
            dsl.assertStats(t, tc, n+1, 0, 0),
            dsl.expectOnlyPings(t, tc),
        ];})
    );
}

var clusterSizes = getClusterSizes();
clusterSizes.forEach(function(n) {
    joinFakeCluster(n);
});

test2('join ringpop with fake node', getClusterSizes(), 20000,
    prepareCluster(function(t, tc, n) { return [
        dsl.joinNewNode(t, tc, n),
        dsl.waitForJoinResponse(t, tc, n),
        dsl.wait(100),
        // node is supposed to disseminate itself
        // remove this node to keep in sync with membership of real node
        dsl.removeFakeNode(t, tc),
        dsl.assertStats(t, tc, n+1, 0, 0),
        dsl.expectOnlyPings(t, tc),
    ];})
);

function joinFrom(n, status, incNoDelta, deltaAlive, nSuspect, nFaulty) {
    test2('join from ' + status + ' with incNoDelta ' + incNoDelta, n, 20000,
        prepareWithStatus(0, status, function(t, tc, n) {
            return [
                dsl.disableNode(t, tc, 0),
                dsl.enableNode(t, tc, 0, tc.fakeNodes[0].incarnationNumber+incNoDelta),
                dsl.sendJoin(t, tc, 0),
                dsl.waitForJoinResponse(t, tc, 0),
                // We expect the node to not accept the join but not change it's own membership
                // A node is expected to disseminate its own existence
                function(list, cb) {
                    tc.fakeNodes[0].incarnationNumber -= incNoDelta;
                    cb(list);
                },
                dsl.assertStats(t, tc, n + deltaAlive, nSuspect, nFaulty, {0: {status: status}}),
            ];
        })
    );
}

joinFrom(getClusterSizes(), 'alive', -1, 1, 0, 0);
joinFrom(getClusterSizes(), 'alive',  0, 1, 0, 0);
joinFrom(getClusterSizes(), 'alive',  1, 1, 0, 0);

joinFrom(clusterSizes, 'suspect', -1, 0, 1, 0);
joinFrom(clusterSizes, 'suspect',  0, 0, 1, 0);
joinFrom(clusterSizes, 'suspect',  1, 0, 1, 0);

joinFrom(clusterSizes, 'faulty', -1, 0, 0, 1);
joinFrom(clusterSizes, 'faulty',  0, 0, 0, 1);
joinFrom(clusterSizes, 'faulty',  1, 0, 0, 1);

<commit_msg>Don't disseminate join list tests<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

var _ = require('lodash');
var events = require('./events');
var util = require('util');
var test2 = require('./test-util').test2;
var dsl = require('./ringpop-assert');
var prepareCluster = require('./test-util').prepareCluster;
var prepareWithStatus = require('./test-util').prepareWithStatus;
var getClusterSizes = require('./it-tests').getClusterSizes;

function joinFakeCluster(n) {
    test2('join cluster of 1+' + n + ' nodes', [n], 20000,
        prepareCluster(function(t, tc, n) { return [
            dsl.assertStats(t, tc, n+1, 0, 0),

            // Wait for a ping from the SUT and validate that it has the piggybacked information in there
            dsl.validateEventBody(t, tc, {
                type: events.Types.Ping,
                direction: 'request'
            }, "Check if node doesn't disseminate join list", function (ping) {
                return ping.body && ping.body.changes &&
                    ping.body.changes.length === 1 &&
                    ping.body.changes[0].status === 'alive'
            }),

            dsl.expectOnlyPings(t, tc),
        ];})
    );
}

var clusterSizes = getClusterSizes();
clusterSizes.forEach(function(n) {
    joinFakeCluster(n);
});

test2('join ringpop with fake node', getClusterSizes(), 20000,
    prepareCluster(function(t, tc, n) { return [
        dsl.joinNewNode(t, tc, n),
        dsl.waitForJoinResponse(t, tc, n),
        dsl.wait(100),
        // node is supposed to disseminate itself
        // remove this node to keep in sync with membership of real node
        dsl.removeFakeNode(t, tc),
        dsl.assertStats(t, tc, n+1, 0, 0),
        dsl.expectOnlyPings(t, tc),
    ];})
);

function joinFrom(n, status, incNoDelta, deltaAlive, nSuspect, nFaulty) {
    test2('join from ' + status + ' with incNoDelta ' + incNoDelta, n, 20000,
        prepareWithStatus(0, status, function(t, tc, n) {
            return [
                dsl.disableNode(t, tc, 0),
                dsl.enableNode(t, tc, 0, tc.fakeNodes[0].incarnationNumber+incNoDelta),
                dsl.sendJoin(t, tc, 0),
                dsl.waitForJoinResponse(t, tc, 0),
                // We expect the node to not accept the join but not change it's own membership
                // A node is expected to disseminate its own existence
                function(list, cb) {
                    tc.fakeNodes[0].incarnationNumber -= incNoDelta;
                    cb(list);
                },
                dsl.assertStats(t, tc, n + deltaAlive, nSuspect, nFaulty, {0: {status: status}}),
            ];
        })
    );
}

joinFrom(getClusterSizes(), 'alive', -1, 1, 0, 0);
joinFrom(getClusterSizes(), 'alive',  0, 1, 0, 0);
joinFrom(getClusterSizes(), 'alive',  1, 1, 0, 0);

joinFrom(clusterSizes, 'suspect', -1, 0, 1, 0);
joinFrom(clusterSizes, 'suspect',  0, 0, 1, 0);
joinFrom(clusterSizes, 'suspect',  1, 0, 1, 0);

joinFrom(clusterSizes, 'faulty', -1, 0, 0, 1);
joinFrom(clusterSizes, 'faulty',  0, 0, 0, 1);
joinFrom(clusterSizes, 'faulty',  1, 0, 0, 1);

<|endoftext|>


<commit_before>// Karma configuration
// Generated on Wed Mar 18 2015 11:41:18 GMT+0800 (CST)

module.exports = (config) => {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '../',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['mocha', 'chai', 'sinon', 'sinon-chai', 'fixture'],

    client: {
      chai: {
        includeStack: true
      }
    },

    // list of files / patterns to load in the browser
    files: [{
      pattern: 'test/specs/*.js',
      included: true,
      watched: !process.env.TRAVIS
    }, {
      pattern: 'test/*.html',
      included: true,
      watched: !process.env.TRAVIS
    }],

    // list of files to exclude
    exclude: [
      'test/coverage/**',
      'lib/**',
      'node_modules/'
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
      'test/**/*.js': ['webpack', 'sourcemap'],
      'test/*.html': ['html2js'],
    },

    webpack: {
      devtool: 'inline-source-map',
      module: {
        rules: [{
          test: /\.jsx?$/,
          use: [{
            loader: 'babel-loader',
          }],
          include: /src|test|demo/,
        }, {
          test: /\.js$/,
          include: /src/,
          use: [{
            loader: 'istanbul-instrumenter-loader',
          }],
          enforce: 'post'
        }]
      },
    },

    plugins: [
      'karma-webpack',
      'karma-mocha',
      'karma-coverage',
      'karma-chai',
      'karma-sinon-chai',
      'karma-sinon',
      'karma-sourcemap-loader',
      'karma-fixture',
      'karma-html2js-preprocessor',
      'karma-firefox-launcher',
      'istanbul-instrumenter-loader',
    ],

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: process.env.TRAVIS ? [] : ['progress', 'coverage'],

    coverageReporter: {
      dir: 'test',
      reporters: [{
        type: 'html',
        subdir: 'coverage'
      }, {
        type: 'text',
      }, {
        type: 'lcov',
        subdir: 'coverage'
      }]
    },

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_DEBUG,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Firefox'],

    browserNoActivityTimeout: 60000,

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: process.env.TRAVIS,
  });
};
<commit_msg>updates test to include reporter in travis<commit_after>// Karma configuration
// Generated on Wed Mar 18 2015 11:41:18 GMT+0800 (CST)

module.exports = (config) => {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '../',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['mocha', 'chai', 'sinon', 'sinon-chai', 'fixture'],

    client: {
      chai: {
        includeStack: true
      }
    },

    // list of files / patterns to load in the browser
    files: [{
      pattern: 'test/specs/*.js',
      included: true,
      watched: !process.env.TRAVIS
    }, {
      pattern: 'test/*.html',
      included: true,
      watched: !process.env.TRAVIS
    }],

    // list of files to exclude
    exclude: [
      'test/coverage/**',
      'lib/**',
      'node_modules/'
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
      'test/**/*.js': ['webpack', 'sourcemap'],
      'test/*.html': ['html2js'],
    },

    webpack: {
      devtool: 'inline-source-map',
      module: {
        rules: [{
          test: /\.jsx?$/,
          use: [{
            loader: 'babel-loader',
          }],
          include: /src|test|demo/,
        }, {
          test: /\.js$/,
          include: /src/,
          use: [{
            loader: 'istanbul-instrumenter-loader',
          }],
          enforce: 'post'
        }]
      },
    },

    plugins: [
      'karma-webpack',
      'karma-mocha',
      'karma-coverage',
      'karma-chai',
      'karma-sinon-chai',
      'karma-sinon',
      'karma-sourcemap-loader',
      'karma-fixture',
      'karma-html2js-preprocessor',
      'karma-firefox-launcher',
      'karma-phantomjs-launcher',
      'istanbul-instrumenter-loader',
    ],

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: process.env.TRAVIS ? ['progress'] : ['progress', 'coverage'],

    coverageReporter: {
      dir: 'test',
      reporters: [{
        type: 'html',
        subdir: 'coverage'
      }, {
        type: 'text',
      }, {
        type: 'lcov',
        subdir: 'coverage'
      }]
    },

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_DEBUG,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: process.env.TRAVIS ? ['Firefox'] : ['Firefox'],

    phantomjsLauncher: {
      // Have phantomjs exit if a ResourceError is encountered (useful if karma exits without killing phantom)
      exitOnResourceError: true
    },

    browserNoActivityTimeout: 60000,

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: process.env.TRAVIS,
  });
};
<|endoftext|>