question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[BUG] - Mock reliable collections do not serialize, or at least, deep copy inserted data

See original GitHub issue

Describe the bug

In the reliable collections docs, the authors describe scenarios in which programmers might accidentally cause bugs by updating objects in-memory, but not in the reliable collections. This is an important behavioral difference that reliable collections have over regular collections - updating a reference to data that was inserted into the reliable collection does not update the stored data.

However, in our unit tests, we have noticed that the mock reliable collections do not model this behavior. Updating a reference to data that is stored in a mock reliable collection will apply to the stored data. This makes our unit tests behave differently than in integration tests, and has been the source of some confusion. Thus, in unit tests we have resorted to manually making deep copies of the data before storing them, by doing a serialization round trip.

Reliable collections by default support data contract serialization. It might be some work to support the default serialization, and not everyone is guaranteed to use it. However, custom serialization is also supported through the IReliableStateManager.TryAddStateSerializer() method. I noticed that the MockReliableStateManager.TryAddStateSerializer() method is currently stubbed out. Is it feasible to implement this method to search for a serializer for a particular type before inserting data, so a deep copy is guaranteed for that type? Since we already use custom serialization, this would be enough to fix this for us.

I decided to open an issue first, to gauge interest in supporting this behavior before attempting a contribution.

To Reproduce

Here is a program that demonstrates this, modeled after the example in the reliable collections docs.

namespace MockReliableCollectionsBug
{
    using Microsoft.ServiceFabric.Data;
    using Microsoft.ServiceFabric.Data.Collections;
    using ServiceFabric.Mocks;
    using System;
    using System.Threading.Tasks;

    public static class MockReliableCollectionsBug
    {
        public class User
        {
            public string Name { get; set; }
            public DateTime LastLogin { get; set; }
        }

        public static async Task Main(string[] args)
        {
            MockReliableStateManager stateManager = new MockReliableStateManager();
            IReliableDictionary2<string, User> userDict = await stateManager.GetOrAddAsync<IReliableDictionary2<string, User>>("test");
            User user = new User { Name = "Gail", LastLogin = DateTime.UtcNow };

            using (ITransaction tx = stateManager.CreateTransaction())
            {
                await userDict.AddAsync(tx, user.Name, user);
                await tx.CommitAsync();
            }

            // Update the in-memory user's LastLogin.
            user.LastLogin = DateTime.UtcNow;

            using (ITransaction tx = stateManager.CreateTransaction())
            {
                ConditionalValue<User> storedUser = await userDict.TryGetValueAsync(tx, user.Name);
                // This should output false, as the storedUser's LastLogin should be the original value, but
                // it returns true, since the stored value is a direct reference, not a copy of the in-memory value
                // which has since been updated.
                Console.WriteLine(user.LastLogin == storedUser.Value.LastLogin);
                await tx.CommitAsync();
            }
        }
    }
}

Expected behavior Console should output false.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:14 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
loekdcommented, Feb 20, 2022

I was going for an approach that would closely mimic the real deal (which uses file streams). The end result is the same I suppose. Good point about the serializer type check.

I’ve also copied your key /value serializer approach in my latest push.

edit: I’ve also taken your serializer collection approach.

1reaction
loekdcommented, Feb 17, 2022

Sounds like a plan. Let’s make sure we follow the docs, concerning types (value types vs reference types). I’ve also got the plan to deprecate .NET 4.5 support and move everything to .NET6. You can find the branch here.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Deep copies in 2021 (non-serializable objects) [duplicate]
First you need to know that the type can be cloned. It needs to have a default constructor for one thing. And actual...
Read more >
Serialise, deserialise; for pickle, deepcopy · Issue #72
Here is a unit test showcasing the current inability to pickle, and deep-copy, unless I am misunderstanding how it is to be done...
Read more >
How to prevent Singleton Pattern from Reflection ...
Suppose, we create clone of a singleton object, then it will create a copy that is there are two instances of a singleton...
Read more >
Reliable Collection object serialization - Azure Service Fabric
Both to replicate and to persist items, Reliable Collections' need to serialize them. Reliable Collections' get the appropriate serializer for ...
Read more >
Bundle | Android Developers
Make a deep copy of the given bundle. Traverses into inner containers and copies them as well, so they are not shared across...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found