From bd082111abd41bcaa1ffc8891420293b9b42a260 Mon Sep 17 00:00:00 2001
From: Dominik Guzei <dominik.guzei@gmail.com>
Date: Wed, 13 Jul 2016 10:13:31 +0200
Subject: [PATCH 1/2] improve and speedup circle ci setup

---
 .testing/cache_build_and_dependencies.js | 38 +++++++++++++++
 .testing/cache_build_and_dependencies.sh |  3 ++
 .testing/cache_meteor.sh                 |  3 ++
 .testing/cache_npm_dependencies.sh       |  4 ++
 .testing/chimp.js                        | 59 ++++++++++++++++++++++++
 .testing/processes.js                    | 45 ++++++++++++++++++
 circle.yml                               | 22 +++++++--
 package.json                             |  6 +--
 tests/acceptance_run                     |  2 +
 tests/acceptance_watch                   |  2 +
 tests/lists.js                           |  4 +-
 11 files changed, 179 insertions(+), 9 deletions(-)
 create mode 100644 .testing/cache_build_and_dependencies.js
 create mode 100644 .testing/cache_build_and_dependencies.sh
 create mode 100644 .testing/cache_meteor.sh
 create mode 100644 .testing/cache_npm_dependencies.sh
 create mode 100644 .testing/chimp.js
 create mode 100644 .testing/processes.js
 create mode 100644 tests/acceptance_run
 create mode 100644 tests/acceptance_watch

diff --git a/.testing/cache_build_and_dependencies.js b/.testing/cache_build_and_dependencies.js
new file mode 100644
index 00000000..a9c3f32f
--- /dev/null
+++ b/.testing/cache_build_and_dependencies.js
@@ -0,0 +1,38 @@
+#!/usr/bin/env node
+
+const path = require('path');
+const spawn = require('child_process').spawn;
+const baseDir = path.resolve(__dirname, '../');
+const srcDir = baseDir;
+
+const cacheMeteor = function() {
+  console.log('Caching build & dependencies (can take a while the first time)');
+  const childProcess = spawn('meteor', ['--raw-logs'], {
+    cwd: srcDir,
+    env: process.env
+  });
+  childProcess.stdout.setEncoding('utf8');
+  childProcess.stderr.setEncoding('utf8');
+  childProcess.stdout.on('data', function(line) {
+    process.stdout.write(line);
+  });
+  childProcess.stderr.on('data', function(line) {
+    process.stderr.write(line);
+  });
+  const exitAfterBuild = function exitAfterBuild(line) {
+    if (line.indexOf('App running at') !== -1) {
+      childProcess.kill();
+      console.log('Done caching build & dependencies');
+    } else if (
+      line.indexOf('Your application is crashing') !== -1 ||
+      line.indexOf('Errors prevented startup') !== -1) {
+      childProcess.kill();
+      console.error('There were issues whilst trying to cache build & dependencies');
+      throw new Error(line);
+    }
+  };
+  childProcess.stdout.on('data', exitAfterBuild);
+  childProcess.stderr.on('data', exitAfterBuild);
+};
+
+cacheMeteor();
\ No newline at end of file
diff --git a/.testing/cache_build_and_dependencies.sh b/.testing/cache_build_and_dependencies.sh
new file mode 100644
index 00000000..01493b13
--- /dev/null
+++ b/.testing/cache_build_and_dependencies.sh
@@ -0,0 +1,3 @@
+export MONGO_URL="mongodb://localhost:27017/cache"
+echo "Running meteor to cache it …"
+node ./.testing/cache_build_and_dependencies.js
\ No newline at end of file
diff --git a/.testing/cache_meteor.sh b/.testing/cache_meteor.sh
new file mode 100644
index 00000000..01f4e413
--- /dev/null
+++ b/.testing/cache_meteor.sh
@@ -0,0 +1,3 @@
+# Cache Meteor
+if [ -d ~/.meteor ]; then sudo ln -s ~/.meteor/meteor /usr/local/bin/meteor; fi
+if [ ! -e $HOME/.meteor/meteor ]; then curl https://install.meteor.com | sh; fi
\ No newline at end of file
diff --git a/.testing/cache_npm_dependencies.sh b/.testing/cache_npm_dependencies.sh
new file mode 100644
index 00000000..8ab54567
--- /dev/null
+++ b/.testing/cache_npm_dependencies.sh
@@ -0,0 +1,4 @@
+# Cache npm deps
+if [ ! -e /home/ubuntu/nvm/versions/node/v5.2.0/lib/node_modules/chimp/bin/chimp.js ]; then npm install -g chimp; fi
+if [ ! -e /home/ubuntu/nvm/versions/node/v5.2.0/lib/node_modules/spacejam/bin/spacejam ]; then npm install -g spacejam; fi
+npm install
\ No newline at end of file
diff --git a/.testing/chimp.js b/.testing/chimp.js
new file mode 100644
index 00000000..e1d7979a
--- /dev/null
+++ b/.testing/chimp.js
@@ -0,0 +1,59 @@
+#!/usr/bin/env node
+"use strict";
+
+var path = require('path');
+var extend = require('util')._extend;
+var baseDir = path.resolve(__dirname, '../');
+var srcDir = path.resolve(baseDir);
+var source = require(srcDir + '/node_modules/shell-source');
+var processes = require('./processes.js');
+var isCi = process.argv[2] === '--ci';
+
+var startTestApp = function(onStarted, options) {
+  return processes.start({
+    name: 'Test App',
+    command: 'meteor --port=3100',
+    waitForMessage: 'App running at: http://localhost:3100',
+    options: {
+      cwd: srcDir,
+      env: extend(process.env, options)
+    }
+  }, function() {
+    console.log("Test app is running …");
+    onStarted();
+  });
+};
+
+var startChimpWatch = function() {
+  processes.start({
+    name: 'Chimp Watch',
+    command: 'chimp --ddp=http://localhost:3100 --watch --path=tests --mocha --chai --browser=chrome',
+    options: { cwd: baseDir }
+  });
+};
+
+var startChimpCi = function() {
+  var command = 'chimp --ddp=http://localhost:3100 --path=tests --browser=chrome --mocha --chai';
+  processes.start({
+    name: 'Chimp CI',
+    command: command,
+    options: { cwd: baseDir }
+  });
+};
+
+if (isCi) {
+  // CI mode -> run once
+  if (process.env.CIRCLECI) {
+    startTestApp(startChimpCi);
+  } else {
+    // Use a different db for local ci testing to avoid nuking of the dev db
+    startTestApp(startChimpCi, {
+      MONGO_URL: 'mongodb://localhost:3001/chimp_db'
+    });
+  }
+} else {
+  // DEV mode -> watch
+  startTestApp(startChimpWatch, {
+    MONGO_URL: 'mongodb://localhost:3001/chimp_db'
+  });
+}
\ No newline at end of file
diff --git a/.testing/processes.js b/.testing/processes.js
new file mode 100644
index 00000000..d7fb0362
--- /dev/null
+++ b/.testing/processes.js
@@ -0,0 +1,45 @@
+"use strict";
+var fs = require('fs');
+var exec = require('child_process').exec;
+var processes = [];
+
+/**
+ * Helper function to start a process and listen for
+ * specific stdout console output and invoke a callback.
+ * This is used in this case to listen when the normal dev
+ * app started its mongoDb, so we can reuse that for the test app.
+ */
+module.exports = {
+  start: function(opts, callback) {
+    var proc = exec(
+       opts.command,
+       opts.options
+    );
+    if (opts.waitForMessage) {
+      proc.stdout.on('data', function waitForMessage(data) {
+        if (data.toString().match(opts.waitForMessage)) {
+          if (callback) {
+            callback();
+          }
+        }
+      });
+    }
+    if (!opts.silent) {
+      proc.stdout.pipe(process.stdout);
+      proc.stderr.pipe(process.stderr);
+    }
+    if (opts.logFile) {
+      var logStream = fs.createWriteStream(opts.logFile, {flags: 'a'});
+      proc.stdout.pipe(logStream);
+      proc.stderr.pipe(logStream);
+    }
+    proc.on('close', function(code) {
+      console.log(opts.name, 'exited with code ' + code);
+      for (var i = 0; i < processes.length; i += 1) {
+        processes[i].kill();
+      }
+      process.exit(code);
+    });
+    processes.push(proc);
+  }
+};
\ No newline at end of file
diff --git a/circle.yml b/circle.yml
index f03cbc87..f1713061 100644
--- a/circle.yml
+++ b/circle.yml
@@ -1,13 +1,27 @@
 machine:
   node:
-    version: 0.10.40
+    version: 5.2.0
 dependencies:
+  cache_directories:
+    - "~/.npm"
+    - "~/.meteor"
+    - "node_modules"
+    - "./.meteor/local/build"
+    - "./.meteor/local/bundler-cache"
+    - "./.meteor/local/isopacks"
+    - "./.meteor/local/plugin-cache"
+    - "/home/ubuntu/nvm/versions/node/v5.2.0/bin"
+    - "/home/ubuntu/nvm/versions/node/v5.2.0/lib/node_modules"
   override:
-    - curl https://install.meteor.com | /bin/sh
-    - meteor npm install
+    - ./.testing/cache_meteor.sh
+    - ./.testing/cache_npm_dependencies.sh
+    - ./.testing/cache_build_and_dependencies.sh
+    - chimp --path=features # Cache chimp deps by running it without any tests
 checkout:
   post:
     - git submodule update --init
 test:
+  pre:
+    - mkdir -p $CIRCLE_TEST_REPORTS/cucumber
   override:
-    - meteor npm test
+    - ./tests/acceptance_run
\ No newline at end of file
diff --git a/package.json b/package.json
index acc161e5..ce2f3049 100644
--- a/package.json
+++ b/package.json
@@ -8,8 +8,7 @@
     "test-app-watch": "meteor test --full-app --driver-package practicalmeteor:mocha",
     "test-watch-terminal": "TEST_WATCH=1 meteor test --driver-package dispatch:mocha-phantomjs",
     "test-app-watch-terminal": "TEST_WATCH=1 meteor test --full-app --driver-package dispatch:mocha-phantomjs",
-    "lint": "eslint .",
-    "chimp-watch": "chimp --ddp=http://localhost:3000 --watch --mocha --path=tests"
+    "lint": "eslint ."
   },
   "dependencies": {
     "autoprefixer": "^6.3.7",
@@ -23,7 +22,8 @@
     "eslint-plugin-import": "^1.10.3",
     "eslint-plugin-jsx-a11y": "^1.5.3",
     "eslint-plugin-meteor": "^3.6.0",
-    "eslint-plugin-react": "^5.2.2"
+    "eslint-plugin-react": "^5.2.2",
+    "shell-source": "^1.1.0"
   },
   "eslintConfig": {
     "parser": "babel-eslint",
diff --git a/tests/acceptance_run b/tests/acceptance_run
new file mode 100644
index 00000000..bd178a93
--- /dev/null
+++ b/tests/acceptance_run
@@ -0,0 +1,2 @@
+#!/bin/sh
+node ./.testing/chimp.js --ci
\ No newline at end of file
diff --git a/tests/acceptance_watch b/tests/acceptance_watch
new file mode 100644
index 00000000..ad679636
--- /dev/null
+++ b/tests/acceptance_watch
@@ -0,0 +1,2 @@
+#!/bin/sh
+node ./.testing/chimp.js
\ No newline at end of file
diff --git a/tests/lists.js b/tests/lists.js
index 25b55c09..91a54eb7 100644
--- a/tests/lists.js
+++ b/tests/lists.js
@@ -3,14 +3,14 @@
 /* globals browser assert */
 
 const countLists = () => {
-  browser.waitForExist('.list-todo');
+  browser.waitForVisible('.list-todo', 5000);
   const elements = browser.elements('.list-todo');
   return elements.value.length;
 };
 
 describe('list ui', () => {
   beforeEach(() => {
-    browser.url('http://localhost:3000');
+    browser.url('http://localhost:3100');
   });
 
   it('can create a list @watch', () => {

From 4fbd3a5c9296d416f055936a95f2d40b7f1648da Mon Sep 17 00:00:00 2001
From: Dominik Guzei <dominik.guzei@gmail.com>
Date: Wed, 13 Jul 2016 10:16:25 +0200
Subject: [PATCH 2/2] fixes permission problems

---
 .testing/cache_build_and_dependencies.js | 0
 .testing/cache_build_and_dependencies.sh | 0
 .testing/cache_meteor.sh                 | 0
 .testing/cache_npm_dependencies.sh       | 0
 tests/acceptance_run                     | 0
 tests/acceptance_watch                   | 0
 6 files changed, 0 insertions(+), 0 deletions(-)
 mode change 100644 => 100755 .testing/cache_build_and_dependencies.js
 mode change 100644 => 100755 .testing/cache_build_and_dependencies.sh
 mode change 100644 => 100755 .testing/cache_meteor.sh
 mode change 100644 => 100755 .testing/cache_npm_dependencies.sh
 mode change 100644 => 100755 tests/acceptance_run
 mode change 100644 => 100755 tests/acceptance_watch

diff --git a/.testing/cache_build_and_dependencies.js b/.testing/cache_build_and_dependencies.js
old mode 100644
new mode 100755
diff --git a/.testing/cache_build_and_dependencies.sh b/.testing/cache_build_and_dependencies.sh
old mode 100644
new mode 100755
diff --git a/.testing/cache_meteor.sh b/.testing/cache_meteor.sh
old mode 100644
new mode 100755
diff --git a/.testing/cache_npm_dependencies.sh b/.testing/cache_npm_dependencies.sh
old mode 100644
new mode 100755
diff --git a/tests/acceptance_run b/tests/acceptance_run
old mode 100644
new mode 100755
diff --git a/tests/acceptance_watch b/tests/acceptance_watch
old mode 100644
new mode 100755