public void GetChunk_MiddleBytes_Ok() { using (var e = new PushStorageEnvForTest()) { string text = "This is some sample text to be used by the push bundle helper tests"; var bundleHelper = new PushStorageManager(e.PullDataFolderPath, "randomHash"); File.WriteAllText(bundleHelper.BundlePath, text); byte[] chunk = bundleHelper.GetChunk(10, 5); Assert.That(Encoding.UTF8.GetString(chunk), Is.EqualTo("me sa")); } }
public void GetChunk_LengthTooLarge_ReturnsAdjustedByteArray() { using (var e = new PushStorageEnvForTest()) { string text = "sample"; var bundleHelper = new PushStorageManager(e.PullDataFolderPath, "randomHash"); File.WriteAllText(bundleHelper.BundlePath, text); byte[] chunk = bundleHelper.GetChunk(3, 10); // offset is greater than string length Assert.That(Encoding.UTF8.GetString(chunk), Is.EqualTo("ple")); } }
public void Push() { var baseRevisions = GetCommonBaseHashesWithRemoteRepo(); if (baseRevisions == null) { const string errorMessage = "Push failed: A common revision could not be found with the server."; _progress.WriteError(errorMessage); throw new HgResumeOperationFailed(errorMessage); } // create a bundle to push var bundleHelper = new PushStorageManager(PathToLocalStorage, GetBundleIdFilenameBase("push", baseRevisions.Select(rev => rev.Number.Hash), _repo.GetTip().Number.Hash)); var bundleFileInfo = new FileInfo(bundleHelper.BundlePath); if (bundleFileInfo.Length == 0) { _progress.WriteStatus("Preparing data to send"); bool bundleCreatedSuccessfully = _repo.MakeBundle(GetHashStringsFromRevisions(baseRevisions), bundleHelper.BundlePath); if (!bundleCreatedSuccessfully) { // try again after clearing revision cache LastKnownCommonBases = new List <Revision>(); baseRevisions = GetCommonBaseHashesWithRemoteRepo(); bundleCreatedSuccessfully = _repo.MakeBundle(GetHashStringsFromRevisions(baseRevisions), bundleHelper.BundlePath); if (!bundleCreatedSuccessfully) { const string errorMessage = "Push failed: Unable to create local bundle."; _progress.WriteError(errorMessage); throw new HgResumeOperationFailed(errorMessage); } } bundleFileInfo.Refresh(); if (bundleFileInfo.Length == 0) { bundleHelper.Cleanup(); _progress.WriteMessage("No changes to send. Push operation completed"); return; } } var req = new HgResumeApiParameters { RepoId = _apiServer.ProjectId, TransId = bundleHelper.TransactionId, StartOfWindow = 0, BundleSize = (int)bundleFileInfo.Length }; req.ChunkSize = (req.BundleSize < InitialChunkSize) ? req.BundleSize : InitialChunkSize; // req.BaseHash = baseRevisions; <-- Unless I'm not reading the php right we don't need to set this on push. JLN Aug-12 _progress.ProgressIndicator.Initialize(); _progress.WriteStatus("Sending data"); int loopCtr = 0; do // loop until finished... or until the user cancels { loopCtr++; if (_progress.CancelRequested) { throw new UserCancelledException(); } int dataRemaining = req.BundleSize - req.StartOfWindow; if (dataRemaining < req.ChunkSize) { req.ChunkSize = dataRemaining; } byte[] bundleChunk = bundleHelper.GetChunk(req.StartOfWindow, req.ChunkSize); /* API parameters * $repoId, $baseHash, $bundleSize, $offset, $data, $transId * */ var response = PushOneChunk(req, bundleChunk); if (response.Status == PushStatus.NotAvailable) { _progress.ProgressIndicator.Initialize(); _progress.ProgressIndicator.Finish(); return; } if (response.Status == PushStatus.Timeout) { _progress.WriteWarning("Push operation timed out. Retrying..."); continue; } if (response.Status == PushStatus.InvalidHash) { // this should not happen...but sometimes it gets into a state where it remembers the wrong basehash of the server (CJH Feb-12) _progress.WriteVerbose("Invalid basehash response received from server... clearing cache and retrying"); // req.BaseHash = GetCommonBaseHashesWithRemoteRepo(false); <-- Unless I'm misreading the php we don't need to set this on a push. JLN Aug-12 continue; } if (response.Status == PushStatus.Fail) { // This 'Fail' intentionally aborts the push attempt. I think we can continue to go around the loop and retry. See Pull also. CP 2012-06 continue; //var errorMessage = "Push operation failed"; //_progress.WriteError(errorMessage); //throw new HgResumeOperationFailed(errorMessage); } if (response.Status == PushStatus.Reset) { FinishPush(req.TransId); bundleHelper.Cleanup(); const string errorMessage = "Push failed: Server reset."; _progress.WriteError(errorMessage); throw new HgResumeOperationFailed(errorMessage); } if (response.Status == PushStatus.Complete || req.StartOfWindow >= req.BundleSize) { if (response.Status == PushStatus.Complete) { _progress.WriteMessage("Finished sending"); } else { _progress.WriteMessage("Finished sending. Server unpacking data"); } _progress.ProgressIndicator.Finish(); // update our local knowledge of what the server has LastKnownCommonBases = new List <Revision>(_repo.BranchingHelper.GetBranches()); // This may be a little optimistic, the server may still be unbundling the data. //FinishPush(req.TransId); // We can't really tell when the server has finished processing our pulled data. The server cleans up after itself. CP 2012-07 bundleHelper.Cleanup(); return; } req.ChunkSize = response.ChunkSize; req.StartOfWindow = response.StartOfWindow; if (loopCtr == 1 && req.StartOfWindow > req.ChunkSize) { string message = String.Format("Resuming push operation at {0} sent", GetHumanReadableByteSize(req.StartOfWindow)); _progress.WriteVerbose(message); } string eta = CalculateEstimatedTimeRemaining(req.BundleSize, req.ChunkSize, req.StartOfWindow); _progress.WriteStatus(string.Format("Sending {0} {1}", GetHumanReadableByteSize(req.BundleSize), eta)); _progress.ProgressIndicator.PercentCompleted = (int)((long)req.StartOfWindow * 100 / req.BundleSize); } while (req.StartOfWindow < req.BundleSize); }
public PullHandlerApiServerForTest(HgRepository repo, ProgressForTest progress) { const string identifier = "PullHandlerApiServerForTest"; _storageFolder = new TemporaryFolder(identifier); _repo = repo; _progress = progress; _helper = new PushStorageManager(_storageFolder.Path, "randomHash"); Host = identifier; ProjectId = "SampleProject"; _executeCount = 0; _failCount = -1; _timeoutList = new List<int>(); _serverUnavailableList = new List<ServerUnavailableResponse>(); OriginalTip = ""; }
public void Push() { var baseRevisions = GetCommonBaseHashesWithRemoteRepo(); if (baseRevisions == null) { const string errorMessage = "Push failed: A common revision could not be found with the server."; _progress.WriteError(errorMessage); throw new HgResumeOperationFailed(errorMessage); } // create a bundle to push string tip = _repo.GetTip().Number.Hash; string bundleId = ""; foreach (var revision in baseRevisions) { bundleId += String.Format("{0}-{1}", revision.Number.Hash, tip); } var bundleHelper = new PushStorageManager(PathToLocalStorage, bundleId); var bundleFileInfo = new FileInfo(bundleHelper.BundlePath); if (bundleFileInfo.Length == 0) { _progress.WriteStatus("Preparing data to send"); bool bundleCreatedSuccessfully = _repo.MakeBundle(GetHashStringsFromRevisions(baseRevisions), bundleHelper.BundlePath); if (!bundleCreatedSuccessfully) { // try again after clearing revision cache LastKnownCommonBases = new List<Revision>(); baseRevisions = GetCommonBaseHashesWithRemoteRepo(); bundleCreatedSuccessfully = _repo.MakeBundle(GetHashStringsFromRevisions(baseRevisions), bundleHelper.BundlePath); if (!bundleCreatedSuccessfully) { const string errorMessage = "Push failed: Unable to create local bundle."; _progress.WriteError(errorMessage); throw new HgResumeOperationFailed(errorMessage); } } bundleFileInfo.Refresh(); if (bundleFileInfo.Length == 0) { bundleHelper.Cleanup(); _progress.WriteMessage("No changes to send. Push operation completed"); return; } } var req = new HgResumeApiParameters { RepoId = _apiServer.ProjectId, TransId = bundleHelper.TransactionId, StartOfWindow = 0, BundleSize = (int) bundleFileInfo.Length }; req.ChunkSize = (req.BundleSize < InitialChunkSize) ? req.BundleSize : InitialChunkSize; // req.BaseHash = baseRevisions; <-- Unless I'm not reading the php right we don't need to set this on push. JLN Aug-12 _progress.ProgressIndicator.Initialize(); _progress.WriteStatus("Sending data"); int loopCtr = 0; do // loop until finished... or until the user cancels { loopCtr++; if (_progress.CancelRequested) { throw new UserCancelledException(); } int dataRemaining = req.BundleSize - req.StartOfWindow; if (dataRemaining < req.ChunkSize) { req.ChunkSize = dataRemaining; } byte[] bundleChunk = bundleHelper.GetChunk(req.StartOfWindow, req.ChunkSize); /* API parameters * $repoId, $baseHash, $bundleSize, $offset, $data, $transId * */ var response = PushOneChunk(req, bundleChunk); if (response.Status == PushStatus.NotAvailable) { _progress.ProgressIndicator.Initialize(); _progress.ProgressIndicator.Finish(); return; } if (response.Status == PushStatus.Timeout) { _progress.WriteWarning("Push operation timed out. Retrying..."); continue; } if (response.Status == PushStatus.InvalidHash) { // this should not happen...but sometimes it gets into a state where it remembers the wrong basehash of the server (CJH Feb-12) _progress.WriteVerbose("Invalid basehash response received from server... clearing cache and retrying"); // req.BaseHash = GetCommonBaseHashesWithRemoteRepo(false); <-- Unless I'm misreading the php we don't need to set this on a push. JLN Aug-12 continue; } if (response.Status == PushStatus.Fail) { // This 'Fail' intentionally aborts the push attempt. I think we can continue to go around the loop and retry. See Pull also. CP 2012-06 continue; //var errorMessage = "Push operation failed"; //_progress.WriteError(errorMessage); //throw new HgResumeOperationFailed(errorMessage); } if (response.Status == PushStatus.Reset) { FinishPush(req.TransId); bundleHelper.Cleanup(); const string errorMessage = "Push failed: Server reset."; _progress.WriteError(errorMessage); throw new HgResumeOperationFailed(errorMessage); } if (response.Status == PushStatus.Complete || req.StartOfWindow >= req.BundleSize) { if (response.Status == PushStatus.Complete) { _progress.WriteMessage("Finished sending"); } else { _progress.WriteMessage("Finished sending. Server unpacking data"); } _progress.ProgressIndicator.Finish(); // update our local knowledge of what the server has LastKnownCommonBases = new List<Revision>(_repo.BranchingHelper.GetBranches()); // This may be a little optimistic, the server may still be unbundling the data. //FinishPush(req.TransId); // We can't really tell when the server has finished processing our pulled data. The server cleans up after itself. CP 2012-07 bundleHelper.Cleanup(); return; } req.ChunkSize = response.ChunkSize; req.StartOfWindow = response.StartOfWindow; if (loopCtr == 1 && req.StartOfWindow > req.ChunkSize) { string message = String.Format("Resuming push operation at {0} sent", GetHumanReadableByteSize(req.StartOfWindow)); _progress.WriteVerbose(message); } string eta = CalculateEstimatedTimeRemaining(req.BundleSize, req.ChunkSize, req.StartOfWindow); _progress.WriteStatus(string.Format("Sending {0} {1}", GetHumanReadableByteSize(req.BundleSize), eta)); _progress.ProgressIndicator.PercentCompleted = (int)((long)req.StartOfWindow * 100 / req.BundleSize); } while (req.StartOfWindow < req.BundleSize); }
public void GetChunk_OffsetOutOfRange_EmptyByteArray() { using (var e = new PushStorageEnvForTest()) { string text = "sample"; var bundleHelper = new PushStorageManager(e.PullDataFolderPath, "randomHash"); File.WriteAllText(bundleHelper.BundlePath, text); byte[] chunk = bundleHelper.GetChunk(10, 5); // offset is greater than string length Assert.That(chunk.Length, Is.EqualTo(0)); } }