Пример #1
0
        public void ProcessChangeSet_update_cleanly_completes_without_error()
        {
            var context = A.Fake<IDataContext>();
            var resolver = A.Fake<IConflictResolver>();
            var bfim = A.Dummy<Models.Asset>();
            var afim = A.Dummy<Models.Asset>();

            var cs = new ChangeSet()
            {
                Assets = new List<ChangeItem<Models.Asset>>{
                     new ChangeItem<Models.Asset>{
                         Action = ChangeAction.Update,
                         BFIM = bfim,
                         AFIM = afim
                     }
                 }
            };

            var processor = new ChangeSetProcessor(context, resolver);
            var result = processor.Process(1, false, cs);

            ExceptionAssert.Throws<ArgumentNullException>(() => processor.Process(1, false, null));
            Assert.IsTrue(result.IsEmpty);
            Assert.AreEqual(ChangeSet.Empty, result);
            A.CallTo(() => context.Assets.Update(A<Models.Asset>.Ignored)).MustHaveHappened(Repeated.Exactly.Once);
            A.CallTo(() => context.Assets.Update(afim)).MustHaveHappened(Repeated.Exactly.Once);
            A.CallTo(() => context.AcceptChanges()).MustHaveHappened(Repeated.Exactly.Once);
        }
Пример #2
0
        public async Task TestDirectChangeset_Simple()
        {
            for (int i = 0; i < 100; i++)
            {
                TestDomainServices.TestProvider_Scenarios ds = new TestDomainServices.TestProvider_Scenarios();
                DomainServiceContext dsc = new DomainServiceContext(new MockDataService(new MockUser("mathew")), DomainOperationType.Submit);
                ds.Initialize(dsc);

                List <ChangeSetEntry> entries = new List <ChangeSetEntry>();
                for (int j = 0; j < 500; j++)
                {
                    TestDomainServices.POCONoValidation e = new TestDomainServices.POCONoValidation()
                    {
                        ID = i,
                        A  = "A" + i,
                        B  = "B" + i,
                        C  = "C" + i,
                        D  = "D" + i,
                        E  = "E" + i
                    };
                    entries.Add(new ChangeSetEntry(j, e, null, DomainOperation.Insert));
                }

                await ChangeSetProcessor.ProcessAsync(ds, entries);

                Assert.IsFalse(entries.Any(p => p.HasError));
            }
        }
Пример #3
0
        public void ProcessChangeSet_update_dirty_invokes_successful_resolver_and_successful_retry()
        {
            var repo = A.Fake<IRepository<Asset, int>>();
            var context = A.Fake<IDataContext>();
            var resolver = A.Fake<IConflictResolver>();
            var bfim = A.Dummy<Models.Asset>();
            var afim = A.Dummy<Models.Asset>();

            var cs = new ChangeSet()
            {
                Assets = new List<ChangeItem<Models.Asset>>{
                     new ChangeItem<Models.Asset>{
                         Action = ChangeAction.Update,
                         BFIM = bfim,
                         AFIM = afim
                     }
                 }
            };

            A.CallTo(() => repo.KeySelector).Returns((Asset a) => a.Id);
            A.CallTo(() => context.Assets).Returns(repo);
            A.CallTo(() => context.AcceptChanges()).Throws(new ConcurrencyException()).Once();
            A.CallTo(() => resolver.Resolve(repo, A<ChangeItem<Asset>>.Ignored, A<IDictionary<int,Asset>>.Ignored)).Returns(true);

            var processor = new ChangeSetProcessor(context, resolver);
            var result = processor.Process(1, false, cs);

            Assert.IsTrue(result.IsEmpty);
            Assert.AreEqual(ChangeSet.Empty, result);
            A.CallTo(() => context.Assets.Update(afim)).MustHaveHappened(Repeated.Exactly.Once);
            A.CallTo(() => context.AcceptChanges()).MustHaveHappened(Repeated.Exactly.Twice);
        }
Пример #4
0
        public async Task TestDirectChangeset_Cities()
        {
            for (int i = 0; i < 100; i++)
            {
                CityDomainService    ds  = new CityDomainService();
                DomainServiceContext dsc = new DomainServiceContext(new MockDataService(new MockUser("mathew")), DomainOperationType.Submit);
                ds.Initialize(dsc);

                List <ChangeSetEntry> entries = new List <ChangeSetEntry>();
                for (int j = 0; j < 500; j++)
                {
                    City newCity = new City()
                    {
                        Name = "Toledo", CountyName = "Lucas", StateName = "OH"
                    };
                    entries.Add(new ChangeSetEntry(j, newCity, null, DomainOperation.Insert));
                }

                await ChangeSetProcessor.ProcessAsync(ds, entries);

                Assert.IsFalse(entries.Any(p => p.HasError));
            }
        }
Пример #5
0
        public async Task Authorization_Custom_Authorization_On_Custom_Update()
        {
            // Specifically, the City data is marked so that no one can delete a Zip code
            // from WA unless their user name is WAGuy
            MockUser notWaGuy = new MockUser("notWAGuy");

            notWaGuy.IsAuthenticated = true;

            DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(typeof(CityDomainService));
            City city = null;

            // Execute a query to get a City from WA
            using (CityDomainService cities = new CityDomainService())
            {
                DomainOperationEntry getCitiesQuery = serviceDescription.GetQueryMethod("GetCities");

                // Now prepare for a query to find a Zip in WA
                DomainServiceContext ctxt = new WcfDomainServiceContext(new MockDataService(notWaGuy), DomainOperationType.Query);
                cities.Initialize(ctxt);

                IEnumerable result = (await cities.QueryAsync <City>(new QueryDescription(getCitiesQuery), CancellationToken.None)).Result;

                city = result.OfType <City>().FirstOrDefault(z => z.StateName == "WA");
                Assert.IsNotNull(city, "Could not find a city in WA");
            }


            using (CityDomainService cities = new CityDomainService())
            {
                // Now prepare for a submit to invoke AssignCityZoneIfAuthorized as a named update method
                DomainServiceContext ctxt = new WcfDomainServiceContext(new MockDataService(notWaGuy), DomainOperationType.Submit);
                cities.Initialize(ctxt);

                // Prepare an attempt to delete this with a user whose name is not WAGuy
                // This should fail due to a custom auth attribute
                List <ChangeSetEntry> entries = new List <ChangeSetEntry>();

                ChangeSetEntry entry = new ChangeSetEntry();
                entry.DomainOperationEntry = serviceDescription.GetCustomMethod(typeof(City), "AssignCityZoneIfAuthorized");
                entry.EntityActions        = new EntityActionCollection {
                    { "AssignCityZoneIfAuthorized", new object[] { "SomeZone" } }
                };
                entry.Operation = DomainOperation.Update;
                entry.Entity    = city;
                entries.Add(entry);

                UnauthorizedAccessException exception = null;
                try
                {
                    await ChangeSetProcessor.ProcessAsync(cities, entries);
                }
                catch (UnauthorizedAccessException ex)
                {
                    exception = ex;
                }
                Assert.IsNotNull(exception, "Expected failure attempting to perform custom method on WA with inappropriate user name");
                Assert.AreEqual("Only one user is authorized to execute operation 'AssignCityZoneIfAuthorized', and it isn't you.", exception.Message);
            }

            // Now do that again but with a user who is WAGuy -- it should succeed
            using (CityDomainService cities = new CityDomainService())
            {
                MockUser waGuy = new MockUser("WAGuy");
                waGuy.IsAuthenticated = true;

                // Now prepare for a submit to invoke AssignCityZoneIfAuthorized as a named update method
                DomainServiceContext ctxt = new WcfDomainServiceContext(new MockDataService(waGuy), DomainOperationType.Submit);
                cities.Initialize(ctxt);

                // Prepare an attempt to delete this with a user whose name is not WAGuy
                // This should fail due to a custom auth attribute

                // Prepare a submit to call the AssignCityZoneIfAuthorized with an unauthorized user
                List <ChangeSetEntry> entries = new List <ChangeSetEntry>();

                ChangeSetEntry entry = new ChangeSetEntry();
                entry.DomainOperationEntry = serviceDescription.GetCustomMethod(typeof(City), "AssignCityZoneIfAuthorized");
                entry.EntityActions        = new EntityActionCollection {
                    { "AssignCityZoneIfAuthorized", new object[] { "SomeZone" } }
                };
                entry.Operation = DomainOperation.Update;
                entry.Entity    = city;
                entries.Add(entry);

                Exception exception = null;
                try
                {
                    await ChangeSetProcessor.ProcessAsync(cities, entries);
                }
                catch (UnauthorizedAccessException ex)
                {
                    exception = ex;
                }
                Assert.IsNull(exception, "Expected success attempting to delete a zip from WA with inappropriate user name");
            }
        }
Пример #6
0
        public async Task Authorization_Custom_Authorization_On_CUD()
        {
            // Specifically, the City data is marked so that no one can delete a Zip code
            // from WA unless their user name is WAGuy
            MockUser notWaGuy = new MockUser("notWAGuy");

            notWaGuy.IsAuthenticated = true;

            DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(typeof(CityDomainService));
            Zip zip = null;

            // First execute a query to get some zips
            DomainOperationEntry getZipsQuery = serviceDescription.GetQueryMethod("GetZips");
            DomainServiceContext ctxt;

            using (CityDomainService cities = new CityDomainService())
            {
                // Now prepare for a query to find a Zip in WA
                ctxt = new WcfDomainServiceContext(new MockDataService(notWaGuy), DomainOperationType.Query);
                cities.Initialize(ctxt);
                IEnumerable result = (await cities.QueryAsync <Zip>(new QueryDescription(getZipsQuery), CancellationToken.None)).Result;

                zip = result.OfType <Zip>().FirstOrDefault(z => z.StateName == "WA");
                Assert.IsNotNull(zip, "Could not find a zip code in WA");
            }

            // Prepare a submit to delete this zip from a user who is not authorized
            using (CityDomainService cities = new CityDomainService())
            {
                // Now prepare for a query to find a Zip in WA
                ctxt = new WcfDomainServiceContext(new MockDataService(notWaGuy), DomainOperationType.Submit);
                cities.Initialize(ctxt);

                // Prepare an attempt to delete this with a user whose name is not WAGuy
                // This should fail due to a custom auth attribute
                List <ChangeSetEntry> entries = new List <ChangeSetEntry>();

                ChangeSetEntry entry = new ChangeSetEntry(1, zip, zip, DomainOperation.Delete);
                entries.Add(entry);
                UnauthorizedAccessException exception = null;
                try
                {
                    await ChangeSetProcessor.ProcessAsync(cities, entries);
                }
                catch (UnauthorizedAccessException ex)
                {
                    exception = ex;
                }
                Assert.IsNotNull(exception, "Expected failure attempting to delete a zip from WA with inappropriate user name");
                Assert.AreEqual("Only one user can delete zip codes from that state, and it isn't you.", exception.Message);
            }

            // Now do that again but with a user who is WAGuy -- it should succeed
            using (CityDomainService cities = new CityDomainService())
            {
                MockUser waGuy = new MockUser("WAGuy");
                waGuy.IsAuthenticated = true;

                // Now try a submit where the user *is* Mathew to validate we succeed
                ctxt = new WcfDomainServiceContext(new MockDataService(waGuy), DomainOperationType.Submit);
                cities.Initialize(ctxt);
                List <ChangeSetEntry> entries = new List <ChangeSetEntry>();

                ChangeSetEntry entry = new ChangeSetEntry(1, zip, zip, DomainOperation.Delete);
                entries.Add(entry);
                Exception exception = null;
                try
                {
                    await ChangeSetProcessor.ProcessAsync(cities, entries);
                }
                catch (UnauthorizedAccessException ex)
                {
                    exception = ex;
                }
                Assert.IsNull(exception, "Expected success attempting to delete a zip from WA with inappropriate user name");
            }
        }
Пример #7
0
 public OfflineController(ChangeSetProcessor changeSetProcessor)
 {
     _changeSetProcessor = changeSetProcessor;
 }
Пример #8
0
        public void ProcessChangeSet_update_dirty_invokes_unsuccessful_merge_and_no_retry()
        {
            var repo = A.Fake<IRepository<Asset, int>>();
            var context = A.Fake<IDataContext>();
            var resolver = new RejectConcurrentEditsConflictResolver();
            var afim = A.Dummy<Models.Asset>();

            var cs = new ChangeSet()
            {
                Assets = new List<ChangeItem<Models.Asset>>{
                     new ChangeItem<Models.Asset>{
                         Action = ChangeAction.Update,
                         BFIM = A.Dummy<Models.Asset>(),
                         AFIM = afim
                     }
                 }
            };
            A.CallTo(() => repo.KeySelector).Returns((Asset a) => a.Id);
            A.CallTo(() => context.Assets).Returns(repo);
            A.CallTo(() => context.AcceptChanges()).Throws(new ConcurrencyException()).Once();

            var processor = new ChangeSetProcessor(context, resolver);
            var result = processor.Process(1, false, cs);

            Assert.IsFalse(result.IsEmpty);
            Assert.AreNotEqual(ChangeSet.Empty, result);
            A.CallTo(() => context.Assets.Update(afim)).MustHaveHappened(Repeated.Exactly.Once);
            A.CallTo(() => context.AcceptChanges()).MustHaveHappened(Repeated.Exactly.Once);
        }
Пример #9
0
        public void ProcessChangeSet_which_locks_retains_lock_on_failed_merge()
        {
            var job = new Job() { Id = 42 };
            var context = A.Fake<IDataContext>();
            var resolver = A.Fake<IConflictResolver>();
            var bfim = A.Dummy<Models.Asset>();
            var afim = A.Dummy<Models.Asset>();

            var cs = new ChangeSet()
            {
                Assets = new List<ChangeItem<Models.Asset>>{
                    new ChangeItem<Models.Asset>(ChangeAction.Update,bfim,afim),
                    new ChangeItem<Models.Asset>(ChangeAction.Delete,A.Dummy<Asset>(),null),
                    new ChangeItem<Models.Asset>(ChangeAction.Create,null, A.Dummy<Asset>())
                }
            };

            A.CallTo(() => resolver.Resolve(A<IRepository<Asset, int>>.Ignored, A<ChangeItem<Asset>>.Ignored, A<IDictionary<int, Asset>>.Ignored)).Returns(false);
            A.CallTo(() => context.Jobs.GetById(A<int>.Ignored)).Returns(job);
            A.CallTo(() => context.Assets.KeySelector).Returns((Asset a) => a.Id);
            A.CallTo(() => context.AcceptChanges()).Throws(new ConcurrencyException());
            A.CallTo(() => context.AcceptChanges()).DoesNothing().Once();

            var processor = new ChangeSetProcessor(context, resolver);
            var result = processor.Process(1, true, cs);

            Assert.IsFalse(result.IsEmpty);
            Assert.AreNotEqual(ChangeSet.Empty, result);
            A.CallTo(() => context.Assets.Update(afim)).MustHaveHappened(Repeated.Exactly.Once);
            A.CallTo(() => context.AcceptChanges()).MustHaveHappened(Repeated.Exactly.Twice);
            A.CallTo(() => resolver.Resolve(A<IRepository<Asset, int>>.Ignored, A<ChangeItem<Asset>>.Ignored, A<IDictionary<int, Asset>>.Ignored)).MustHaveHappened(Repeated.Exactly.Once);
            //Assert.IsNotNull(job.LockedBy); // disabling this check temporarily this functionality was designed around EF and transaction rollbacks
        }
Пример #10
0
        public void ProcessChangeSet_throws_when_attempt_to_lock_closed_lock()
        {
            var context = A.Fake<IDataContext>();
            var cs = A.Dummy<ChangeSet>();

            A.CallTo(() => context.Jobs.GetById(A<int>.Ignored))
                .Returns(new Job() { LockedBy = "FooBar" });

            var processor = new ChangeSetProcessor(context, A.Dummy<IConflictResolver>());

            ExceptionAssert.Throws<ConcurrencyException>(() => processor.Process(A<int>.Ignored, true, cs));
        }
Пример #11
0
        public void ProcessChangeSet_throws_when_invalid_job_id_used_in_lock()
        {
            var context = A.Fake<IDataContext>();
            var cs = A.Dummy<ChangeSet>();

            A.CallTo(() => context.Jobs.GetById(A<int>.Ignored)).Returns(null);

            var processor = new ChangeSetProcessor(context, A.Dummy<IConflictResolver>());

            ExceptionAssert.Throws<EntityNotFoundException>(() => processor.Process(A<int>.Ignored, false, cs));
        }
Пример #12
0
        public void Get_initial_changeset_returns_only_partition_with_all_items_in_afim_and_action_is_initialize()
        {
            var assets = new List<Asset>
            {
                new Asset(){Id=1,JobId=0},
                new Asset(){Id=2,JobId=0},
                new Asset(){Id=3,JobId=1},
                new Asset(){Id=4,JobId=0}
            }.AsQueryable();

            var repo = A.Fake<IRepository<Asset, int>>();
            var context = A.Fake<IDataContext>();
            var resolver = A.Fake<IConflictResolver>();

            A.CallTo(() => repo.GetAll()).Returns(assets);
            A.CallTo(() => context.Assets).Returns(repo);

            var processor = new ChangeSetProcessor(context, resolver);
            var result = processor.BuildInitialChangeSet(0);



            A.CallTo(() => context.AcceptChanges()).MustNotHaveHappened();
            Assert.IsNotNull(result);
            Assert.IsFalse(result.IsEmpty);
            Assert.AreNotEqual(ChangeSet.Empty, result);
            //Assert.IsTrue(result.All(_ => _ is ChangeItem<Asset>));
            //Assert.IsTrue(result.All(_ => _.Action == ChangeAction.Initialize));
            //Assert.IsTrue(result.All(_ => _.GetBFIM() == null));
            //Assert.IsTrue(result.All(_ => _.GetAFIM() != null));
            //Assert.AreEqual(3, result.Assets.Count);
            //Assert.AreEqual(3, result.TotalItemsCount);
            //Assert.AreEqual(3, result.Count());
            Assert.IsTrue(result.Assets.All(_ => _.AFIM.JobId == 0));
        }
Пример #13
0
 private void Exec(int jobId, double pcPercent, double conflictGuarantee, IConflictResolver resolver)
 {
     bool claimIt = false;
     if (s_rng.NextDouble() < pcPercent)
         claimIt = true;
     var cs = BuildChangeSet(jobId);
     var dc = new Rel.Data.Ef6.TpContext();
     var res = resolver;
     var csp = new ChangeSetProcessor(dc, res);
     ChangeSet result;
     if (s_rng.NextDouble() < conflictGuarantee)
     {
         Touch(jobId, cs);
     }
     using (new Timed(false, "ChangeSet {0}", res.GetType().Name))
         result = csp.Process(jobId, claimIt, cs);
 }