Skip to content

Commit

Permalink
test insert in list recovery
Browse files Browse the repository at this point in the history
  • Loading branch information
ironage committed Nov 20, 2023
1 parent 7c554c8 commit 12afcfb
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 6 deletions.
17 changes: 17 additions & 0 deletions test/object-store/collection_fixtures.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ struct LinkedCollectionBase {
virtual void clear_collection(Obj obj) = 0;
virtual std::vector<Obj> get_links(Obj obj) = 0;
virtual void move(Obj, size_t, size_t) {}
virtual void insert(Obj, size_t, ObjLink) {}
bool remove_linked_object(Obj obj, ObjLink to)
{
auto links = get_links(obj);
Expand Down Expand Up @@ -518,6 +519,12 @@ struct ListOfObjects : public LinkedCollectionBase {
auto coll = source.get_linklist(col);
coll.move(from, to);
}
void insert(Obj source, size_t ndx, ObjLink to) override
{
ColKey col = get_link_col_key(source.get_table());
auto coll = source.get_linklist(col);
coll.insert(ndx, to.get_obj_key());
}
size_t size_of_collection(Obj obj)
{
ColKey col = get_link_col_key(obj.get_table());
Expand Down Expand Up @@ -587,6 +594,16 @@ struct ListOfMixedLinks : public LinkedCollectionBase {
ColKey col = get_link_col_key(obj.get_table());
obj.get_list<Mixed>(col).move(from, to);
}
void insert(Obj from, size_t ndx, ObjLink to) override
{
ColKey col = get_link_col_key(from.get_table());
from.get_list<Mixed>(col).insert(ndx, to);
// When adding dynamic links through a mixed value, the relationship map needs to be dynamically updated.
// In practice, this is triggered by the addition of backlink columns to any table.
if (m_relation_updater) {
m_relation_updater();
}
}

size_t count_unresolved_links(Obj obj)
{
Expand Down
71 changes: 65 additions & 6 deletions test/object-store/sync/client_reset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -772,9 +772,9 @@ TEST_CASE("sync: client reset", "[sync][pbs][client reset][baas]") {
list.insert(1, key2);
list.add(key2);
list.add(key3); // common suffix of key3
list.set(0,
key1); // this set operation triggers the list copy because the index becomes ambiguious
// 1, 2, 2, 3, 2, 3
// this set operation triggers the list copy because the index becomes ambiguious
list.set(0, key1);
})
->make_remote_changes([&](SharedRealm remote) {
auto table = get_table(*remote, "link target");
Expand All @@ -791,7 +791,7 @@ TEST_CASE("sync: client reset", "[sync][pbs][client reset][baas]") {
REQUIRE(get_key_for_object_with_value(target_table, 1));
REQUIRE(get_key_for_object_with_value(target_table, 3));
auto list = table->begin()->get_linklist("list");
REQUIRE(list.size() == 3);
REQUIRE(list.size() == 3); // 1, 3, 3
REQUIRE(list.get_object(0).get<Int>("value") == 1);
REQUIRE(list.get_object(1).get<Int>("value") == 3);
REQUIRE(list.get_object(2).get<Int>("value") == 3);
Expand Down Expand Up @@ -2506,6 +2506,16 @@ struct Move {
size_t to;
};

struct Insert {
Insert(size_t index, util::Optional<int64_t> key)
: ndx(index)
, pk(key)
{
}
size_t ndx;
util::Optional<int64_t> pk;
};

struct CollectionOperation {
CollectionOperation(Add op)
: m_op(op)
Expand All @@ -2531,6 +2541,10 @@ struct CollectionOperation {
: m_op(op)
{
}
CollectionOperation(Insert op)
: m_op(op)
{
}
void apply(collection_fixtures::LinkedCollectionBase* collection, Obj src_obj, TableRef dst_table)
{
mpark::visit(
Expand Down Expand Up @@ -2569,21 +2583,27 @@ struct CollectionOperation {
[&](Clear) {
collection->clear_collection(src_obj);
},
[&](Insert insert) {
Mixed pk_to_add = insert.pk ? Mixed{insert.pk} : Mixed{};
ObjKey dst_key = dst_table->find_primary_key(pk_to_add);
REALM_ASSERT(dst_key);
collection->insert(src_obj, insert.ndx, ObjLink{dst_table->get_key(), dst_key});
},
[&](Move move) {
collection->move(src_obj, move.from, move.to);
}},
m_op);
}

private:
mpark::variant<Add, Remove, Clear, RemoveObject, CreateObject, Move> m_op;
mpark::variant<Add, Remove, Clear, RemoveObject, CreateObject, Move, Insert> m_op;
};

} // namespace test_instructions

TEMPLATE_TEST_CASE("client reset collections of links", "[sync][pbs][client reset][links][collections]",
cf::ListOfObjects, cf::ListOfMixedLinks, cf::SetOfObjects, cf::SetOfMixedLinks,
cf::DictionaryOfObjects, cf::DictionaryOfMixedLinks)
cf::ListOfObjects, cf::ListOfMixedLinks/*, cf::SetOfObjects, cf::SetOfMixedLinks,
cf::DictionaryOfObjects, cf::DictionaryOfMixedLinks*/)
{
if (!util::EventLoop::has_implementation())
return;
Expand All @@ -2594,6 +2614,7 @@ TEMPLATE_TEST_CASE("client reset collections of links", "[sync][pbs][client rese
const std::string collection_prop_name = "collection";
TestType test_type(collection_prop_name, "dest");
constexpr bool test_type_is_array = realm::is_any_v<TestType, cf::ListOfObjects, cf::ListOfMixedLinks>;
constexpr bool test_type_is_set = realm::is_any_v<TestType, cf::SetOfObjects, cf::SetOfMixedLinks>;
Schema schema = {
{"source",
{{valid_pk_name, PropertyType::Int | PropertyType::Nullable, true},
Expand Down Expand Up @@ -2919,6 +2940,14 @@ TEMPLATE_TEST_CASE("client reset collections of links", "[sync][pbs][client rese
reset_collection({RemoveObject{"dest", dest_pk_4}}, {Add{dest_pk_4}, Add{dest_pk_5}},
{dest_pk_1, dest_pk_2, dest_pk_3, dest_pk_5}, 1);
}
SECTION("local adds two links to objects which are both removed by the remote") {
reset_collection({Add{dest_pk_4}, Add{dest_pk_5}, CreateObject("dest", 6), Add{6}}, {RemoveObject("dest", dest_pk_4), RemoveObject("dest", dest_pk_5)},
{dest_pk_1, dest_pk_2, dest_pk_3, 6}, 2);
}
SECTION("local removes two objects which were linked to by remote") {
reset_collection({RemoveObject("dest", dest_pk_1), RemoveObject("dest", dest_pk_2), CreateObject("dest", 6), Add{6}}, {},
{dest_pk_3, 6}, 2);
}
if (test_mode == ClientResyncMode::Recover) {
SECTION("local adds a list item and removes source object, remote modifies list") {
reset_collection_removing_source_object({Add{dest_pk_4}, RemoveObject{"source", source_pk}},
Expand Down Expand Up @@ -2966,6 +2995,29 @@ TEMPLATE_TEST_CASE("client reset collections of links", "[sync][pbs][client rese
reset_collection({Move{0, 1}, Add{dest_pk_5}}, {CreateObject("dest", 6), Add{6}},
{dest_pk_2, dest_pk_1, dest_pk_3, dest_pk_5});
}
SECTION("local moves on locally-added elements when server removes the object that the new links point to") {
reset_collection({Add{dest_pk_5}, Add{dest_pk_5}, Move{4, 3}}, {Add{dest_pk_4}, RemoveObject("dest", dest_pk_5)},
{dest_pk_1, dest_pk_2, dest_pk_3}); // local overwrite, but without pk_5
}
SECTION("local insert and delete can be recovered even if a local link was deleted by remote") {
// start : 1, 2, 3
// local : 1, 2, 3, 5, 6, 1
// remote : 4, 1, 2, 3 {remove obj 5}
// result : 1, 2, 3, 6, 1
reset_collection({CreateObject("dest", 6), Add{dest_pk_5}, Add{6}, Insert{4, dest_pk_4}, Remove{dest_pk_4}, Add{dest_pk_1}},
{Insert{0, dest_pk_4}, RemoveObject("dest", dest_pk_5)},
{dest_pk_4, dest_pk_1, dest_pk_2, dest_pk_3, 6, dest_pk_1});
}
SECTION("both add link to object which has been deleted by other side") {
// start : 1, 2, 3
// local : 1, 1, 2, 3, 5, {remove object 4}
// remote : 1, 2, 3, 3, 4, {remove obj 5}
// result : 1, 1, 2, 3, 3
reset_collection({Add{dest_pk_5}, Insert{0, dest_pk_1}, RemoveObject("dest", dest_pk_4)},
{Add{dest_pk_4}, Insert{3, dest_pk_3}, RemoveObject("dest", dest_pk_5)},
{dest_pk_1, dest_pk_1, dest_pk_2, dest_pk_3, dest_pk_3});
}

SECTION("local moves on added elements can be merged with remote moves") {
reset_collection({Add{dest_pk_4}, Add{dest_pk_5}, Move{3, 4}}, {Move{0, 1}},
{dest_pk_2, dest_pk_1, dest_pk_3, dest_pk_5, dest_pk_4});
Expand All @@ -2991,6 +3043,13 @@ TEMPLATE_TEST_CASE("client reset collections of links", "[sync][pbs][client rese
{Remove{dest_pk_1}, Remove{dest_pk_2}}, {dest_pk_3, dest_pk_4});
}
}
else if constexpr (test_type_is_set) {
SECTION("remote adds two links to objects which are both removed by local") {
reset_collection({RemoveObject("dest", dest_pk_4), RemoveObject("dest", dest_pk_5), CreateObject("dest", 6), Add{6}, Remove{dest_pk_1}},
{Remove{dest_pk_2}, Add{dest_pk_4}, Add{dest_pk_5}, CreateObject("dest", 6), Add{6}, CreateObject("dest", 7), Add{7}, RemoveObject("dest", dest_pk_5)},
{dest_pk_3, 6, 7});
}
}
}

template <typename T>
Expand Down

0 comments on commit 12afcfb

Please sign in to comment.