Task TestOnDisconnect()

in database/testapp/Assets/Firebase/Sample/Database/UIHandlerAutomated.cs [2001:2159]


    Task TestOnDisconnect() {
      return Task.Run(() => {
        // This test queues many OnDisconnect actions, then goes offline and validates that they ran.
        // It will also validate that they did not run before going offline and that they don't
        // run a second time if we go offline again.

        // Long list of constants:
        string childKey = "ChildKey";

        string cancelDirectChild = "Cancel";
        string cancelParentChild = "CancelParentChild";
        string cancelParentParent = "CancelParent";
        string cancelValue = "CancelValue";

        string removeValueChild = "RemoveValue";
        string removeValueValue = "RemoveValueValue";

        string setValueChild = "SetValue";
        string setValueValue = "SetValueValue";

        string setValueAndStringPriorityChild = "SetValueAndStringPriority";
        string setValueAndStringValue = "SetValueAndStringPriorityValue";
        string setValueAndStringPriority = "SetValueAndStringPriority";

        string setValueAndDoublePriorityChild = "SetValueAndDoublePriority";
        string setValueAndDoubleValue = "SetValueAndDoublePriorityValue";
        double setValueAndDoublePriority = 3.14d;

        string updateChildrenChild = "UpdateChildren";
        Dictionary<string, object> initialValue = new Dictionary<string, object>();
        initialValue["stay"] = "This should be unchanged";
        initialValue["change"] = "This should change";
        initialValue["remove"] = "This should be removed";
        Dictionary<string, object> change = new Dictionary<string, object>();
        change["new"] = "This is new";
        change["change"] = "This is changed";
        change["remove"] = null;  // setting it to null removes the child
        // "stay" is not mentioned and should therefore stay the same
        Dictionary<string, object> expectedValue = new Dictionary<string, object>();
        expectedValue["stay"] = "This should be unchanged";
        expectedValue["new"] = "This is new";
        expectedValue["change"] = "This is changed";

        // End of the long list of constants

        // We use Push to create a random child to not interfere with someone else running this test.
        var parent = database.RootReference.Child("TestTree").Push();

        try {
          var r = parent.Child(childKey);
          // 1. Queue lots of OnDisconnect stuff
          WaitAndAssertCompleted("OnDisconnect.RemoveValue",
              r.Child(removeValueChild).OnDisconnect().RemoveValue());

          // Queue something, then cancel it.
          WaitAndAssertCompleted("OnDisconnect.RemoveValue",
              r.Child(cancelDirectChild).OnDisconnect().RemoveValue());
          WaitAndAssertCompleted("OnDisconnect.Cancel",
              r.Child(cancelDirectChild).OnDisconnect().Cancel());

          WaitAndAssertCompleted("OnDisconnect.RemoveValue",
              r.Child(cancelParentParent).Child(cancelParentChild).OnDisconnect().RemoveValue());
          // Cancelling at the parent level also cancels actions for child nodes:
          WaitAndAssertCompleted("OnDisconnect.Cancel",
              r.Child(cancelParentParent).OnDisconnect().Cancel());

          WaitAndAssertCompleted("OnDisconnect.SetValue",
              r.Child(setValueChild).OnDisconnect().SetValue(setValueValue));

          WaitAndAssertCompleted("OnDisconnect.SetValueAndPriority",
              r.Child(setValueAndStringPriorityChild).OnDisconnect().
              SetValue(setValueAndStringValue, setValueAndStringPriority));

          WaitAndAssertCompleted("OnDisconnect.SetValueAndPriority",
              r.Child(setValueAndDoublePriorityChild).OnDisconnect().
              SetValue(setValueAndDoubleValue, setValueAndDoublePriority));

          WaitAndAssertCompleted("OnDisconnect.UpdateChildren",
              r.Child(updateChildrenChild).OnDisconnect().UpdateChildren(change));

          // 2. Set pre-existing values
          // (We intentionally do that AFTER queueing the OnDisconnect actions.)
          WaitAndAssertCompleted("RemoveValue", r.RemoveValueAsync());
          WaitAndAssertCompleted("SetValue", r.Child(cancelDirectChild).SetValueAsync(cancelValue));
          WaitAndAssertCompleted("SetValue",
              r.Child(cancelParentParent).Child(cancelParentChild).SetValueAsync(cancelValue));
          WaitAndAssertCompleted("SetValue", r.Child(removeValueChild).SetValueAsync(removeValueValue));
          WaitAndAssertCompleted("SetValue", r.Child(updateChildrenChild).SetValueAsync(initialValue));

          // 3. Some asserts that things have not run yet:
          Task<DataSnapshot> t;
          t = r.GetValueAsync();
          WaitAndAssertCompleted("GetValue", t);
          AssertEq("Number of children before offline", 4, t.Result.ChildrenCount);
          Assert("To be removed child still there", t.Result.HasChild(removeValueChild));

          // GoOffline to trigger the OnDisconnect actions
          database.GoOffline();
          database.GoOnline();

          // Validate that everything is as expexted
          t = r.GetValueAsync();
          WaitAndAssertCompleted("GetValue", t);
          AssertEq("Number of children", 6, t.Result.ChildrenCount);

          Assert("Cancel child exists", t.Result.HasChild(cancelDirectChild));
          AssertEq("Cancel child unchanged", t.Result.Child(cancelDirectChild).Value, cancelValue);

          Assert("Cancel parent child exists",
              t.Result.HasChild(cancelParentParent) &&
              t.Result.Child(cancelParentParent).HasChild(cancelParentChild));
          AssertEq("Cancel parent child unchanged",
              t.Result.Child(cancelParentParent).Child(cancelParentChild).Value, cancelValue);

          Assert("Removed child does not exist", !t.Result.HasChild(removeValueChild));

          AssertEq("SetValue value", t.Result.Child(setValueChild).Value, setValueValue);
          AssertEq("SetValue priority", t.Result.Child(setValueChild).Priority, null);

          AssertEq("SetValueAndStringPriority value",
              t.Result.Child(setValueAndStringPriorityChild).Value, setValueAndStringValue);
          AssertEq("SetValueAndStringPriority priority",
              t.Result.Child(setValueAndStringPriorityChild).Priority, setValueAndStringPriority);

          AssertEq("SetValueAndDoublePriority value",
              t.Result.Child(setValueAndDoublePriorityChild).Value, setValueAndDoubleValue);
          AssertEq("SetValueAndDoublePriority priority",
              t.Result.Child(setValueAndDoublePriorityChild).Priority, setValueAndDoublePriority);

          Assert("UpdateChildren value as expected",
              EqualContent(t.Result.Child(updateChildrenChild).Value, expectedValue));

          // Redo everything, to check that OnDisconnect actions are only run once.
          WaitAndAssertCompleted("RemoveValue", r.RemoveValueAsync());
          WaitAndAssertCompleted("SetValue", r.Child(cancelDirectChild).SetValueAsync(cancelValue));
          WaitAndAssertCompleted("SetValue",
              r.Child(cancelParentParent).Child(cancelParentChild).SetValueAsync(cancelValue));
          WaitAndAssertCompleted("SetValue", r.Child(removeValueChild).SetValueAsync(removeValueValue));
          WaitAndAssertCompleted("SetValue", r.Child(updateChildrenChild).SetValueAsync(initialValue));
          t = r.GetValueAsync();
          WaitAndAssertCompleted("GetValue", t);
          AssertEq("Number of children before offline", 4, t.Result.ChildrenCount);
          Assert("To be removed child still there", t.Result.HasChild(removeValueChild));

          // GoOffline again (this time, there should be no OnDisconnect actions)
          database.GoOffline();
          database.GoOnline();

          // This time, the state should not have changed
          t = r.GetValueAsync();
          WaitAndAssertCompleted("GetValue", t);
          AssertEq("Number of children before offline", 4, t.Result.ChildrenCount);
          Assert("To be removed child still there", t.Result.HasChild(removeValueChild));
        } finally {
          // Finally, cleanup, as to not pollute the test database
          parent.RemoveValueAsync();
        }
      });
    }