Search in sources :

Example 11 with MapBasedShadowStore

use of org.springframework.sync.diffsync.shadowstore.MapBasedShadowStore in project spring-sync by spring-projects.

the class DiffSyncTest method patchList_addNewItem_lostReturn.

//
// Guaranteed Delivery - Lost outbound packet scenario
//
// TODO: This is primarily a client-side case. By definition, the server never receives the patch.
//       Therefore, there's nothing server-side to be tested.
//       However, this case *does* apply to Spring Sync when used in an Android client.
//       Therefore, tests for this scenario will need to be fleshed out.
//
// Guaranteed Delivery - Lost return packet scenario
//
@Test
public void patchList_addNewItem_lostReturn() throws Exception {
    DiffSync<Todo> sync = new DiffSync<Todo>(new MapBasedShadowStore("x"), Todo.class);
    // Create the list resource
    List<Todo> todos = getTodoList();
    // Apply an initial patch to get the server shadow's client version bumped up.
    // Initially, the server shadow's server and client versions are both 0,
    // matching the incoming patch's versions, so the patch is applied normally.
    List<PatchOperation> ops1 = new ArrayList<PatchOperation>();
    ops1.add(new AddOperation("/~", new Todo(100L, "NEW ITEM 100", false)));
    VersionedPatch versionedPatch = new VersionedPatch(ops1, 0, 0);
    // At this point, the client sends the patch to the server, the client puts the patch in an outbound stack, 
    // the client increments its shadow client version to 1, and the server calls sync.apply() to apply the patch.
    List<Todo> patched = sync.apply(todos, versionedPatch);
    // After the patch is applied, the server shadow versions are
    //   - Primary shadow: serverVersion = 0, clientVersion = 1
    //   - Backup shadow : serverVersion = 0, clientVersion = 1
    // At this point, the server's shadow has client version 1 and server version 0
    // The server then copies its current shadow to backup shadow before performing a new diff against the shadow, bumping the server version to 1 *after* the diff is performed.
    // The backup shadow, having been taken before the new diff was created, still has server version 0.
    // Before it performs the diff, however, it copies its current shadow to backup shadow.
    // The diff was performed against the shadow whose client version 1 and server version 0, therefore the patch will have client version 1 and server version 0.
    VersionedPatch lostDiff = sync.diff(patched);
    // After the diff is applied, the server shadow's server version is incremented.
    //   - Primary shadow: serverVersion = 1, clientVersion = 1
    //   - Backup shadow : serverVersion = 0, clientVersion = 1
    // Verify that the patch has client version 1, server version 0
    assertEquals(1, lostDiff.getClientVersion());
    assertEquals(0, lostDiff.getServerVersion());
    // In the lost return packet scenario, the client never receives that return diff (lostDiff) or acknowledgement of the server having applied the first patch.
    // The client can only assume that the server never received it (although it did).
    // So it produces a new patch against its shadow (whose server version is still at 0 and client version is 1).
    // It then sends both patches to the server and the server attempts to apply them both.
    List<PatchOperation> ops2 = new ArrayList<PatchOperation>();
    ops2.add(new AddOperation("/~", new Todo(200L, "NEW ITEM 200", false)));
    VersionedPatch versionedPatch2 = new VersionedPatch(ops2, 0, 1);
    patched = sync.apply(patched, versionedPatch, versionedPatch2);
    // The first patch's server version is 0, which is less than the server shadow's server version of 1.
    // This indicates a lost packet scenario, meaning that the client never received or applied the
    // return patch from the previous cycle.
    // So the server resurrects the backup shadow into the primary shadow:
    //   - Primary shadow: serverVersion = 0, clientVersion = 1
    //   - Backup shadow : serverVersion = 0, clientVersion = 1
    // Then it tries to apply the first patch. Since the patch's client version is less than the shadow's client version, 
    // it ignores the patch as a duplicate (that was applied earlier)
    // Then it tries to apply the second patch. This patch's client version is the same as the shadow's client version, 
    // so it applies it as with normal operation.
    // After the applying the 2nd patch, the server shadow's server version is incremented.
    //   - Primary shadow: serverVersion = 0, clientVersion = 2
    //   - Backup shadow : serverVersion = 0, clientVersion = 2
    // Finally, the server performs a diff against the shadow (whose server version is 0 and whose client version is 2).
    // Therefore, the patch produced should have client version 2, server version 0.
    // After the diff, the server version will be 1, but there's no way to verify that, except to perform another patch.
    VersionedPatch diff = sync.diff(patched);
    // the server is acknowledging client version 1 and 2 (the client should be at that version by this time)
    assertEquals(2, diff.getClientVersion());
    // the server created the patch against server version 0 (but it will be 1 after the patch is created)
    assertEquals(0, diff.getServerVersion());
    // After the diff is applied, the server shadow's server version is incremented.
    //   - Primary shadow: serverVersion = 1, clientVersion = 2
    //   - Backup shadow : serverVersion = 0, clientVersion = 2
    // Now test that the resulting list is as expected.
    // The original should remain unchanged
    assertEquals(todos, getTodoList());
    // The patched resource should now contain 2 additional items, one from each patch sent.
    // It should *NOT* have two of the item that was added as part of the initial patch (the one that was sent twice).
    assertNotEquals(patched, todos);
    // Should only have added 2 new items. It shouldn't have added the first new item twice.
    assertEquals(5, patched.size());
    assertEquals(todos.get(0), patched.get(0));
    assertEquals(todos.get(1), patched.get(1));
    assertEquals(todos.get(2), patched.get(2));
    assertEquals(new Todo(100L, "NEW ITEM 100", false), patched.get(3));
    assertEquals(new Todo(200L, "NEW ITEM 200", false), patched.get(4));
}
Also used : Todo(org.springframework.sync.Todo) MapBasedShadowStore(org.springframework.sync.diffsync.shadowstore.MapBasedShadowStore) ArrayList(java.util.ArrayList) PatchOperation(org.springframework.sync.PatchOperation) AddOperation(org.springframework.sync.AddOperation) Test(org.junit.Test)

Example 12 with MapBasedShadowStore

use of org.springframework.sync.diffsync.shadowstore.MapBasedShadowStore in project spring-sync by spring-projects.

the class DiffSyncTest method patchList_removeTwoItems.

@Test
public void patchList_removeTwoItems() throws Exception {
    DiffSync<Todo> sync = new DiffSync<Todo>(new MapBasedShadowStore("x"), Todo.class);
    Patch patch = readJsonPatchFromResource("patch-remove-two-items");
    List<Todo> todos = getTodoList();
    List<Todo> patched = sync.apply(todos, patch);
    // original should remain unchanged
    assertEquals(todos, getTodoList());
    assertNotEquals(patched, todos);
    assertEquals(1, patched.size());
    assertEquals(new Todo(1L, "A", false), patched.get(0));
}
Also used : Todo(org.springframework.sync.Todo) MapBasedShadowStore(org.springframework.sync.diffsync.shadowstore.MapBasedShadowStore) Patch(org.springframework.sync.Patch) Test(org.junit.Test)

Example 13 with MapBasedShadowStore

use of org.springframework.sync.diffsync.shadowstore.MapBasedShadowStore in project spring-sync by spring-projects.

the class DiffSyncTest method patchEntity_booleanProperty.

@Test
public void patchEntity_booleanProperty() throws Exception {
    DiffSync<Todo> sync = new DiffSync<Todo>(new MapBasedShadowStore("x"), Todo.class);
    Patch patch = readJsonPatchFromResource("single-change-status");
    Todo todo = new Todo(1L, "A", false);
    Todo patched = sync.apply(todo, patch);
    assertEquals(1L, patched.getId().longValue());
    assertEquals("A", patched.getDescription());
    assertTrue(patched.isComplete());
    // original remains unchanged
    assertEquals(1L, todo.getId().longValue());
    assertEquals("A", todo.getDescription());
    assertFalse(todo.isComplete());
}
Also used : Todo(org.springframework.sync.Todo) MapBasedShadowStore(org.springframework.sync.diffsync.shadowstore.MapBasedShadowStore) Patch(org.springframework.sync.Patch) Test(org.junit.Test)

Example 14 with MapBasedShadowStore

use of org.springframework.sync.diffsync.shadowstore.MapBasedShadowStore in project spring-sync by spring-projects.

the class DiffSyncTest method patchList_addNewItem.

@Test
public void patchList_addNewItem() throws Exception {
    DiffSync<Todo> sync = new DiffSync<Todo>(new MapBasedShadowStore("x"), Todo.class);
    Patch patch = readJsonPatchFromResource("patch-add-new-item");
    List<Todo> todos = getTodoList();
    List<Todo> patched = sync.apply(todos, patch);
    // original should remain unchanged
    assertEquals(todos, getTodoList());
    assertNotEquals(patched, todos);
    assertEquals(4, patched.size());
    assertEquals(todos.get(0), patched.get(0));
    assertEquals(todos.get(1), patched.get(1));
    assertEquals(todos.get(2), patched.get(2));
    assertEquals(new Todo(null, "D", false), patched.get(3));
}
Also used : Todo(org.springframework.sync.Todo) MapBasedShadowStore(org.springframework.sync.diffsync.shadowstore.MapBasedShadowStore) Patch(org.springframework.sync.Patch) Test(org.junit.Test)

Example 15 with MapBasedShadowStore

use of org.springframework.sync.diffsync.shadowstore.MapBasedShadowStore in project spring-sync by spring-projects.

the class DiffSyncTest method patchEntity_moveProperty_duplicate.

@Test
public void patchEntity_moveProperty_duplicate() throws Exception {
    DiffSync<Person> sync = new DiffSync<Person>(new MapBasedShadowStore("x"), Person.class);
    List<PatchOperation> ops = new ArrayList<PatchOperation>();
    ops.add(new MoveOperation("/firstName", "/lastName"));
    VersionedPatch vPatch1 = new VersionedPatch(ops, 0, 0);
    VersionedPatch vPatch2 = new VersionedPatch(ops, 0, 0);
    Person person = new Person("Edmund", "Blackadder");
    Person patched = sync.apply(person, vPatch1, vPatch2);
    VersionedPatch diff = sync.diff(patched);
    // the server is acknowledge client version 1 (the client should be at that version by this time)
    assertEquals(1, diff.getClientVersion());
    // the server created the patch against server version 0 (but it will be 1 after the patch is created)
    assertEquals(0, diff.getServerVersion());
    assertEquals("Blackadder", patched.getFirstName());
    assertNull(patched.getLastName());
}
Also used : MapBasedShadowStore(org.springframework.sync.diffsync.shadowstore.MapBasedShadowStore) MoveOperation(org.springframework.sync.MoveOperation) ArrayList(java.util.ArrayList) PatchOperation(org.springframework.sync.PatchOperation) Person(org.springframework.sync.Person) Test(org.junit.Test)

Aggregations

MapBasedShadowStore (org.springframework.sync.diffsync.shadowstore.MapBasedShadowStore)26 Test (org.junit.Test)25 Todo (org.springframework.sync.Todo)22 Patch (org.springframework.sync.Patch)21 ArrayList (java.util.ArrayList)5 PatchOperation (org.springframework.sync.PatchOperation)5 MoveOperation (org.springframework.sync.MoveOperation)4 Person (org.springframework.sync.Person)4 PatchException (org.springframework.sync.PatchException)2 AddOperation (org.springframework.sync.AddOperation)1 PersistenceCallbackRegistry (org.springframework.sync.diffsync.PersistenceCallbackRegistry)1 ShadowStore (org.springframework.sync.diffsync.ShadowStore)1 MockMvc (org.springframework.test.web.servlet.MockMvc)1