public void ReadOnlySnapshot()
        {
            var blob = NewBlob();

            var writer = new CloudBlobBacked <string>(
                blob,
                writeToCloudFrequency: ShortInterval);

            writer.Object = "hello";

            PauseForReplication();

            var snapshot = new CloudBlobBacked <string>(blob);

            Assert.AreEqual("hello", snapshot.Object);

            writer.Object = "changed";

            PauseForReplication();

            Assert.AreEqual("hello", snapshot.Object);

            var snapshot2 = new CloudBlobBacked <string>(blob);

            Assert.AreEqual("changed", snapshot2.Object);

            writer.Shutdown();
        }
        public void ReaderWriterWithoutLease()
        {
            var blob = NewBlob();

            var writer = new CloudBlobBacked <string>(
                blob,
                leaseDuration: null,
                writeToCloudFrequency: ShortInterval);

            var reader = new CloudBlobBacked <string>(
                blob,
                readFromCloudFrequency: ShortInterval);

            writer.Object = "Hello world!";

            int attempts = 0;

            while (!writer.Object.Equals(reader.Object) && (attempts < 10))
            {
                PauseForReplication();
                attempts++;
            }

            Assert.AreEqual(writer.Object, "Hello world!");
            Assert.AreEqual(reader.Object, "Hello world!");

            reader.Shutdown();
            writer.Shutdown();
        }
        public void LockBlocksWrites()
        {
            var blob = NewBlob();

            var writer1 = new CloudBlobBacked <string>(
                blob,
                writeToCloudFrequency: ShortInterval);

            var writer2 = new CloudBlobBacked <string>(
                blob,
                writeToCloudFrequency: ShortInterval);

            writer1.Object = "hello";

            PauseForReplication();

            var reader = new CloudBlobBacked <string>(
                blob,
                readFromCloudFrequency: ShortInterval);

            Assert.AreEqual("hello", reader.Object);

            lock (writer1.SyncRoot)
            {
                Assert.AreEqual("hello", reader.Object);

                writer1.Object = "1";
                writer2.Object = "2";

                PauseForReplication();

                Assert.AreEqual("2", reader.Object);

                writer2.Shutdown();
            }

            PauseForReplication();

            Assert.AreEqual("1", reader.Object);

            reader.Shutdown();
            writer1.Shutdown();
            writer2.Shutdown();
        }
        public void Lease()
        {
            var blob = NewBlob();

            // Take a lease out on a new blob
            var exclusiveWriter = new CloudBlobBacked <string>(
                blob,
                writeToCloudFrequency: ShortInterval,
                leaseDuration: LeaseDuration);

            exclusiveWriter.Object = "Hello";

            // Verify that no one else can take the lease
            try
            {
                new CloudBlobBacked <string>(blob, leaseDuration: LeaseDuration);
                Assert.Fail("I managed to take a lease on this object form elsewhere");
            }
            catch (InvalidOperationException)
            {
            }

            // A reader is ok though
            PauseForReplication();
            var reader = new CloudBlobBacked <string>(blob, readFromCloudFrequency: ShortInterval);

            Assert.AreEqual("Hello", reader.Object);

            // Someone else can try and update it, but updates will not be made while the lease is active...
            var otherWriter = new CloudBlobBacked <string>(blob, writeToCloudFrequency: ShortInterval);

            otherWriter.Object = "I changed";
            PauseForReplication();
            Assert.AreNotEqual("I changed", reader.Object);
            Assert.AreEqual("I changed", otherWriter.Object);

            // The write will eventually be made after the lease is given up though
            exclusiveWriter.Shutdown();
            PauseForReplication();
            Assert.AreEqual("I changed", reader.Object);
            Assert.AreEqual("I changed", otherWriter.Object);

            reader.Shutdown();
            otherWriter.Shutdown();
        }
        public void MultipleWritersStress()
        {
            var blob = NewBlob();

            // Two instances fighting over the value of an object and a witness
            // that ensures they each win at least 'Difficulty' times.

            const int Difficulty = 4;

            var witness = new CloudBlobBacked <string>(
                blob,
                readFromCloudFrequency: ShortInterval);

            var writer1 = new CloudBlobBacked <string>(
                blob,
                readFromCloudFrequency: ShortInterval,
                writeToCloudFrequency: TimeSpan.FromSeconds(0.3));

            var writer2 = new CloudBlobBacked <string>(
                blob,
                readFromCloudFrequency: ShortInterval,
                writeToCloudFrequency: TimeSpan.FromSeconds(0.7));

            int writer1SuccessCount = 0;
            int writer2SuccessCount = 0;

            witness.OnUpdate += (s, e) =>
            {
                writer1SuccessCount += "1".Equals(witness.Object) ? 1 : 0;
                writer2SuccessCount += "2".Equals(witness.Object) ? 1 : 0;
            };

            while ((writer1SuccessCount < Difficulty) || (writer2SuccessCount < Difficulty))
            {
                writer1.Object = "1";
                writer2.Object = "2";
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
            }

            witness.Shutdown();
            writer1.Shutdown();
            writer2.Shutdown();
        }
        public void ReaderWriterWithLease()
        {
            var blob = NewBlob();

            var writer = new CloudBlobBacked <string>(
                blob,
                leaseDuration: LeaseDuration,
                writeToCloudFrequency: ShortInterval);

            var reader = new CloudBlobBacked <string>(
                blob,
                readFromCloudFrequency: ShortInterval);

            writer.Object = "Hello world!";

            PauseForReplication();

            Assert.AreEqual(writer.Object, reader.Object);

            reader.Shutdown();
            writer.Shutdown();
        }
        private void AllVariations <T>(Action <CloudBlobBacked <T> > test) where T : class
        {
            Trace.TraceInformation("readOnce");
            var readOnce =
                new CloudBlobBacked <T>(NewBlob());

            test(readOnce);
            readOnce.Shutdown();

            Trace.TraceInformation("readOnceUnderLease");
            var readOnceUnderLease =
                new CloudBlobBacked <T>(NewBlob(), leaseDuration: LeaseDuration);

            test(readOnceUnderLease);
            readOnceUnderLease.Shutdown();

            Trace.TraceInformation("readContinually");
            var readContinually =
                new CloudBlobBacked <T>(NewBlob(), readFromCloudFrequency: ShortInterval);

            test(readContinually);
            readContinually.Shutdown();

            Trace.TraceInformation("readContinuallyUnderLease");
            var readContinuallyUnderLease = new CloudBlobBacked <T>(
                NewBlob(),
                readFromCloudFrequency: ShortInterval,
                leaseDuration: LeaseDuration);

            test(readContinuallyUnderLease);
            readContinuallyUnderLease.Shutdown();

            Trace.TraceInformation("writeContinually");
            var writeContinually =
                new CloudBlobBacked <T>(NewBlob(), writeToCloudFrequency: ShortInterval);

            test(writeContinually);
            writeContinually.Shutdown();

            Trace.TraceInformation("writeContinuallyUnderLease");
            var writeContinuallyUnderLease = new CloudBlobBacked <T>(
                NewBlob(),
                writeToCloudFrequency: ShortInterval,
                leaseDuration: LeaseDuration);

            test(writeContinuallyUnderLease);
            writeContinuallyUnderLease.Shutdown();

            Trace.TraceInformation("readWriteContinually");
            var readWriteContinually = new CloudBlobBacked <T>(
                NewBlob(),
                readFromCloudFrequency: ShortInterval,
                writeToCloudFrequency: ShortInterval);

            test(readWriteContinually);
            readWriteContinually.Shutdown();

            Trace.TraceInformation("readWriteContinuallyUnderLease");
            var readWriteContinuallyUnderLease = new CloudBlobBacked <T>(
                NewBlob(),
                readFromCloudFrequency: ShortInterval,
                writeToCloudFrequency: ShortInterval,
                leaseDuration: LeaseDuration);

            test(readWriteContinuallyUnderLease);
            readWriteContinuallyUnderLease.Shutdown();
        }