public void ProcessChangeSet_update_dirty_invokes_successful_resolver_and_successful_retry() { var repo = A.Fake<IRepository<Asset, int>>(); var context = A.Fake<IDataContext>(); var resolver = A.Fake<IConflictResolver>(); var bfim = A.Dummy<Models.Asset>(); var afim = A.Dummy<Models.Asset>(); var cs = new ChangeSet() { Assets = new List<ChangeItem<Models.Asset>>{ new ChangeItem<Models.Asset>{ Action = ChangeAction.Update, BFIM = bfim, AFIM = afim } } }; A.CallTo(() => repo.KeySelector).Returns((Asset a) => a.Id); A.CallTo(() => context.Assets).Returns(repo); A.CallTo(() => context.AcceptChanges()).Throws(new ConcurrencyException()).Once(); A.CallTo(() => resolver.Resolve(repo, A<ChangeItem<Asset>>.Ignored, A<IDictionary<int,Asset>>.Ignored)).Returns(true); var processor = new ChangeSetProcessor(context, resolver); var result = processor.Process(1, false, cs); Assert.IsTrue(result.IsEmpty); Assert.AreEqual(ChangeSet.Empty, result); A.CallTo(() => context.Assets.Update(afim)).MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => context.AcceptChanges()).MustHaveHappened(Repeated.Exactly.Twice); }
public void ProcessChangeSet_update_cleanly_completes_without_error() { var context = A.Fake<IDataContext>(); var resolver = A.Fake<IConflictResolver>(); var bfim = A.Dummy<Models.Asset>(); var afim = A.Dummy<Models.Asset>(); var cs = new ChangeSet() { Assets = new List<ChangeItem<Models.Asset>>{ new ChangeItem<Models.Asset>{ Action = ChangeAction.Update, BFIM = bfim, AFIM = afim } } }; var processor = new ChangeSetProcessor(context, resolver); var result = processor.Process(1, false, cs); ExceptionAssert.Throws<ArgumentNullException>(() => processor.Process(1, false, null)); Assert.IsTrue(result.IsEmpty); Assert.AreEqual(ChangeSet.Empty, result); A.CallTo(() => context.Assets.Update(A<Models.Asset>.Ignored)).MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => context.Assets.Update(afim)).MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => context.AcceptChanges()).MustHaveHappened(Repeated.Exactly.Once); }
private IHttpActionResult Conflict(ChangeSet changeSet) { if (changeSet == null || changeSet.IsEmpty) return Conflict(); else return ResponseMessage( Request.CreateResponse( HttpStatusCode.Conflict, changeSet)); }
public void ProcessChangeSet_update_dirty_invokes_unsuccessful_merge_and_no_retry() { var repo = A.Fake<IRepository<Asset, int>>(); var context = A.Fake<IDataContext>(); var resolver = new RejectConcurrentEditsConflictResolver(); var afim = A.Dummy<Models.Asset>(); var cs = new ChangeSet() { Assets = new List<ChangeItem<Models.Asset>>{ new ChangeItem<Models.Asset>{ Action = ChangeAction.Update, BFIM = A.Dummy<Models.Asset>(), AFIM = afim } } }; A.CallTo(() => repo.KeySelector).Returns((Asset a) => a.Id); A.CallTo(() => context.Assets).Returns(repo); A.CallTo(() => context.AcceptChanges()).Throws(new ConcurrencyException()).Once(); var processor = new ChangeSetProcessor(context, resolver); var result = processor.Process(1, false, cs); Assert.IsFalse(result.IsEmpty); Assert.AreNotEqual(ChangeSet.Empty, result); A.CallTo(() => context.Assets.Update(afim)).MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => context.AcceptChanges()).MustHaveHappened(Repeated.Exactly.Once); }
public void ProcessChangeSet_which_locks_retains_lock_on_failed_merge() { var job = new Job() { Id = 42 }; var context = A.Fake<IDataContext>(); var resolver = A.Fake<IConflictResolver>(); var bfim = A.Dummy<Models.Asset>(); var afim = A.Dummy<Models.Asset>(); var cs = new ChangeSet() { Assets = new List<ChangeItem<Models.Asset>>{ new ChangeItem<Models.Asset>(ChangeAction.Update,bfim,afim), new ChangeItem<Models.Asset>(ChangeAction.Delete,A.Dummy<Asset>(),null), new ChangeItem<Models.Asset>(ChangeAction.Create,null, A.Dummy<Asset>()) } }; A.CallTo(() => resolver.Resolve(A<IRepository<Asset, int>>.Ignored, A<ChangeItem<Asset>>.Ignored, A<IDictionary<int, Asset>>.Ignored)).Returns(false); A.CallTo(() => context.Jobs.GetById(A<int>.Ignored)).Returns(job); A.CallTo(() => context.Assets.KeySelector).Returns((Asset a) => a.Id); A.CallTo(() => context.AcceptChanges()).Throws(new ConcurrencyException()); A.CallTo(() => context.AcceptChanges()).DoesNothing().Once(); var processor = new ChangeSetProcessor(context, resolver); var result = processor.Process(1, true, cs); Assert.IsFalse(result.IsEmpty); Assert.AreNotEqual(ChangeSet.Empty, result); A.CallTo(() => context.Assets.Update(afim)).MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => context.AcceptChanges()).MustHaveHappened(Repeated.Exactly.Twice); A.CallTo(() => resolver.Resolve(A<IRepository<Asset, int>>.Ignored, A<ChangeItem<Asset>>.Ignored, A<IDictionary<int, Asset>>.Ignored)).MustHaveHappened(Repeated.Exactly.Once); //Assert.IsNotNull(job.LockedBy); // disabling this check temporarily this functionality was designed around EF and transaction rollbacks }
private void Touch(int jobid, ChangeSet cs) { var im = cs.Assets.First(_ => _.BFIM != null).BFIM; s_rng.NextBytes(im.RowVersion); }
private ChangeSet BuildChangeSet(int jobId) { var dc = new Rel.Data.Ef6.TpContext(); IList<Asset> assets; int count; using (var scope = new TransactionScope()) { int take = s_rng.Next(s_minCsSize, s_maxCsSize); assets = dc.Database.SqlQuery<Asset>( @"SELECT Id ,JobId ,Name ,RowVersion ,ServiceArea ,PercentTolerance ,StaticTolerance ,MonotonicTolerance ,MaximumAndMinimumDecay ,MaxMinDecayWithStepAndTol ,MinimumDecay FROM ( SELECT * FROM dbo.Asset WITH(NOLOCK) WHERE JobId=@p0 ) a ORDER BY PercentTolerance ASC OFFSET 0 ROWS FETCH NEXT @p1 ROWS ONLY", jobId, take).ToList(); count = dc.Database.SqlQuery<int>(@"SELECT COUNT(Id) FROM dbo.Asset WITH(NOLOCK) WHERE JobId=@p0", jobId).Single(); scope.Complete(); } var cs = new ChangeSet() { Assets = assets .Select(ModifyAsset) .Union(NewAssets(jobId, s_rng.Next(1, (int)Math.Ceiling(assets.Count * 0.3)))).ToList() }; s_assetCount[jobId - 1].IncrementBy(count); s_assetCountBase[jobId - 1].Increment(); return cs; }