Wednesday, March 26, 2014

Testing RavenDB Indexes

RavenDB prefers performance over accuracy, meaning Raven will return results as fast as it can rather than waiting for other operations to complete.  Because of this testing out indexes can be a little tricky.  If you set up an integration test inserting some data into Raven and then begin querying data back out with an index, you might find that your index returns nothing!  How can it return nothing when you've just inserted data?  This is where you will need to instruct Raven to wait for indexes to finish rebuilding before returning results.

In my last post, I added
store.Conventions.DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites;
to the SpecsForRavenDb<T> class so that we can query data we have just inserted into Raven.  The problem with this is DefaultQueryingConsistency property does not apply to indexes.

To instruct Raven to wait for non-stale results when querying indexes, we can add add a listener our SpecsForRavenDb<T> class.
public class NoStaleQueriesListener : IDocumentQueryListener  
 {  
    public void BeforeQueryExecuted(IDocumentQueryCustomization queryCustomization)  
    {  
      queryCustomization.WaitForNonStaleResults();  
    }  
 }  
   
This simple class tells RavenDB before each query is executed wait for non stale results.  To hook it into our test base class, we just need to add one line to SpecsForRavenDb<T> before we initialize our EmbeddableDocumentStore:
.RegisterListener(NoStaleQueriesListener())
Since we are only applying our listener when testing, Raven will wait for non stale results in a test scenario, but will still use the default behavior of returning results as fast as possible when running in production.

Now our final SpecsForRavenDb<T> class looks like this:
    public abstract class SpecsForRavenDb<T> : SpecsFor<T> where T : class 
    { 
        private IDocumentStore _store; 
        public IDocumentSession RavenSession { get; set; } 
 
        public override void SetupEachSpec() 
        { 
            _store = new EmbeddableDocumentStore 
                { 
                    RunInMemory = true 
                }
                .RegisterListener(NoStaleQueriesListener())
                .Initialize(); 
 
            _store.Conventions.DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites;
            IndexCreation.CreateIndexes(typeof(MyProject.MyIndex).Assembly, _store);  
 
            RavenSession = _store.OpenSession(); 
             
            base.SetupEachSpec(); 
        } 
         
        protected override void ConfigureContainer(StructureMap.IContainer container) 
        { 
            container.Configure(cfg => cfg.For<IDocumentSession>().Use(RavenSession)); 
        } 
 
        protected override void AfterSpec() 
        { 
            base.AfterSpec(); 
            RavenSession.Dispose(); 
            _store.Dispose(); 
        } 
    }

No comments:

Post a Comment