根据https://cloud.google.com/appengine/docs/java/tools/localunittesting#Writing_HRD_Datastore_Tests,“如果您的应用使用高复制数据存储(HRD),您可能需要编写测试来验证应用程序在最终一致性方面的行为.LocalDatastoreServiceTestConfig公开了使这一过程变得简单的选项。 “你应该设置setDefaultHighRepJobPolicyUnappliedJobPercentage(100)
,然后,“通过将未应用的作业百分比设置为100,我们指示本地数据存储区以最大的最终一致性进行操作。最大的最终一致性意味着写入将提交但总是失败要应用,所以全局(非祖先)查询将始终无法看到更改。“
但是,我认为setDefaultHighRepJobPolicyUnappliedJobPercentage(100)
不起作用。
如果确实如此,那么我的下面的测试用例testEventualConsistency()
应该通过,但它在第二个断言失败了。在第一个断言中,我使用Objectify ancestor()查询读回了我保存的对象。它的工作原理是因为检索了对象。但是,第二个断言失败了。在那个断言中我还读回了我保存的对象,但是我没有使用Objectify ancestor()查询,所以它不应该检索任何东西,因为我已经指定不应该完成任务(即{{1设置)。
EventualConsistencyTest测试用例
setDefaultHighRepJobPolicyUnappliedJobPercentage(100)
用户定义
import static com.googlecode.objectify.ObjectifyService.begin;
import static com.googlecode.objectify.ObjectifyService.ofy;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import java.util.List;
import org.junit.Test;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.Ref;
import com.googlecode.objectify.util.Closeable;
import com.netbase.followerdownloader.model.DownloadTask;
import com.netbase.followerdownloader.model.User;
public class EventualConsistencyTest {
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
.setDefaultHighRepJobPolicyUnappliedJobPercentage(100));
@Test
public void testEventualConsistency() {
helper.setUp();
ObjectifyRegistrar.registerDataModel();
User user = new User();
user.id = 1L;
Closeable closeable1 = begin();
ofy().save().entity(user);
closeable1.close();
Closeable closeable2 = begin();
DownloadTask downloadTask = new DownloadTask();
downloadTask.owner = Ref.create(user);
ofy().save().entity(downloadTask);
closeable2.close();
Closeable closeable3 = ObjectifyService.begin();
List<DownloadTask> downloadTasks1 = ofy().load().type(DownloadTask.class).ancestor(user).list();
assertThat(downloadTasks1.size(), equalTo(1));
closeable3.close();
Closeable closeable4 = ObjectifyService.begin();
List<DownloadTask> downloadTasks2 = ofy().load().type(DownloadTask.class).list();
assertThat(downloadTasks2.size(), equalTo(0)); // THIS SHOULD PASS IF setDefaultHighRepJobPolicyUnappliedJobPercentage(100) WORKED
closeable4.close();
helper.tearDown();
}
}
DownloadTask定义
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
@Entity
public class User {
@Id public Long id;
public User () {
}
}
环境:
如果我错过了其他重要的事情,这里有一个更详尽的清单:
我的问题是:
import com.googlecode.objectify.Ref;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Parent;
@Entity
public class DownloadTask {
@Id public Long id;
@Parent public Ref<User> owner;
public DownloadTask() {
}
}
是否已损坏?
setDefaultHighRepJobPolicyUnappliedJobPercentage(100)
是否真的没有记录?它实际上是否适用于该工作,即使文档说它不应该?
传递给setDefaultHighRepJobPolicyUnappliedJobPercentage(100)
的值是否真的应该是setDefaultHighRepJobPolicyUnappliedJobPercentage()
而不是让我们说100
?
Objectify祖先查询是否真的没有记录?
答案 0 :(得分:1)
https://cloud.google.com/appengine/docs/java/tools/localunittesting#Java_Writing_High_Replication_Datastore_tests的观察结果解释了这个问题: “在本地环境中,执行属于具有未应用写入的实体组的实体的get()将始终使未应用写入的结果对后续全局查询可见。”
在本文中,这意味着祖先查询:
List<DownloadTask> downloadTasks1 = ofy().load().type(DownloadTask.class).ancestor(user).list();
在内部“执行get()
属于具有未应用写入的实体组的Entity
”会影响紧随其后的全局查询的行为:
List<DownloadTask> downloadTasks2 = ofy().load().type(DownloadTask.class).list();
为了避免您的测试相互影响,特别是以这种方式相互干扰,最好每个测试操作使用一个单独的方法(每个都有所有需要的设置和拆卸部分),而不是在单一测试方法中连续进行的测试操作。