git2consul
Advanced tools
Comparing version 0.6.4 to 0.6.5
var util = require('util'); | ||
var git2consul = require('./lib'); | ||
var git2consul = require('./lib'); |
@@ -140,3 +140,3 @@ var fs = require('fs'); | ||
this_obj.pull(function(err, msg) { | ||
this_obj.pull(function(err) { | ||
this_obj.busy = false; | ||
@@ -146,3 +146,3 @@ /* istanbul ignore next */ | ||
if (err) return cb(err); | ||
logger.info("Initialized branch: %s", msg); | ||
logger.info("Initialized branch %s from %s", this_obj.name, this_obj.repo_name); | ||
cb(); | ||
@@ -162,3 +162,3 @@ }); | ||
// Clone the branch | ||
this_obj.clone(function(err, msg) { | ||
this_obj.clone(function(err) { | ||
this_obj.busy = false; | ||
@@ -168,3 +168,3 @@ /* istanbul ignore next */ | ||
if (err) return cb(err); | ||
logger.info("Initialized branch: %s", msg); | ||
logger.info("Initialized branch %s from %s", this_obj.name, this_obj.repo_name); | ||
cb(); | ||
@@ -171,0 +171,0 @@ }); |
var logger = require('../../logging.js'); | ||
// Set testing mode based on whether we're running in mocha or not. | ||
var testing = (process.argv[1].indexOf('_mocha'), process.argv[1].length - 6) != -1; | ||
/** | ||
@@ -8,6 +11,6 @@ * Set up a polling hook to update the git_manager on an interval. This can | ||
*/ | ||
exports.init = function(config, repo, mock) { | ||
exports.init = function(config, repo) { | ||
if (!config.interval || config.interval < 0 || parseInt(config.interval) != config.interval) | ||
throw 'Polling intervals must be positive integers' | ||
throw 'Polling intervals must be positive integers'; | ||
@@ -22,3 +25,3 @@ var start_branch_updater = function(branch) { | ||
}); | ||
}, mock ? 1000 /* istanbul ignore next */ : | ||
}, testing ? 1000 /* istanbul ignore next */ : | ||
config.interval * 60 * 1000); | ||
@@ -33,3 +36,3 @@ }; | ||
// out the updates and reduce load spikes against git servers. | ||
}, mock ? 10 : /* istanbul ignore next */ | ||
}, testing ? 10 : /* istanbul ignore next */ | ||
((Math.floor((Math.random() * 30) + 1) ) * 1000)); // In the common case, start polling a random number of seconds later. | ||
@@ -36,0 +39,0 @@ }); |
@@ -7,2 +7,4 @@ var _ = require('underscore'); | ||
var config_reader = require('../config_reader.js'); | ||
var logger = require('../logging.js'); | ||
@@ -12,9 +14,13 @@ | ||
// By default, git2consul expects to run as a daemon. If this flag is disabled, git2consul will not | ||
// start any hooks and will shut down after initializing each branch in each repo. | ||
Object.defineProperty(exports, 'daemon', {value: true, writable: true}); | ||
// Track all active GitManager objects so we can traverse them as needed for a graceful shutdown. | ||
var repos = exports.repos = {}; | ||
Object.defineProperty(exports, 'repos', { value: {} }); | ||
// End the process once we are sure that no branches are busy updating. | ||
exports.gracefulShutdown = function(cb) { | ||
for (var repo_name in repos) { | ||
var repo = repos[repo_name]; | ||
for (var repo_name in exports.repos) { | ||
var repo = exports.repos[repo_name]; | ||
for (var i=0; i<repo.branch_names.length; ++i) { | ||
@@ -33,7 +39,11 @@ var branch_name = repo.branch_names[i]; | ||
// In some cases (such as unit tests), it might be good to know that halt was called. | ||
exports.halt_seen = true; | ||
/* istanbul ignore else */ | ||
// If we were provided a callback, fire it once we know all branches have quiesced. Otherwise, | ||
// shutdown the process. | ||
// If this method has a callback, fire it rather than killing the process. | ||
if (cb) { | ||
cb(); | ||
} else if ((process.argv[1].indexOf('_mocha'), process.argv[1].length - 6) != -1) { | ||
logger.warn("Process is running in unit test. Ignore shutdown."); | ||
} else { | ||
@@ -47,9 +57,5 @@ process.exit(0); | ||
*/ | ||
exports.enableHaltOnChange = function() { | ||
if (!daemon) { | ||
return logger.error("Halt on change requested but no_daemon mode is enabled. Refusing to enable halt on change.") | ||
} | ||
var enableHaltOnChange = function() { | ||
config_reader.wait(function(err) { | ||
if (err) return logger.error("Config poll failure due to %s. Ignoring...", err); | ||
if (err) return logger.error("config poll failure due to %s. Ignoring...", err); | ||
@@ -60,2 +66,5 @@ exports.gracefulShutdown(); | ||
/** | ||
* Provided a configuration object, walk all repo configs and initialize the child repos. | ||
*/ | ||
exports.createRepos = function(config, cb) { | ||
@@ -65,10 +74,21 @@ var this_obj = this; | ||
var error_handler = function(err) { | ||
// Report the error to cb but also gracefully shutdown unless we are in test mode. | ||
// Report the error to cb but also gracefully shutdown. | ||
exports.gracefulShutdown(); | ||
cb(err); | ||
if (mock) var my_cb = function() { logger.error(err) }; | ||
exports.gracefulShutdown(my_cb); | ||
}; | ||
// TODO: Validate that local_store exists. | ||
// Validate that local_store exists. | ||
if (!config.local_store) return error_handler("No local_store provided"); | ||
if (config.no_daemon === true) { | ||
// If we are running in no daemon mode, set git to disable any listeners that would keep | ||
// the process running after the initial sync. | ||
exports.daemon = false; | ||
} else if (config.halt_on_change === true) { | ||
// If we aren't running in no daemon mode and the configuration calls for halt on change, enable it. | ||
// We don't do this if config.no_daemon is enabled as the halt on change listener would keep the process | ||
// running. | ||
enableHaltOnChange(); | ||
} | ||
// Build the root_directory, if necessary | ||
@@ -82,5 +102,2 @@ mkdirp(config.local_store, function(err) { | ||
try { | ||
if (err) return cb('Failed to create root_directory for repo: ' + err); | ||
// Each repo needs a copy of config.local_store | ||
@@ -90,6 +107,6 @@ repo_config.local_store = config.local_store; | ||
// Validate repo name is unique. | ||
if (repos[repo_config.name]) return cb("A repo with that name is already tracked."); | ||
repos[repo_config.name] = new Repo(repo_config); | ||
if (exports.repos[repo_config.name]) return cb("A repo with that name is already tracked."); | ||
exports.repos[repo_config.name] = new Repo(repo_config); | ||
repos[repo_config.name].init(function(err) { | ||
exports.repos[repo_config.name].init(function(err) { | ||
if (err) return error_handler("Failed to load repo " + repo_config.name + " due to " + err); | ||
@@ -101,40 +118,8 @@ | ||
} catch(e) { | ||
/* istanbul ignore next */ | ||
error_handler(e); | ||
} | ||
}); | ||
cb(); | ||
}); | ||
}; | ||
//////////////////////////////////////////////////////////////////////////////////////////////////// | ||
// | ||
// Unit-testing aids | ||
// | ||
//////////////////////////////////////////////////////////////////////////////////////////////////// | ||
var mock = false; | ||
/* | ||
* Turn on mocking mode so that we can inject some bogus config for the purposes of testing. | ||
*/ | ||
exports.mock = function() { | ||
mock = true; | ||
}; | ||
var daemon = true; | ||
/** | ||
* By default, git2consul expects to run as a daemon. If this flag is disabled, git2consul will not | ||
* start any hooks and will shut down after initializing each branch in each repo. | ||
*/ | ||
exports.setDaemon = function(daemon_mode) { | ||
daemon = daemon_mode; | ||
}; | ||
/** | ||
* Clear the git_manager hash. This is useful for unit tests that need to recreate git_managers. | ||
*/ | ||
exports.clearGitManagers = function() { | ||
git_cache = {}; | ||
}; |
@@ -9,2 +9,4 @@ var _ = require('underscore'); | ||
var git = require('./'); | ||
var Branch = require('./branch.js'); | ||
@@ -67,8 +69,13 @@ | ||
// Validate that we are tracking each Branch before enabling hooks to avoid any | ||
// race conditions where a hook fires before a Branch is initialized. | ||
if (branch_count === this_obj.branch_names.length) { | ||
// We are tracking each Branch. | ||
logger.debug('Branches initialized'); | ||
// TODO: Re-add daemon check | ||
if (/**daemon &&**/ this_obj.hooks) { | ||
if (git.daemon && this_obj.hooks) { | ||
// Flag that hooks are running. This data can be used by unit tests to validate | ||
// that daemon config is working properly. | ||
Object.defineProperty(this_obj, 'hooks_active', {value: true}); | ||
// Init hooks | ||
@@ -84,3 +91,3 @@ var errs = []; | ||
hook_provider.init(hook, this_obj, process.env.MOCK); | ||
hook_provider.init(hook, this_obj); | ||
} catch (e) { | ||
@@ -87,0 +94,0 @@ return errs.push("Hook configuration failed due to " + e); |
@@ -48,13 +48,2 @@ var logging = require('./logging.js'); | ||
if (config.no_daemon === true) { | ||
// If we are running in no daemon mode, set git to disable any listeners that would keep | ||
// the process running after the initial sync. | ||
git.setDaemon(false); | ||
} else if (config.halt_on_change === true) { | ||
// If we aren't running in no daemon mode and the configuration calls for halt on change, enable it. | ||
// We don't do this if config.no_daemon is enabled as the halt on change listener would keep the process | ||
// running. | ||
git.enableHaltOnChange(); | ||
} | ||
if (!config.local_store) { | ||
@@ -61,0 +50,0 @@ config.local_store = os.tmpdir(); |
{ | ||
"name": "git2consul", | ||
"description": "System for moving data from git to consul", | ||
"version": "0.6.4", | ||
"version": "0.6.5", | ||
"contributors": [ | ||
@@ -6,0 +6,0 @@ { |
@@ -22,2 +22,4 @@ var should = require('should'); | ||
var git = require('../lib/git'); | ||
var git_utils = require('./utils/git_utils.js'); | ||
@@ -27,19 +29,29 @@ var consul_utils = require('./utils/consul_utils.js'); | ||
exports.cleanup = function(cb) { | ||
// Delete all tracked repos. | ||
for (var key in git.repos) { | ||
delete git.repos[key]; | ||
} | ||
delete git.halt_seen; | ||
// Delete every key from consul. | ||
consul_utils.purgeKeys('', function(err) { | ||
if (err) return cb(err); | ||
// Delete the test remote repo | ||
rimraf(git_utils.TEST_REMOTE_REPO, function(err) { | ||
if (err) return cb(err); | ||
// Recreate the test remote repo | ||
mkdirp(git_utils.TEST_REMOTE_REPO, function(err) { | ||
if (err) return cb(err); | ||
// Delete our local working dir | ||
rimraf(git_utils.TEST_WORKING_DIR, function(err) { | ||
if (err) return cb(err); | ||
// Recreate the local working dir | ||
mkdirp(git_utils.TEST_WORKING_DIR, function(err) { | ||
if (err) return cb(err); | ||
rimraf(git_utils.TEST_GITHUB_WORKING_DIR, function(err) { | ||
if (err) return cb(err); | ||
mkdirp(git_utils.TEST_GITHUB_WORKING_DIR, function(err) { | ||
if (err) return cb(err); | ||
cb(); | ||
}); | ||
}); | ||
cb(); | ||
}); | ||
@@ -52,24 +64,10 @@ }); | ||
var manual_mode = false; | ||
/** | ||
* Provide a mechanism to disable bootstrapping for test cases that want to configure all | ||
* repo functionality themselves. | ||
*/ | ||
exports.manual_mode = function(manual) { | ||
manual_mode = manual; | ||
}; | ||
// These cleanup operations need to run before each test to make sure the state of the | ||
// suite is consistent. Placed here, they will be run before all suites and tests. | ||
beforeEach(function(done) { | ||
// If we are in manual mode, do nothing. | ||
if (manual_mode) return done(); | ||
exports.cleanup(function(err) { | ||
git_utils.initRepo(function(err) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); |
@@ -9,3 +9,2 @@ var should = require('should'); | ||
var Repo = require('../lib/git/repo.js'); | ||
var git_utils = require('./utils/git_utils.js'); | ||
@@ -17,6 +16,6 @@ | ||
var massive_concurrency_test = function(normal_ref_order) { | ||
// Test that branches update correctly even in the presence of multiple pending updates, whether the | ||
// pending updates are serviced in arrival order or not. | ||
var concurrency_test = function(normal_ref_order) { | ||
var my_gm; | ||
var sample_key = 'sample_key'; | ||
@@ -27,36 +26,58 @@ var sample_value = 'test data'; | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Concurrency update.", false, function(err) { | ||
if (err) return done(err); | ||
git_utils.initRepo(function(err, repo) { | ||
git_commands.getCurrentRef(git_utils.TEST_REMOTE_REPO, function(err, ref) { | ||
if (err) done(err); | ||
// The default repo created by initRepo has a single branch, master. | ||
var branch = repo.branches['master']; | ||
var first_ref = ref; | ||
// Handle the initial sync of this repo. Init adds a file to the remote repo, and this line syncs | ||
// that to our local cache and to consul. | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
var sample_key2 = 'sample_key2'; | ||
var sample_value2 = 'test data2'; | ||
git_utils.addFileToGitRepo(sample_key2, sample_value2, "Second file for concurrencty test.", false, function(err) { | ||
// Now that we have a working repo, we start populating the remote end. This test works by adding two | ||
// files in separate commits and then updating our local branch cache for both at the same time. Here, | ||
// we add and commit the first file to the remote repo. | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Concurrency update.", function(err) { | ||
if (err) return done(err); | ||
// Grab the git ref of HEAD from the remote repo. This represents the first change we need to sync. | ||
git_commands.getCurrentRef(git_utils.TEST_REMOTE_REPO, function(err, ref) { | ||
if (err) done(err); | ||
var second_ref = ref; | ||
var branch = git_utils.repo.branches['master']; | ||
var first_ref = ref; | ||
branch.handleRefChange((normal_ref_order ? first_ref : second_ref), function(cb) { | ||
if (err) return done(err); | ||
}); | ||
var sample_key2 = 'sample_key2'; | ||
var sample_value2 = 'test data2'; | ||
branch.handleRefChange((normal_ref_order ? second_ref : first_ref), function(cb) { | ||
// Add and commit the second file to the remote repo. | ||
git_utils.addFileToGitRepo(sample_key2, sample_value2, "Second file for concurrencty test.", function(err) { | ||
if (err) return done(err); | ||
// At this point, the git_manager should have populated consul with both sample_key | ||
consul_utils.validateValue(git_utils.repo.name + '/master/' + sample_key, sample_value, function(err, value) { | ||
if (err) return done(err); | ||
consul_utils.validateValue(git_utils.repo.name + '/master/' + sample_key2, sample_value2, function(err, value) { | ||
// Grab the git ref of HEAD from the remote repo. This represents the first change we need to sync. | ||
git_commands.getCurrentRef(git_utils.TEST_REMOTE_REPO, function(err, ref) { | ||
if (err) done(err); | ||
var second_ref = ref; | ||
// Handle both ref changes. The order in which we call handleRefChange is driven by normal_ref_order: | ||
// in the 'true' case, we will call handleRefChange on the first commit first. | ||
branch.handleRefChange((normal_ref_order ? first_ref : second_ref), function(cb) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
// Because calls to handleRefChange are serviced in arrival order, this invocation will always fire its | ||
// callback after the above invocation. | ||
branch.handleRefChange((normal_ref_order ? second_ref : first_ref), function(cb) { | ||
if (err) return done(err); | ||
// At this point, the local clone of the branch should have populated consul with both sample_keys | ||
consul_utils.validateValue(repo.name + '/' + branch.name + '/' + sample_key, sample_value, function(err, value) { | ||
if (err) return done(err); | ||
consul_utils.validateValue(repo.name + '/' + branch.name + '/' + sample_key2, sample_value2, function(err, value) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -71,4 +92,4 @@ }); | ||
it ('should serialize access to a single branch', massive_concurrency_test(true)); | ||
it ('should serialize access to a single branch even if updates are out of order', massive_concurrency_test(false)); | ||
it ('should serialize access to a single branch', concurrency_test(true)); | ||
it ('should serialize access to a single branch even if updates are out of order', concurrency_test(false)); | ||
}); |
@@ -17,9 +17,17 @@ var should = require('should'); | ||
it ('should handle updates to a single file', function(done) { | ||
var sample_key = 'sample_key'; | ||
var sample_value = 'new test data'; | ||
var repo_name = git_utils.repo.name; | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Update a file.", function(err) { | ||
// The current copy of the git master branch. This is initialized before each test in the suite. | ||
var branch; | ||
beforeEach(function(done) { | ||
// Each of these tests needs a working repo instance, so create it here and expose it to the suite | ||
// namespace. | ||
git_utils.initRepo(function(err, repo) { | ||
if (err) return done(err); | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key, sample_value, function(err, value) { | ||
// The default repo created by initRepo has a single branch, master. | ||
branch = repo.branches['master']; | ||
// Handle the initial sync of this repo. Init adds a file to the remote repo, and this line syncs | ||
// that to our local cache and to consul. | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
@@ -32,11 +40,16 @@ done(); | ||
it ('should handle additions of new files', function(done) { | ||
var sample_key = 'sample_new_key'; | ||
var sample_value = 'new value'; | ||
var repo_name = git_utils.repo.name; | ||
var sample_key = 'sample_key_to_add'; | ||
var sample_value = 'i like turtles'; | ||
// Add the file, call branch.handleRef to sync the commit, then validate that consul contains the correct info. | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Add a file.", function(err) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our sample_key | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key, sample_value, function(err, value) { | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
done(); | ||
// At this point, the repo should have populated consul with our sample_key | ||
consul_utils.validateValue('test_repo/master/' + sample_key, sample_value, function(err, value) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
@@ -46,17 +59,82 @@ }); | ||
it ('should handle additions of multiple files', function(done) { | ||
var sample_key = 'sample_first_key_to_add'; | ||
var sample_value = 'i like turtles'; | ||
var sample_key2 = 'sample_second_key_to_add'; | ||
var sample_value2 = 'i (still) like turtles'; | ||
// Add the files, call branch.handleRef to sync the commits, then validate that consul contains the correct info. | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Add a file.", function(err) { | ||
if (err) return done(err); | ||
git_utils.addFileToGitRepo(sample_key2, sample_value2, "Add another file.", function(err) { | ||
if (err) return done(err); | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our sample_keys | ||
consul_utils.validateValue('test_repo/master/' + sample_key, sample_value, function(err, value) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our sample_keys | ||
consul_utils.validateValue('test_repo/master/' + sample_key2, sample_value2, function(err, value) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it ('should handle updates to a single file', function(done) { | ||
var sample_key = 'sample_key_to_update'; | ||
var sample_value = 'i like turtles'; | ||
// Add the file, call branch.handleRef to sync the commit, then do it all again with a different value. | ||
// Finally, validate that consul contains the correct info. | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Add a file.", function(err) { | ||
if (err) return done(err); | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
// Change the value we commit to the remote end. | ||
sample_value = 'i really like turtles'; | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Update a file.", function(err) { | ||
if (err) return done(err); | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
consul_utils.validateValue('test_repo/master/' + sample_key, sample_value, function(err, value) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it ('should handle deletions of existing files', function(done) { | ||
var sample_key = 'sample_new_key'; | ||
var sample_value = 'new value'; | ||
var repo_name = git_utils.repo.name; | ||
var sample_key = 'sample_key_to_delete'; | ||
var sample_value = 'secret!'; | ||
// Add the file, call branch.handleRef to sync the commit, then delete the file and sync again. | ||
// Finally, validate that consul contains the correct info. | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Create file to delete.", function(err) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our sample_key | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key, sample_value, function(err, value) { | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
git_utils.deleteFileFromGitRepo(sample_key, "Delete file.", true, function(err) { | ||
// Validate that the file was added to consul before we delete it | ||
consul_utils.validateValue('test_repo/master/' + sample_key, sample_value, function(err, value) { | ||
if (err) return done(err); | ||
// At this point, the repo should have removed our sample_key | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key, undefined, function(err, value) { | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
done(); | ||
git_utils.deleteFileFromGitRepo(sample_key, "Delete file.", function(err) { | ||
if (err) return done(err); | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
// At this point, the branch should have removed our sample_key from consul. | ||
consul_utils.validateValue('test_repo/master/' + sample_key, undefined, function(err, value) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -72,17 +150,25 @@ }); | ||
var sample_value = 'movable value'; | ||
var repo_name = git_utils.repo.name; | ||
// Add the file, call branch.handleRef to sync the commit, then move the file and sync again. | ||
// Finally, validate that consul contains the correct info. | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Create file to move.", function(err) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our sample_key | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key, sample_value, function(err, value) { | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
git_utils.moveFileInGitRepo(sample_key, sample_moved_key, "Move file.", function(err) { | ||
// Validate that the file was added to consul before we move it | ||
consul_utils.validateValue('test_repo/master/' + sample_key, sample_value, function(err, value) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our moved key, deleting the old name | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key, undefined, function(err) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our moved key, adding the new name | ||
consul_utils.validateValue(repo_name + '/master/' + sample_moved_key, sample_value, function(err) { | ||
git_utils.moveFileInGitRepo(sample_key, sample_moved_key, "Move file.", function(err) { | ||
if (err) return done(err); | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
done(); | ||
// At this point, the repo should have populated consul with our moved key, deleting the old name | ||
consul_utils.validateValue('test_repo/master/' + sample_key, undefined, function(err) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our moved key, adding the new name | ||
consul_utils.validateValue('test_repo/master/' + sample_moved_key, sample_value, function(err) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
@@ -96,22 +182,32 @@ }); | ||
it ('should handle moving an existing file into a subfolder', function(done) { | ||
var sample_key = 'sample_movable_key'; | ||
var sample_moved_key = 'subfolder/sample_moved_key'; | ||
var sample_key = 'sample_wrong_directory_key'; | ||
var sample_moved_key = 'subfolder/sample_right_directory_key'; | ||
var sample_value = 'movable value'; | ||
var repo_name = git_utils.repo.name; | ||
// Add the file, call branch.handleRef to sync the commit, then move the file and sync again. | ||
// Finally, validate that consul contains the correct info. | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Create file to move to subfolder.", function(err) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our sample_key | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key, sample_value, function(err, value) { | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
mkdirp(git_utils.TEST_REMOTE_REPO + 'subfolder', function(err) { | ||
// Validate that the file was added to consul before we move it | ||
consul_utils.validateValue('test_repo/master/' + sample_key, sample_value, function(err, value) { | ||
if (err) return done(err); | ||
git_utils.moveFileInGitRepo(sample_key, sample_moved_key, "Move file to subfolder.", function(err) { | ||
// Create the subdirectory in the remote repo. | ||
mkdirp(git_utils.TEST_REMOTE_REPO + 'subfolder', function(err) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our moved key, deleting the old name | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key, undefined, function(err) { | ||
// Move the key to the subdirectory. | ||
git_utils.moveFileInGitRepo(sample_key, sample_moved_key, "Move file to subfolder.", function(err) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our moved key, adding the new name | ||
consul_utils.validateValue(repo_name + '/master/' + sample_moved_key, sample_value, function(err) { | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
done(); | ||
// At this point, the repo should have populated consul with our moved key, deleting the old name | ||
consul_utils.validateValue('test_repo/master/' + sample_key, undefined, function(err) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our moved key, adding the new name | ||
consul_utils.validateValue('test_repo/master/' + sample_moved_key, sample_value, function(err) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
@@ -129,17 +225,25 @@ }); | ||
var sample_value = 'linked value'; | ||
var repo_name = git_utils.repo.name; | ||
// Add the file, call branch.handleRef to sync the commit, then convert the file to a symlink and | ||
// sync again. Finally, validate that consul contains the correct info. | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Create file for symlinking.", function(err) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our sample_key | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key, sample_value, function(err, value) { | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
git_utils.symlinkFileInGitRepo(sample_key, sample_referrent_file, "Change type of file.", function(err) { | ||
// At this point, the repo should have populated consul with our sample_key | ||
consul_utils.validateValue('test_repo/master/' + sample_key, sample_value, function(err, value) { | ||
if (err) return done(err); | ||
// After symlinking, the consul KV should contain the symlink's name as a key and the symlinked file's contents as a value | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key, sample_value, function(err) { | ||
if (err) return done(err); | ||
// The symlink's referrent should also appear in the KV store. | ||
consul_utils.validateValue(repo_name + '/master/' + sample_referrent_file, sample_value, function(err) { | ||
git_utils.symlinkFileInGitRepo(sample_key, sample_referrent_file, "Change type of file.", function(err) { | ||
if (err) return done(err); | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
done(); | ||
// After symlinking, the consul KV should contain the symlink's name as a key and the symlinked file's contents as a value | ||
consul_utils.validateValue('test_repo/master/' + sample_key, sample_value, function(err) { | ||
if (err) return done(err); | ||
// The symlink's referrent should also appear in the KV store. | ||
consul_utils.validateValue('test_repo/master/' + sample_referrent_file, sample_value, function(err) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
@@ -146,0 +250,0 @@ }); |
@@ -15,2 +15,23 @@ var should = require('should'); | ||
// The current copy of the git master branch. This is initialized before each test in the suite. | ||
var branch; | ||
beforeEach(function(done) { | ||
// Each of these tests needs a working repo instance, so create it here and expose it to the suite | ||
// namespace. | ||
git_utils.initRepo(function(err, repo) { | ||
if (err) return done(err); | ||
// The default repo created by initRepo has a single branch, master. | ||
branch = repo.branches['master']; | ||
// Handle the initial sync of this repo. Init adds a file to the remote repo, and this line syncs | ||
// that to our local cache and to consul. | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
var buffer_test = function(size, cb) { | ||
@@ -22,9 +43,8 @@ var buf = new Buffer(size); | ||
git_utils.addFileToGitRepo("big_file", buf.toString(), "super big value test", cb); | ||
git_utils.addFileToGitRepo("big_file", buf.toString(), "super big value test", function(err) { | ||
branch.handleRefChange(0, cb); | ||
}); | ||
}; | ||
it ('should accept values <= 512kB', function(done) { | ||
var repo_name = git_utils.repo.name; | ||
buffer_test(512*1024, function(err) { | ||
@@ -34,3 +54,3 @@ if (err) return done(err); | ||
// At this point, the repo should have populated consul with our sample_key | ||
consul_utils.getValue(repo_name + '/master/big_file', function(err, value) { | ||
consul_utils.getValue('test_repo/master/big_file', function(err, value) { | ||
if (err) return done(err); | ||
@@ -44,9 +64,6 @@ value.length.should.equal(512*1024); | ||
it ('should reject values over 512kB', function(done) { | ||
var repo_name = git_utils.repo.name; | ||
buffer_test(513*1024, function(err) { | ||
err.should.not.equal(null); | ||
// Because the write was rejected, no KV will exist. | ||
consul_utils.validateValue(repo_name + '/master/big_file', undefined, function(err) { | ||
consul_utils.validateValue('test_repo/master/big_file', undefined, function(err) { | ||
if (err) return done(err); | ||
@@ -60,13 +77,13 @@ done(); | ||
it ('should handle files with empty values', function(done) { | ||
var repo_name = git_utils.repo.name; | ||
var sample_key = 'sample_new_key'; | ||
var sample_key = 'sample_empty_value_key'; | ||
var sample_value = ''; | ||
var default_repo_config = git_utils.createRepoConfig(); | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Add a file.", function(err) { | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Add a file with an empty value.", function(err) { | ||
if (err) return done(err); | ||
// At this point, the repo should have populated consul with our sample_key | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key, sample_value, function(err, value) { | ||
if (err) return done(err); | ||
done(); | ||
branch.handleRefChange(0, function(err) { | ||
// At this point, the repo should have populated consul with our sample_key | ||
consul_utils.validateValue('test_repo/master/' + sample_key, sample_value, function(err, value) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
@@ -73,0 +90,0 @@ }); |
@@ -11,7 +11,2 @@ var should = require('should'); | ||
describe('Graceful Shutdown', function() { | ||
before(function() { | ||
git.mock(); | ||
bootstrap.manual_mode(true); | ||
}); | ||
@@ -25,39 +20,32 @@ it ('should successfully fire if nothing else is happening', function(done) { | ||
it ('should successfully fire if other stuff is happening', function(done) { | ||
git_utils.initRepo(function(err, repo) { | ||
if (err) return done(err); | ||
bootstrap.cleanup(function(err) { | ||
git_utils.initRepo(function(err) { | ||
// This should be set only once the handle ref has completed. | ||
var shutdown_seen = false; | ||
var sample_key = 'sample_key'; | ||
var sample_value = 'new test data'; | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Update a file.", function(err) { | ||
if (err) return done(err); | ||
// This should be set only once the handle ref has completed. | ||
var shutdown_seen = false; | ||
var ref_change_handled = false; | ||
var sample_key = 'sample_key'; | ||
var sample_value = 'new test data'; | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Update a file.", false, function(err) { | ||
repo.branches['master'].handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
shutdown_seen.should.equal(false); | ||
ref_change_handled = true; | ||
}); | ||
var ref_change_handled = false; | ||
git_utils.repo.branches['master'].handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
shutdown_seen.should.equal(false); | ||
ref_change_handled = true; | ||
}); | ||
// This should not fire until after we've processed the handleRefChange above | ||
git.gracefulShutdown(function() { | ||
shutdown_seen = true; | ||
ref_change_handled.should.equal(true); | ||
done(); | ||
}); | ||
// This should not fire until after we've processed the handleRefChange above | ||
git.gracefulShutdown(function() { | ||
shutdown_seen = true; | ||
ref_change_handled.should.equal(true); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
after(function() { | ||
bootstrap.manual_mode(false); | ||
}); | ||
}); |
@@ -9,2 +9,3 @@ var should = require('should'); | ||
var git = require('../lib/git'); | ||
var Repo = require('../lib/git/repo.js'); | ||
@@ -15,113 +16,82 @@ var git_utils = require('./utils/git_utils.js'); | ||
describe('Cloning a repo for the first time', function() { | ||
describe('Initializing git2consul', function() { | ||
it ('should handle a multiple file repo', function(done) { | ||
var repo_name = git_utils.repo.name; | ||
var sample_key = 'sample_key'; | ||
var sample_value = 'test data'; | ||
var default_repo_config = git_utils.createRepoConfig(); | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Clone test.", false, function(err) { | ||
it ('should handle creating a repo tracking multiple branches', function(done) { | ||
// Create a remote git repo with 3 branches and a file per branch. Then, init a Repo object and validate | ||
// that all 3 files are in the appropriate place in the Consul KV store. | ||
git_commands.init(git_utils.TEST_REMOTE_REPO, function(err) { | ||
if (err) return done(err); | ||
var sample_key2 = 'sample_key2'; | ||
var sample_value2 = 'test data2'; | ||
var default_repo_config = git_utils.createRepoConfig(); | ||
git_utils.addFileToGitRepo(sample_key2, sample_value2, "Second file for clone test.", function(err) { | ||
if (err) return done(err); | ||
var repo_config = git_utils.createRepoConfig(); | ||
repo_config.branches = ['dev', 'test', 'prod']; | ||
var branch_tests = []; | ||
// At this point, the repo should have populated consul with our sample_key | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key, sample_value, function(err, value) { | ||
if (err) return done(err); | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key2, sample_value2, function(err, value) { | ||
var create_branch_and_add = function(branch_name, done) { | ||
return function() { | ||
git_commands.checkout_branch(branch_name, git_utils.TEST_REMOTE_REPO, function(err) { | ||
if (err) return done(err); | ||
done(); | ||
git_utils.addFileToGitRepo("readme.md", "Test file in " + branch_name + " branch", branch_name + " commit", function(err) { | ||
if (err) return done(err); | ||
// If we've processed every branch, we are done and are ready to create a git manager around these | ||
// three branches. | ||
if (branch_tests.length === 0) { | ||
validate_result(done); | ||
} else { | ||
// If there are more test functions to run, do so. | ||
branch_tests.pop()(); | ||
} | ||
}); | ||
}); | ||
}); | ||
}; | ||
}; | ||
// Create a test function for each branch | ||
repo_config.branches.forEach(function(branch_name) { | ||
branch_tests.push(create_branch_and_add(branch_name, done)); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('Initializing git2consul', function() { | ||
// Create the first branch test. | ||
branch_tests.pop()(); | ||
it ('should handle creating a repo tracking multiple branches', function(done) { | ||
var branches = ['dev', 'test', 'prod']; | ||
var config = git_utils.createConfig(); | ||
var repo_config = config.repos[0]; | ||
repo_config.branches = branches; | ||
var branch_tests = []; | ||
var create_branch_and_add = function(branch_name, done) { | ||
return function() { | ||
git_commands.checkout_branch(branch_name, git_utils.TEST_REMOTE_REPO, function(err) { | ||
// Once all branches have been populated, validate that the KV is in the right state. | ||
var validate_result = function(done) { | ||
var repo = new Repo(repo_config); | ||
repo.init(function(err) { | ||
if (err) return done(err); | ||
git_utils.addFileToGitRepo("readme.md", "Stub file in " + branch_name + " branch", branch_name + " stub.", false, function(err) { | ||
// Check consul for the correct file in each branch. | ||
consul_utils.validateValue('test_repo/dev/readme.md', "Test file in dev branch", function(err, value) { | ||
if (err) return done(err); | ||
// If we've processed every branch, we are done and are ready to create a git manager around these | ||
// three branches. | ||
if (branch_tests.length === 0) { | ||
var repo = new Repo(repo_config); | ||
repo.init(function(err) { | ||
consul_utils.validateValue('test_repo/test/readme.md', "Test file in test branch", function(err, value) { | ||
if (err) return done(err); | ||
consul_utils.validateValue('test_repo/prod/readme.md', "Test file in prod branch", function(err, value) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
} else { | ||
// If there are more test functions to run, do so. | ||
branch_tests.pop()(); | ||
} | ||
}); | ||
}); | ||
}); | ||
}; | ||
}; | ||
// Create a test function for each branch | ||
branches.forEach(function(branch_name) { | ||
branch_tests.push(create_branch_and_add(branch_name, done)); | ||
}); | ||
// Most tests assume that we want a repo already initted, so requiring bootstrap.js provides this. However, | ||
// for this test, we want to start with a clean slate. | ||
bootstrap.cleanup(function(err) { | ||
if (err) done(err); | ||
git_commands.init(git_utils.TEST_REMOTE_REPO, function(err) { | ||
if (err) return done(err); | ||
// Run the first test | ||
branch_tests.pop()(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it ('should handle creating a git_manager around a repo that already exists', function(done) { | ||
var repo_config = git_utils.createRepoConfig(); | ||
describe('git2consul config', function() { | ||
var sample_key = 'sample_key'; | ||
var sample_value = 'test data'; | ||
// This addFileToGitRepo will automatically create a git_manager in git_utils, so once the callback | ||
// has fired we know that we are mirroring and managing the master branch locally. | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Create a git repo.", function(err) { | ||
beforeEach(function(done) { | ||
// Each of these tests needs a working repo instance, so create it here and expose it to the suite | ||
// namespace. | ||
git_utils.initRepo(function(err, repo) { | ||
if (err) return done(err); | ||
// Now we create another repo around the same repo with the same local address. This tells | ||
// us that a git_manager can be created around an existing repo without issue. | ||
var repo = new Repo(repo_config); | ||
repo.init(function(err) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
/** | ||
it ('should handle creating a git_manager around a repo that has been emptied', function(done) { | ||
var repo_config = git_utils.createRepoConfig(); | ||
// The default repo created by initRepo has a single branch, master. | ||
branch = repo.branches['master']; | ||
// This addFileToGitRepo will automatically create a git_manager in git_utils, so once the callback | ||
// has fired we know that we are mirroring and managing the master branch locally. | ||
git_utils.deleteFileFromGitRepo('readme.md', "Clearing repo.", function(err) { | ||
if (err) return done(err); | ||
// Now we create another repo around the same repo with the same local address. This tells | ||
// us that a git_manager can be created around an emptied repo without issue. | ||
var repo = new Repo(repo_config); | ||
repo.init(function(err) { | ||
// Handle the initial sync of this repo. Init adds a file to the remote repo, and this line syncs | ||
// that to our local cache and to consul. | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
@@ -133,74 +103,36 @@ done(); | ||
it ('should handle populating consul when you create a git_manager around a repo that is already on disk', function(done) { | ||
var repo_name = git_utils.repo.name; | ||
var default_config = git_utils.createConfig(); | ||
var default_repo_config = default_config.repos[0]; | ||
default_repo_config.name = repo_name; | ||
git_manager.clearGitManagers(); | ||
var config = { | ||
repos: [{ | ||
name: 'repo1', | ||
url: 'file://' + git_utils.TEST_REMOTE_REPO, | ||
branches: [ 'master' ] | ||
},{ | ||
name: 'repo2', | ||
url: git_utils.TEST_REMOTE_REPO, | ||
branches: [ 'master' ] | ||
}] | ||
}; | ||
var sample_key = 'sample_key'; | ||
var sample_value = 'test data'; | ||
it ('should fail to create repos if no local_store is present on the top level config', function(done) { | ||
git.createRepos(config, function(err) { | ||
err.should.equal('No local_store provided'); | ||
// Create a git_manager and validate that the expected contents are present. This should only be run | ||
// once we know the consul cluster has been purged of the previously cached values. | ||
var test_git_manager = function(done) { | ||
// Now we create another git_manager around the same repo with the same local address. This tells | ||
// us that a git_manager can be created around an existing repo without issue. | ||
git_manager.manageRepo(default_config, default_repo_config, function(err, gm) { | ||
(err === null).should.equal(true); | ||
// At this point, the git_manager should have populated consul with our sample_key | ||
consul_utils.validateValue(repo_name + '/master/' + sample_key, sample_value, function(err, value) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
}; | ||
// This addFileToGitRepo will automatically create a git_manager in git_utils, so once the callback | ||
// has fired we know that we are mirroring and managing the master branch locally. | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Stale repo test.", function(err) { | ||
if (err) return done(err); | ||
// Now we want to delete the KVs from Consul and create another git_manager with the same configuration. | ||
consul_utils.purgeKeys('test_repo', function(err) { | ||
if (err) return done(err); | ||
consul_utils.waitForDelete('test_repo?recurse', function(err) { | ||
if (err) return done(err); | ||
test_git_manager(done); | ||
}); | ||
}); | ||
// Now fix config by adding local_store | ||
config.local_store = git_utils.TEST_WORKING_DIR; | ||
done(); | ||
}); | ||
}); | ||
it ('should handle creating multiple git repos', function(done) { | ||
var sample_key = 'sample_key'; | ||
var sample_value = 'test data'; | ||
var default_config = git_utils.createConfig(); | ||
var countdown = 2; | ||
// Add a Github repo to our repo config because we want to initialize multiple repos at once. | ||
default_config.repos.push({ | ||
name: 'test_github_repo', | ||
url: git_utils.TEST_GITHUB_REPO, | ||
branches: [ 'master' ] | ||
}); | ||
it ('should handle successfully creating multiple git repos with valid config', function(done) { | ||
git.createRepos(config, function(err) { | ||
(err === undefined).should.equal(true); | ||
git.repos.should.have.properties('repo1', 'repo2'); | ||
// We use 'false' for the auto-commit flag on this call because we don't want a git_manager to be | ||
// created in git_utils. We want the manageRepos call to be the first time we create any repos | ||
// in this test. | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Multi repo test.", false, function(err) { | ||
if (err) return done(err); | ||
git_manager.manageRepos(default_config, function(err, gms) { | ||
if (err) return done(err); | ||
(err == null).should.equal(true); | ||
gms.length.should.equal(2); | ||
done(); | ||
}); | ||
--countdown; | ||
if (countdown === 0) done(); | ||
}); | ||
}); | ||
**/ | ||
}); |
@@ -14,14 +14,36 @@ var should = require('should'); | ||
var default_repo_config = git_utils.createRepoConfig(); | ||
// The current copy of the git master branch. This is initialized before each test in the suite. | ||
var branch; | ||
beforeEach(function(done) { | ||
// Each of these tests needs a working repo instance, so create it here and expose it to the suite | ||
// namespace. | ||
git_utils.initRepo(function(err, repo) { | ||
if (err) return done(err); | ||
// The default repo created by initRepo has a single branch, master. | ||
branch = repo.branches['master']; | ||
// Handle the initial sync of this repo. Init adds a file to the remote repo, and this line syncs | ||
// that to our local cache and to consul. | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
var test_add = function(key_name, key_value) { | ||
return function(done) { | ||
var repo_name = git_utils.repo.name; | ||
git_utils.addFileToGitRepo(key_name, key_value, key_name + " key name test.", function(err) { | ||
if (err) return done(err); | ||
// At this point, the git_manager should have populated consul with our sample_key | ||
consul_utils.validateValue(repo_name + '/master/' + key_name, key_value, function(err, value) { | ||
branch.handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
done(); | ||
// At this point, the git_manager should have populated consul with our sample_key | ||
consul_utils.validateValue('test_repo/master/' + key_name, key_value, function(err, value) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
@@ -28,0 +50,0 @@ }); |
@@ -11,2 +11,4 @@ var should = require('should'); | ||
var Repo = require('../lib/git/repo.js'); | ||
var git = require('../lib/git'); | ||
var git_commands = require('../lib/git/commands.js'); | ||
var git_utils = require('./utils/git_utils.js'); | ||
@@ -21,2 +23,3 @@ | ||
*/ | ||
// Test failing webhook configs | ||
@@ -49,16 +52,24 @@ [[ | ||
var my_hooked_gm; | ||
it ('should reject invalid webhook config', function(done) { | ||
var repo_config = git_utils.createRepoConfig(); | ||
repo_config.hooks = hook_config; | ||
var repo = new Repo(repo_config); | ||
repo.init(function(err) { | ||
if (hook_config[0]) { | ||
err[0].should.equal(hook_config[0].err); | ||
} else { | ||
err[0].should.startWith('Hook configuration failed due to'); | ||
} | ||
done(); | ||
git_commands.init(git_utils.TEST_REMOTE_REPO, function(err) { | ||
if (err) return done(err); | ||
// When we create a repo, we need it to have an initial commit. The call to addFile provides that. | ||
git_utils.addFileToGitRepo("readme.md", "Stub file to give us something to commit.", "Init webhook config repo.", function(err) { | ||
if (err) return done(err); | ||
var repo_config = git_utils.createRepoConfig(); | ||
repo_config.hooks = hook_config; | ||
var repo = new Repo(repo_config); | ||
repo.init(function(err) { | ||
if (hook_config[0]) { | ||
err[0].should.equal(hook_config[0].err); | ||
} else { | ||
err[0].should.startWith('Hook configuration failed due to'); | ||
} | ||
done(); | ||
}); | ||
}); | ||
}); | ||
@@ -69,4 +80,2 @@ }); | ||
var repo_counter = 0; | ||
[ | ||
@@ -98,5 +107,5 @@ // Test webhooks sharing a port | ||
'url': '/githubpoke_bogus_branch', | ||
'port': 5252, | ||
'port': 5253, | ||
'body': { ref: "refs/heads/bogus_branch", head_commit: {id: 12345} }, | ||
'fqurl': 'http://localhost:5252/githubpoke_bogus_branch', | ||
'fqurl': 'http://localhost:5253/githubpoke_bogus_branch', | ||
'no_change_expected': true | ||
@@ -106,5 +115,5 @@ },{ | ||
'url': '/stashpoke_bogus_branch', | ||
'port': 5252, | ||
'port': 5253, | ||
'body': { refChanges: [{refId: "refs/heads/bogus_branch", toHash: "0"}]}, | ||
'fqurl': 'http://localhost:5252/stashpoke_bogus_branch', | ||
'fqurl': 'http://localhost:5253/stashpoke_bogus_branch', | ||
'no_change_expected': true | ||
@@ -114,5 +123,5 @@ },{ | ||
'url': '/bitbucket_bogus_branch', | ||
'port': 5252, | ||
'port': 5253, | ||
'body': '%7B%22repository%22%3A+%7B%22website%22%3A+null%2C+%22fork%22%3A+false%2C+%22name%22%3A+%22configuration%22%2C+%22scm%22%3A+%22git%22%2C+%22owner%22%3A+%22ryanbreen%22%2C+%22absolute_url%22%3A+%22%2Fryanbreen%2Fconfiguration%2F%22%2C+%22slug%22%3A+%22configuration%22%2C+%22is_private%22%3A+true%7D%2C+%22truncated%22%3A+false%2C+%22commits%22%3A+%5B%7B%22node%22%3A+%226f086f3d3de7%22%2C+%22files%22%3A+%5B%7B%22type%22%3A+%22modified%22%2C+%22file%22%3A+%22jobs_service%2Fauspice%2Fdemo-consumer-key%22%7D%5D%2C+%22raw_author%22%3A+%22Ryan+Breen+%3Crbreen%40vistaprint.com%3E%22%2C+%22utctimestamp%22%3A+%222014-10-18+23%3A20%3A47%2B00%3A00%22%2C+%22author%22%3A+%22Ryan+Breen%22%2C+%22timestamp%22%3A+%222014-10-19+01%3A20%3A47%22%2C+%22raw_node%22%3A+%226f086f3d3de724b9007934408e023b628a59ea15%22%2C+%22parents%22%3A+%5B%2230c88d68d029%22%5D%2C+%22branch%22%3A+%22dev%22%2C+%22message%22%3A+%22Adding+bitbucket+test.%5Cn%22%2C+%22revision%22%3A+null%2C+%22size%22%3A+-1%7D%5D%2C+%22canon_url%22%3A+%22https%3A%2F%2Fbitbucket.org%22%2C+%22user%22%3A+%22ryanbreen%22%7D', | ||
'fqurl': 'http://localhost:5252/bitbucket_bogus_branch', | ||
'fqurl': 'http://localhost:5253/bitbucket_bogus_branch', | ||
'no_change_expected': true | ||
@@ -124,5 +133,5 @@ }], | ||
'url': '/githubpoke_bogus_ref', | ||
'port': 5252, | ||
'port': 5254, | ||
'body': { ref: "refs/remotes/origin/master", head_commit: {id: 12345} }, | ||
'fqurl': 'http://localhost:5252/githubpoke_bogus_branch', | ||
'fqurl': 'http://localhost:5254/githubpoke_bogus_branch', | ||
'no_change_expected': true | ||
@@ -132,5 +141,5 @@ },{ | ||
'url': '/stashpoke_bogus_ref', | ||
'port': 5252, | ||
'port': 5254, | ||
'body': { refChanges: [{refId: "refs/remotes/origin/master", toHash: "0"}]}, | ||
'fqurl': 'http://localhost:5252/stashpoke_bogus_ref', | ||
'fqurl': 'http://localhost:5254/stashpoke_bogus_ref', | ||
'no_change_expected': true | ||
@@ -140,73 +149,71 @@ },{ | ||
'url': '/bitbucket_bogus_ref', | ||
'port': 5252, | ||
'port': 5254, | ||
'body': '', | ||
'fqurl': 'http://localhost:5252/bitbucket_bogus_ref', | ||
'fqurl': 'http://localhost:5254/bitbucket_bogus_ref', | ||
'no_change_expected': true | ||
}] | ||
}] | ||
].forEach(function(hook_config) { | ||
var repo; | ||
describe('webhook', function() { | ||
before(function(done) { | ||
// Add a file for the config, commit it, and validate that it has populated properly. | ||
var test_hook_req = function(config, cb) { | ||
var sample_key = 'webhook_key_' + config.type; | ||
var sample_value = config.type + ' test data'; | ||
// Enable manual mode. We don't want the standard git2consul bootstrap tests to create a git_manager | ||
// that is enabled without hooks as this just causes endless confusion. | ||
bootstrap.manual_mode(true); | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Webhook.", function(err) { | ||
if (err) return cb(err); | ||
bootstrap.cleanup(function(err) { | ||
var req_conf = { url: config.fqurl, method: 'POST' }; | ||
if (config.type === 'bitbucket') { | ||
req_conf.form = { payload: decodeURIComponent(config.body).replace(/\+/g, ' ') }; | ||
} else req_conf.json = config.body | ||
if (config.type === 'stash') req_conf.headers = {'content-encoding':'UTF-8'}; | ||
request(req_conf, function(err) { | ||
if (err) return done(err); | ||
if (err) return cb(err); | ||
var repo_config = git_utils.createRepoConfig(); | ||
repo_config.hooks = hook_config; | ||
repo_config.name = "webhook_test" + repo_counter; | ||
++repo_counter; | ||
// If this is a test that won't trigger an update, such as a req specifying an untracked branch, | ||
// short-circuit here and don't test for a KV update. | ||
if (config.no_change_expected) return cb(); | ||
git_utils.initRepo(repo_config, function(err, gm) { | ||
if (err) return done(err); | ||
done(); | ||
consul_utils.waitForValue('test_repo/master/' + sample_key, function(err) { | ||
if (err) return cb(err); | ||
cb(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}; | ||
var sample_data_randomizer = 0; | ||
it ('should handle inbound requests', function(done) { | ||
var repo_config = git_utils.createRepoConfig(); | ||
repo_config.hooks = hook_config; | ||
// This creates a function suitable as the predicate of a mocha test. The function will enclose | ||
// the config object and use it to send a request to the webhook and validate the response. | ||
var create_request_validator = function(config) { | ||
return function(done) { | ||
var repo_name = git_utils.repo.name; | ||
var sample_key = 'sample_key'; | ||
var sample_value = 'stash test data ' + sample_data_randomizer; | ||
++sample_data_randomizer; | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Webhook.", false, function(err) { | ||
git_utils.initRepo(repo_config, function(err, repo) { | ||
if (err) return done(err); | ||
// Handle the initial sync of this repo. Init adds a file to the remote repo, and this line syncs | ||
// that to our local cache and to consul. | ||
repo.branches['master'].handleRefChange(0, function(err) { | ||
if (err) return done(err); | ||
var req_conf = { url: config.fqurl, method: 'POST' }; | ||
if (config.type === 'bitbucket') { | ||
req_conf.form = { payload: decodeURIComponent(config.body).replace(/\+/g, ' ') }; | ||
} else req_conf.json = config.body | ||
if (config.type === 'stash') req_conf.headers = {'content-encoding':'UTF-8'}; | ||
request(req_conf, function(err) { | ||
if (err) return done(err); | ||
// If this is a test that won't trigger an update, such as a req specifying an untracked branch, | ||
// short-circuit here and don't test for a KV update. | ||
if (config.no_change_expected) return done(); | ||
consul_utils.waitForValue(repo_name + '/master/sample_key', function(err) { | ||
// Test each hook config, 1 at a time. Since they are updating the same repo, having all webhooks | ||
// fire in parallel would lead to undefined results. | ||
var test_config = function() { | ||
config = hook_config.pop(); | ||
test_hook_req(config, function(err) { | ||
if (err) return done(err); | ||
if (hook_config.length > 0) return test_config(); | ||
done(); | ||
}); | ||
}); | ||
}; | ||
test_config(); | ||
}); | ||
}; | ||
}; | ||
hook_config.forEach(function(config) { | ||
it (config.type + ' should handle inbound requests', create_request_validator(config)); | ||
}); | ||
}); | ||
@@ -231,4 +238,2 @@ }); | ||
var my_hooked_gm; | ||
it ('should reject invalid polling config', function(done) { | ||
@@ -238,4 +243,3 @@ var repo_config = git_utils.createRepoConfig(); | ||
var repo = new Repo(repo_config); | ||
repo.init(function(err) { | ||
git_utils.initRepo(repo_config, function(err, repo) { | ||
if (hook_config[0]) { | ||
@@ -254,38 +258,72 @@ err[0].should.equal('Hook configuration failed due to Polling intervals must be positive integers'); | ||
before(function(done) { | ||
// Create a repo with a polling hook and validate that the KV is updated on a change to the remote | ||
// repo contents. | ||
it ('should handle polling updates', function(done) { | ||
// Enable manual mode. We don't want the standard git2consul bootstrap tests to create a git_manager | ||
// that is enabled without hooks as this just causes endless confusion. | ||
bootstrap.manual_mode(true); | ||
process.env.MOCK = true; | ||
var repo_config = git_utils.createRepoConfig(); | ||
repo_config.hooks = [{ | ||
'type': 'polling', | ||
'interval': '1' | ||
}]; | ||
repo_config.name = "polling_test"; | ||
bootstrap.cleanup(function(err) { | ||
git_utils.initRepo(repo_config, function(err, repo) { | ||
if (err) return done(err); | ||
var repo_config = git_utils.createRepoConfig(); | ||
repo_config.hooks = [{ | ||
'type': 'polling', | ||
'interval': '1' | ||
}]; | ||
repo_config.name = "polling_test"; | ||
repo.hooks_active.should.equal(true); | ||
git_utils.initRepo(repo_config, function(err, gm) { | ||
var sample_key = 'sample_key'; | ||
var sample_value = 'stash test data'; | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Polling hook.", function(err) { | ||
if (err) return done(err); | ||
done(); | ||
consul_utils.waitForValue('polling_test/master/sample_key', function(err) { | ||
if (err) return done(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it ('should handle polling updates', function(done) { | ||
var repo_name = git_utils.repo.name; | ||
var sample_key = 'sample_key'; | ||
var sample_value = 'stash test data'; | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Webhook.", false, function(err) { | ||
describe('no daemon mode', function() { | ||
// No daemon mode works by disabling hooks. Validate that no_daemon mode is enabled by attempting to start | ||
// a repo with hooks and checking that no hooks are actually running. | ||
it ('should disable hooks', function(done) { | ||
var repo_config = git_utils.createRepoConfig(); | ||
repo_config.hooks = [{ | ||
'type': 'polling', | ||
'interval': '1' | ||
},{ | ||
'type': 'stash', | ||
'url': '/stashpoke_bogus_branch', | ||
'port': 5253 | ||
}]; | ||
repo_config.name = "you_shall_not_hook"; | ||
git_commands.init(git_utils.TEST_REMOTE_REPO, function(err) { | ||
if (err) return done(err); | ||
consul_utils.waitForValue(repo_name + '/master/sample_key', function(err) { | ||
var sample_key = 'readme.md'; | ||
var sample_value = 'stub data'; | ||
git_utils.addFileToGitRepo(sample_key, sample_value, "Stub commit.", function(err) { | ||
if (err) return done(err); | ||
done(); | ||
var config = { | ||
repos: [repo_config], | ||
local_store: git_utils.TEST_WORKING_DIR, | ||
no_daemon: true | ||
}; | ||
// Now, create a repo with hooks. The hooks should not be active due to no_daemon mode. | ||
git.createRepos(config, function(err) { | ||
(undefined === err).should.equal(true); | ||
var repo = git.repos['you_shall_not_hook']; | ||
(undefined === repo.hooks_active).should.equal(true); | ||
done(); | ||
}); | ||
}); | ||
@@ -292,0 +330,0 @@ }); |
@@ -8,22 +8,8 @@ var fs = require('fs'); | ||
exports.TEST_REMOTE_REPO = '/tmp/test_repo/'; | ||
exports.TEST_GITHUB_REPO = 'https://github.com/ryanbreen/git2consul_data.git'; | ||
exports.TEST_WORKING_DIR = '/tmp/test_workspace/'; | ||
exports.TEST_GITHUB_WORKING_DIR = '/tmp/test_github_workspace/'; | ||
var repo_counter = 0; | ||
exports.createConfig = function() { | ||
return { | ||
local_store: exports.TEST_WORKING_DIR, | ||
repos: [ | ||
exports.createRepoConfig() | ||
] | ||
}; | ||
}; | ||
exports.createRepoConfig = function() { | ||
++repo_counter; | ||
return { | ||
local_store: exports.TEST_WORKING_DIR, | ||
name: 'test_repo' + repo_counter, | ||
name: 'test_repo', | ||
url: 'file://' + exports.TEST_REMOTE_REPO, | ||
@@ -34,2 +20,5 @@ branches: [ 'master' ] | ||
/** | ||
* Initialize a repo and return it in a callback. | ||
*/ | ||
exports.initRepo = function(repo_config, cb) { | ||
@@ -44,12 +33,17 @@ | ||
if (err) return cb(err); | ||
exports.addFileToGitRepo("readme.md", "Stub file to give us something to commit.", "Init repo.", false, function(err) { | ||
// When we create a repo, we need it to have an initial commit. The call to addFile provides that. | ||
exports.addFileToGitRepo("readme.md", "Stub file to give us something to commit.", "Init repo.", function(err) { | ||
if (err) return cb(err); | ||
repo_config.local_store = exports.TEST_WORKING_DIR; | ||
exports.repo = new Repo(repo_config); | ||
git.repos[repo_config.name] = exports.repo; | ||
exports.repo.init(function(err) { | ||
var repo = new Repo(repo_config); | ||
// Register this repo such that graceful shutdown checks in the git module work. | ||
git.repos[repo_config.name] = repo; | ||
repo.init(function(err) { | ||
if (err) return cb(err); | ||
cb(null); | ||
cb(null, repo); | ||
}); | ||
@@ -60,9 +54,4 @@ }); | ||
exports.addFileToGitRepo = function(name, content, commit_message, update, cb) { | ||
exports.addFileToGitRepo = function(name, content, commit_message, cb) { | ||
if (!cb) { | ||
cb = update; | ||
update = true; | ||
} | ||
fs.writeFile(exports.TEST_REMOTE_REPO + name, content, function(err) { | ||
@@ -76,11 +65,3 @@ if (err) return cb(err); | ||
if (err) return cb(err); | ||
if (update) { | ||
exports.repo.branches['master'].handleRefChange(0, function(err) { | ||
if (err) return cb(err); | ||
cb(); | ||
}); | ||
} else { | ||
cb(); | ||
} | ||
cb(); | ||
}); | ||
@@ -91,9 +72,4 @@ }); | ||
exports.deleteFileFromGitRepo = function(name, commit_message, update, cb) { | ||
exports.deleteFileFromGitRepo = function(name, commit_message, cb) { | ||
if (!cb) { | ||
cb = update; | ||
update = true; | ||
} | ||
git_commands.delete(name, exports.TEST_REMOTE_REPO, function(err) { | ||
@@ -104,11 +80,3 @@ if (err) return cb(err); | ||
if (err) return cb(err); | ||
if (update) { | ||
exports.repo.branches['master'].handleRefChange(0, function(err) { | ||
if (err) return cb(err); | ||
cb(); | ||
}); | ||
} else { | ||
cb(); | ||
} | ||
cb(); | ||
}); | ||
@@ -118,9 +86,4 @@ }); | ||
exports.moveFileInGitRepo = function(old_name, new_name, commit_message, update, cb) { | ||
exports.moveFileInGitRepo = function(old_name, new_name, commit_message, cb) { | ||
if (!cb) { | ||
cb = update; | ||
update = true; | ||
} | ||
git_commands.mv(old_name, new_name, exports.TEST_REMOTE_REPO, function(err) { | ||
@@ -131,10 +94,3 @@ if (err) return cb(err); | ||
if (err) return cb(err); | ||
if (update) { | ||
exports.repo.branches['master'].handleRefChange(0, function(err) { | ||
if (err) return cb(err); | ||
cb(); | ||
}); | ||
} else { | ||
cb(); | ||
} | ||
cb(); | ||
}); | ||
@@ -144,9 +100,4 @@ }); | ||
exports.symlinkFileInGitRepo = function(link, referrent, commit_message, update, cb) { | ||
exports.symlinkFileInGitRepo = function(link, referrent, commit_message, cb) { | ||
if (!cb) { | ||
cb = update; | ||
update = true; | ||
} | ||
fs.rename(exports.TEST_REMOTE_REPO + link, exports.TEST_REMOTE_REPO + referrent, function(err) { | ||
@@ -166,10 +117,3 @@ if (err) return cb(err); | ||
if (err) return cb(err); | ||
if (update) { | ||
exports.repo.branches['master'].handleRefChange(0, function(err) { | ||
if (err) return cb(err); | ||
cb(); | ||
}); | ||
} else { | ||
cb(); | ||
} | ||
cb(); | ||
}); | ||
@@ -176,0 +120,0 @@ }); |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
97697
33
2132
24