Google App Engine Datastore - Testing Queries fails

不打扰是莪最后的温柔 提交于 2019-11-28 12:33:19

There is nothing wrong with your test code. The issue lies in the Datastore itself. Most queries in the HR Datastore are not "immediately consistent" but eventually consistent. You can read more about this in the Datastore documentation.

So basically what happens is that you put an entity into the Datastore, and the SDK's Datastore "simulates" the latency that you can observe in production, so if you run a query right after that (which is not an ancestor query), the query result will not include the new entity you just saved.

If you put a few seconds sleep between the datastore.Put() and q.GetAll(), you will see the test passes. Try it. In my test it was enough to sleep just 100ms, and the test always passed. But when writing tests for such cases, use the StronglyConsistentDatastore: true option as can be seen in JonhGB's answer.

You would also see the test pass without sleep if you'd use Ancestor queries because they are strongly consistent.

The way to do this is to force the datastore to be strongly consistent by setting up the context like this:

c, err := aetest.NewContext(&aetest.Options{StronglyConsistentDatastore: true})
    if err != nil {
        t.Fatal(err)
    }

Now the datastore won't need any sleep to work, which is faster, and better practice in general.


Update: This only works with the old aetest package which was imported via appengine/aetest. It does not work with the newer aetest package which is imported with google.golang.org/appengine/aetest. App Engine has changed from using an appengine.Context to using a context.Context, and consequently the way that the test package now works is quite different.

To compliment @JohnGB's answer in the latest version of aetest, there are more steps to get a context with strong consistency. First create an instance, then create a request from that instance, which you can use to produce a context.

inst, err := aetest.NewInstance(
&aetest.Options{StronglyConsistentDatastore: true})

if err != nil {
    t.Fatal(err)
}
defer inst.Close()

req, err := inst.NewRequest("GET", "/", nil)
if err != nil {
    t.Fatal(err)
}

ctx := appengine.NewContext(req)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!