This repository has been archived by the owner on Mar 14, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 22
Mosa 130/sync chain data #146
Merged
Merged
Changes from 3 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
820d385
Sync service to sync data from geth leveldb to local folder
6765e44
Added Rsync service logic for remote sync aswell
69fb11c
Added comments, unit tests and test dependency
a312071
Refactoring - Directly exposing the class and Added comments on path …
c886532
Added example to call service on CONFIGURE.md
7452873
Freezing version of dependency in package.json
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
const Rsync = require('rsync'); | ||
|
||
const rootPrefix = "../.." | ||
, basicHelper = require(rootPrefix + '/helpers/basic_helper') | ||
, responseHelper = require(rootPrefix + '/lib/formatter/response') | ||
, logger = require(rootPrefix + '/helpers/custom_console_logger') | ||
; | ||
|
||
//az is rsync flag where z represents compression and a stands for "archive" and syncs recursively and | ||
// preserves symbolic links, special and device files, modification times, group, owner, and permissions | ||
const defaultFlag = 'az'; | ||
|
||
/** | ||
* @notice For remote Sync specify user,host and path in sourceConfig/destinationConfig, for local sync dont add user and host key | ||
* | ||
* @dev Key pair based ssh needs to setup for remote rsync | ||
* | ||
* @param sourceConfig object {user:'source_user', host:'10.1.2.2', path:'~/temp'} | ||
* @param destinationConfig object {user:'destination_user', host:'10.1.2.3', path:'~/temp'} | ||
* | ||
* @constructor | ||
* | ||
* Example: | ||
* | ||
* let sourceConfig = { | ||
* user: "user", | ||
* host: "10.1.1.1", | ||
* path: "~/tmp" | ||
* }, | ||
* destinationConfig = { | ||
* path: "~/tmp" | ||
* }, | ||
* let syncInstance = new SyncKlass(sourceConfig, destinationConfig); | ||
* syncInstance.perform( result =>{ | ||
* //Logic on success | ||
* }); | ||
* //if source / destination is local then user or path key in config can be skipped | ||
*/ | ||
function SyncKlass(sourceConfig, destinationConfig) { | ||
let oThis = this; | ||
|
||
oThis.source = oThis._formatPath(sourceConfig); | ||
oThis.destination = oThis._formatPath(destinationConfig); | ||
} | ||
|
||
SyncKlass.prototype = { | ||
/** | ||
* Sync source folder to destination folder | ||
* | ||
* @return {Promise<result>} | ||
*/ | ||
perform: function () { | ||
let oThis = this; | ||
|
||
return oThis._sync(); | ||
}, | ||
/** | ||
* Sync source folder to destination folder | ||
* | ||
* @return {Promise<result>} | ||
* @private | ||
*/ | ||
_sync: async function () { | ||
let oThis = this; | ||
|
||
await oThis._validate(); | ||
|
||
oThis.rsync = new Rsync(); | ||
oThis.rsync.flags(defaultFlag) | ||
.source(oThis.source) | ||
.destination(oThis.destination); | ||
|
||
return new Promise(function (resolve, reject) { | ||
oThis.rsync.execute(function (error, code, cmd) { | ||
if (error) { | ||
|
||
logger.error(error); | ||
let responseError = responseHelper.error({ | ||
internal_error_identifier: 's_s_sync_validate_1', | ||
api_error_identifier: 'rsync_failed', | ||
error_config: basicHelper.fetchErrorConfig(), | ||
debug: {error} | ||
}); | ||
reject(responseError); | ||
} | ||
resolve(responseHelper.successWithData({ | ||
statusCode: code, | ||
cmd: cmd | ||
})) | ||
}); | ||
}); | ||
}, | ||
/** | ||
* Input validations | ||
* | ||
* @private | ||
*/ | ||
_validate: async function () { | ||
let oThis = this; | ||
|
||
let errorConf = { | ||
internal_error_identifier: "s_s_val_validate_2", | ||
debug_options: {}, | ||
error_config: basicHelper.fetchErrorConfig() | ||
}; | ||
|
||
if (!oThis.source) { | ||
logger.error("Sync source is not defined"); | ||
errorConf.api_error_identifier = "sync_source_undefined"; | ||
let errorResponse = responseHelper.error(errorConf); | ||
return Promise.reject(errorResponse); | ||
} | ||
|
||
if (!oThis.destination) { | ||
logger.error("Sync destination is not defined"); | ||
errorConf.api_error_identifier = "sync_destination_undefined"; | ||
let errorResponse = responseHelper.error(errorConf); | ||
return Promise.reject(errorResponse); | ||
} | ||
}, | ||
|
||
/** | ||
* @param origin source/destination | ||
* | ||
* @return {string} formatted path of source/destination | ||
* | ||
* @private | ||
*/ | ||
_formatPath: function (origin) { | ||
|
||
let user = origin.user; | ||
let host = origin.host; | ||
let path = origin.path; | ||
if (!user || !host) { | ||
return path; | ||
} | ||
return path ? `${user}@${host}:${path}` : path; | ||
} | ||
|
||
}; | ||
|
||
module.exports = SyncKlass; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
const assert = require('assert') | ||
|
||
, sinon = require('sinon') | ||
, mock = require('mock-require') | ||
; | ||
const rootPrefix = '../..' | ||
; | ||
|
||
|
||
describe('Sync service', function () { | ||
let RSyncStub, cb, errorCode; | ||
|
||
before(function () { | ||
|
||
RSyncStub = sinon.spy(); | ||
let instance = new RSyncStub() | ||
RSyncStub.prototype.flags = sinon.stub().returns(instance); | ||
RSyncStub.prototype.source = sinon.stub().returns(instance); | ||
RSyncStub.prototype.destination = sinon.stub().returns(instance); | ||
RSyncStub.prototype.execute = function (cb) { | ||
cb(errorCode, 0); | ||
}; | ||
mock('rsync', RSyncStub); | ||
SyncKlass = require(rootPrefix + '/services/sync/sync') | ||
cb = function (error, code, cmd) { | ||
//placeholder callback function | ||
}; | ||
}); | ||
|
||
it('should not sync data is source path is missing ', async function () { | ||
let sourceConfig = { | ||
user: "user", | ||
host: "10.1.1.1", | ||
}, | ||
destinationConfig = { | ||
path: "~/tmp" | ||
}; | ||
|
||
let syncService = new SyncKlass(sourceConfig, destinationConfig); | ||
|
||
try { | ||
await syncService.perform(); | ||
} catch (error) { | ||
assert.equal(error.apiErrorIdentifier, 'sync_source_undefined') | ||
} | ||
}); | ||
|
||
|
||
it('should not sync data is destination path is missing ', async function () { | ||
let sourceConfig = { | ||
user: "user", | ||
host: "10.1.1.1", | ||
path: "~/tmp" | ||
}, | ||
destinationConfig = {}; | ||
let syncService = new SyncKlass(sourceConfig, destinationConfig); | ||
|
||
try { | ||
await syncService.perform(); | ||
} catch (error) { | ||
assert.equal(error.apiErrorIdentifier, 'sync_destination_undefined') | ||
} | ||
}); | ||
|
||
|
||
it('should format path for local path', async function () { | ||
let path = "~/tmp"; | ||
let sourceConfig = { | ||
path: path | ||
}, | ||
destinationConfig = {}; | ||
|
||
let syncService = new SyncKlass(sourceConfig, destinationConfig); | ||
|
||
let formatPath = syncService._formatPath(sourceConfig); | ||
assert.equal(formatPath, path); | ||
|
||
}); | ||
|
||
it('should format path for remote path', async function () { | ||
let path = "~/tmp" | ||
, host = "10.1.1.1" | ||
, user = "user"; | ||
let sourceConfig = { | ||
user: user, | ||
host: host, | ||
path: path | ||
}, | ||
destinationConfig = {}; | ||
|
||
let syncService = new SyncKlass(sourceConfig, destinationConfig); | ||
let formatPath = syncService._formatPath(sourceConfig); | ||
assert.equal(formatPath, `${user}@${host}:${path}`); | ||
}); | ||
|
||
it('should form correct rsync command', async function () { | ||
|
||
let sourceConfig = { | ||
user: "user", | ||
host: "10.1.1.1", | ||
path: "~/tmp" | ||
}, | ||
destinationConfig = { | ||
path: "~/tmp" | ||
}, | ||
syncService = new SyncKlass(sourceConfig, destinationConfig); | ||
|
||
await syncService.perform(); | ||
assert.equal(RSyncStub.prototype.flags.called, true); | ||
assert.equal(RSyncStub.prototype.source.called, true); | ||
assert.equal(RSyncStub.prototype.destination.called, true); | ||
}); | ||
|
||
|
||
it('should fail if rync fails ', async function () { | ||
|
||
let sourceConfig = { | ||
user: "user", | ||
host: "10.1.1.1", | ||
path: "~/tmp" | ||
}, | ||
destinationConfig = { | ||
path: "~/tmp" | ||
}, | ||
syncService = new SyncKlass(sourceConfig, destinationConfig); | ||
errorCode = 1; | ||
|
||
try { | ||
await syncService.perform(); | ||
} | ||
catch (error) { | ||
|
||
assert.equal(error.apiErrorIdentifier, 'rsync_failed'); | ||
assert.equal(RSyncStub.prototype.flags.called, true); | ||
assert.equal(RSyncStub.prototype.source.called, true); | ||
assert.equal(RSyncStub.prototype.destination.called, true); | ||
} | ||
}); | ||
|
||
|
||
it('should return success if rsync was success ', async function () { | ||
|
||
let sourceConfig = { | ||
user: "user", | ||
host: "10.1.1.1", | ||
path: "~/tmp" | ||
}, | ||
destinationConfig = { | ||
path: "~/tmp" | ||
}, | ||
syncService = new SyncKlass(sourceConfig, destinationConfig); | ||
errorCode = undefined; | ||
|
||
let result = await syncService.perform(); | ||
|
||
assert.equal(result.success, true); | ||
assert.equal(RSyncStub.prototype.flags.called, true); | ||
assert.equal(RSyncStub.prototype.source.called, true); | ||
assert.equal(RSyncStub.prototype.destination.called, true); | ||
}); | ||
}); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pls freeze version