public void ShouldNotAllowNewChangeSaveOperationBeforePreviousOneCompletes() { var apiShouldEnter = new AutoResetEvent(initialState: false); var bulkUpdateCalled = 0; IDictionary <string, DocumentInfo> returnInfo = new Dictionary <string, DocumentInfo> { { SimpleEntity.StandardDocId, new DocumentInfo(SimpleEntity.StandardDocId, "2-cc2c5ab22cfa4a0faad27a0cb9ca7968") } }; var dbApiMock = new Mock <IDatabaseApi>(); dbApiMock .Setup(couchApi => couchApi.BulkUpdate(It.IsAny <Action <IBulkUpdateBatch> >())) .Returns <Action <IBulkUpdateBatch> >( updater => Task.Factory.StartNew( () => { apiShouldEnter.WaitOne(); Interlocked.Increment(ref bulkUpdateCalled); updater(Mock.Of <IBulkUpdateBatch>()); return(returnInfo); }, TaskCreationOptions.PreferFairness ) ); ISession sesion = new CouchSession(Default.Settings, Mock.Of <ICouchApi>(c => c.Db("testdb") == dbApiMock.Object)); var entity = SimpleEntity.CreateStandardWithoutRevision(); sesion.Save(entity); var firstSaveChangesTask = sesion.StartSavingChanges(); // Enters API method Thread.Sleep(500); // Allowing first task to arrive to apiShouldEnter wating line first var secondSaveChangesTask = sesion.StartSavingChanges(); // Waits for first task to end Assert.Equal(0, bulkUpdateCalled); apiShouldEnter.Set(); firstSaveChangesTask.WaitOrThrowOnTimeout(); Assert.Equal(1, bulkUpdateCalled); entity.Age--; // Modifing entity for second save to be applicable apiShouldEnter.Set(); // Permitting second API method call to proceed secondSaveChangesTask.WaitOrThrowOnTimeout(); Assert.Equal(2, bulkUpdateCalled); Assert.Equal("2-cc2c5ab22cfa4a0faad27a0cb9ca7968", entity.Revision); }
public void ShouldDelegateChangesSaveToApi() { var couchApi = Mock.Of <ICouchApi>( c => c.Db("testdb") == Mock.Of <IDatabaseApi>( d => d.BulkUpdate(It.IsAny <Action <IBulkUpdateBatch> >()) == new Dictionary <string, DocumentInfo>().ToTask <IDictionary <string, DocumentInfo> >() ) ); ISession sesion = new CouchSession(Default.Settings, couchApi); sesion.Save(SimpleEntity.CreateStandardWithoutRevision()); sesion.SaveChanges(); Mock.Get(couchApi.Db("testdb")).Verify(dbApi => dbApi.BulkUpdate(It.IsAny <Action <IBulkUpdateBatch> >()), Times.Once()); }
public void ShouldSaveNewDocuments() { unitOfWork.AddNew(SimpleEntity.CreateStandardWithoutRevision()); Document savedDoc = null; var bulkUpdateUnitOfWorkMock = new Mock <IBulkUpdateBatch>(MockBehavior.Strict); bulkUpdateUnitOfWorkMock .Setup(u => u.Create(It.IsAny <Document>())) .Callback <Document>(d => { savedDoc = d; }); unitOfWork.ApplyChanges(bulkUpdateUnitOfWorkMock.Object); Assert.NotNull(savedDoc); Assert.Equal(SimpleEntity.CreateDocumentWithoutRevision(), savedDoc); }
public void ShouldAssignNewlyUpdatedRevisionsToEntities() { var couchApi = Mock.Of <ICouchApi>( c => c.Db("testdb") == Mock.Of <IDatabaseApi>( d => d.BulkUpdate(It.IsAny <Action <IBulkUpdateBatch> >()) == new Dictionary <string, DocumentInfo> { { SimpleEntity.StandardDocId, new DocumentInfo(SimpleEntity.StandardDocId, "2-cc2c5ab22cfa4a0faad27a0cb9ca7968") } }.ToTask <IDictionary <string, DocumentInfo> >() ) ); ISession sesion = new CouchSession(Default.Settings, couchApi); var entity = SimpleEntity.CreateStandardWithoutRevision(); sesion.Save(entity); sesion.SaveChanges(); Assert.Equal("2-cc2c5ab22cfa4a0faad27a0cb9ca7968", entity.Revision); }
public void ShouldNotCallCreateOrUpdateIfDocumentEntityHaveDeleted() { var persistedEntity = SimpleEntity.CreateStandard(); unitOfWork.Attach(persistedEntity); var trancientEntity = SimpleEntity.CreateStandardWithoutRevision(); unitOfWork.AddNew(trancientEntity); unitOfWork.MarkAsRemoved(trancientEntity); unitOfWork.MarkAsRemoved(persistedEntity); var bulkUpdateUnitOfWorkMock = new Mock <IBulkUpdateBatch>(MockBehavior.Strict); bulkUpdateUnitOfWorkMock .Setup(u => u.Delete(It.IsAny <string>(), It.IsAny <string>())).Callback <string, string>((id, rev) => { }); //Should throw if methods other than Delete() have been called unitOfWork.ApplyChanges(bulkUpdateUnitOfWorkMock.Object); }
public void ShouldNotAllowAnyOperationBeforeChangeSaveOperationCompletes(string operationName) { // I know this test is ginormus, but it's pretty self-contained and simple to understand var saveChangesOperationShouldProceed = new AutoResetEvent(initialState: false); var saveChangesOperationStarted = new AutoResetEvent(initialState: false); var executedOperations = new List <string>(); IDictionary <string, DocumentInfo> returnInfo = new Dictionary <string, DocumentInfo> { { SimpleEntity.StandardDocId, new DocumentInfo(SimpleEntity.StandardDocId, "2-cc2c5ab22cfa4a0faad27a0cb9ca7968") } }; var dbApiMock = new Mock <IDatabaseApi>(); dbApiMock .Setup(couchApi => couchApi.BulkUpdate(It.IsAny <Action <IBulkUpdateBatch> >())) .Returns <Action <IBulkUpdateBatch> >( updater => Task.Factory.StartNew( () => { saveChangesOperationStarted.Set(); saveChangesOperationShouldProceed.WaitOne(); updater(Mock.Of <IBulkUpdateBatch>()); return(returnInfo); } ) ); dbApiMock .Setup(api => api.Query(It.IsAny <ViewQuery>())) .Returns <ViewQuery>( _ => { lock (executedOperations) executedOperations.Add("Query"); return(ViewQueryResult.Empty.ToTask()); }); dbApiMock .Setup(api => api.QueryLucene(It.IsAny <LuceneQuery>())) .Returns <LuceneQuery>( _ => { lock (executedOperations) executedOperations.Add("QueryLucene"); return (LuceneQueryResult.Empty.ToTask()); }); dbApiMock .Setup(api => api.RequestDocument(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <AdditionalDocumentProperty>())) .Returns <string, string, AdditionalDocumentProperty>( (_, __, ___) => { lock (executedOperations) executedOperations.Add("RequestDocument"); return(SimpleEntity.CreateDocument().ToTask()); }); dbApiMock .Setup(api => api.RequestLastestDocumentRevision(It.IsAny <string>())) .Returns <string>( _ => { lock (executedOperations) executedOperations.Add("RequestLastestDocumentRevision"); return(SimpleEntity.StandardDocId.ToTask()); }); dbApiMock .Setup(api => api.DeleteDocument(It.IsAny <string>(), It.IsAny <string>())) .Returns <string, string>( (_, __) => { lock (executedOperations) executedOperations.Add("DeleteDocument"); return(SimpleEntity.StandardDocumentInfo.ToTask()); }); dbApiMock .Setup(api => api.SaveDocument(It.IsAny <Document>())) .Returns <Document>( _ => { lock (executedOperations) executedOperations.Add("SaveDocument"); return(SimpleEntity.StandardDocumentInfo.ToTask()); }); ISession sesion = new CouchSession(Default.Settings, Mock.Of <ICouchApi>(c => c.Db("testdb") == dbApiMock.Object)); sesion.Save(SimpleEntity.CreateStandardWithoutRevision()); var saveChangesOperation = sesion.StartSavingChanges(); // Wating for StartSavingChanges to delegate execution to CouchAPI resetting session-wide wait handle saveChangesOperationStarted.WaitOne(); var startOperationTask = Task.Factory.StartNew( () => { Task operation = null; switch (operationName) { case "load": operation = sesion.Load <SimpleEntity>("doc1a"); break; case "query": operation = sesion.Query <SimpleEntity>( new ViewQuery { DesignDocumentName = "dd1", ViewName = "byX", Key = "key1", IncludeDocs = true }); break; case "fullTextQuery": operation = sesion.QueryLucene <SimpleEntity>( new LuceneQuery { DesignDocumentName = "dd1", IndexName = "byX", IncludeDocs = true, Query = "key1:2" }); break; } // ReSharper disable PossibleNullReferenceException operation.WaitOrThrowOnTimeout(); // ReSharper restore PossibleNullReferenceException }); Assert.True( executedOperations.Count == 0, string.Join(", ", executedOperations) + " operation(s) have executed before save changes operation completes"); saveChangesOperationShouldProceed.Set(); saveChangesOperation.WaitOrThrowOnTimeout(); startOperationTask.WaitOrThrowOnTimeout(); Assert.Equal(1, executedOperations.Count); }
public void ShouldThrowIfTransientDocumentEntityAttached() { Assert.Throws <ArgumentException>(() => unitOfWork.Attach(SimpleEntity.CreateStandardWithoutRevision())); }