public void Load_ValidationErrors() { var mockDomainClient = new CitiesMockDomainClient(); ValidationResult[] validationErrors = new ValidationResult[] { new ValidationResult("Foo", new string[] { "Bar" }) }; mockDomainClient.QueryCompletedResult = Task.FromResult(new QueryCompletedResult(Enumerable.Empty <Entity>(), Enumerable.Empty <Entity>(), 0, validationErrors)); Cities.CityDomainContext ctx = new Cities.CityDomainContext(mockDomainClient); string myState = "Test User State"; LoadOperation <Cities.City> loadOperation = ctx.Load(ctx.GetCitiesQuery(), LoadBehavior.RefreshCurrent, l => l.MarkErrorAsHandled(), myState);; this.EnqueueCompletion(() => loadOperation); EnqueueCallback(delegate { Assert.AreSame(myState, loadOperation.UserState); CollectionAssert.AreEqual(validationErrors, (ICollection)loadOperation.ValidationErrors); // verify the exception properties var ex = loadOperation.Error as DomainOperationException; Assert.IsNotNull(ex, "expected exception of type DomainOperationException"); Assert.AreEqual(OperationErrorStatus.ValidationFailed, ex.Status); Assert.AreEqual(string.Format(Resource.DomainContext_LoadOperationFailed_Validation, "GetCities"), ex.Message); }); EnqueueTestComplete(); }
public async Task Load_Cancel_DomainClientCancel() { var mockDomainClient = new CitiesMockDomainClient(); Cities.CityDomainContext ctx = new Cities.CityDomainContext(mockDomainClient); // If cancellation results in request beeing cancelled the result should be cancelled var tcs = new TaskCompletionSource <QueryCompletedResult>(); mockDomainClient.QueryCompletedResult = tcs.Task; var loadOp = ctx.Load(ctx.GetCitiesQuery()); loadOp.Cancel(); Assert.IsTrue(loadOp.IsCancellationRequested); Assert.IsTrue(ctx.IsLoading); Assert.IsFalse(loadOp.IsCanceled); Assert.IsFalse(loadOp.IsComplete); tcs.TrySetCanceled(loadOp.CancellationToken); await loadOp; Assert.IsFalse(ctx.IsLoading); Assert.IsTrue(loadOp.IsCanceled); Assert.IsTrue(loadOp.IsComplete); Assert.IsFalse(loadOp.HasError, "Cancelled operation should not have any error"); }
public void ExogenousDomainClient() { Cities.CityDomainContext ctxt1 = new CityDomainContext(TestURIs.Cities); Cities.CityDomainContext ctxt2 = new CityDomainContext(TestURIs.Cities); var q1 = ctxt1.GetCitiesInStateQuery("OH"); ExceptionHelper.ExpectInvalidOperationException(delegate { ctxt2.Load(q1, false); }, string.Format(Resource.DomainContext_InvalidEntityQueryDomainClient, q1.QueryName)); }
public async Task Load() { Cities.CityDomainContext ctx = new Cities.CityDomainContext(new CitiesMockDomainClient()); string myState = "Test User State"; var query = ctx.GetCitiesQuery().Where(p => p.StateName == "WA").OrderBy(p => p.CountyName).Take(4); LoadOperation lo = ctx.Load(query, TestHelperMethods.DefaultOperationAction, myState); await lo; Assert.IsNull(lo.Error); Assert.AreEqual(4, ctx.Cities.Count); Assert.IsTrue(ctx.Cities.All(p => p.StateName == "WA")); Assert.AreEqual(myState, lo.UserState); }
public void CancellationSupport() { var domainClient = new CitiesMockDomainClient(); domainClient.SetSupportsCancellation(false); Cities.CityDomainContext ctx = new Cities.CityDomainContext(domainClient); var query = ctx.GetCitiesQuery(); LoadOperation lo = ctx.Load(query, false); Assert.IsFalse(lo.CanCancel, "Cancellation should not be supported."); Assert.IsFalse(ctx.DomainClient.SupportsCancellation, "Cancellation should not be supported."); ExceptionHelper.ExpectException <NotSupportedException>(delegate { lo.Cancel(); }, string.Format(CultureInfo.CurrentCulture, Resources.AsyncOperation_CancelNotSupported)); }
public void Cities_LoadStates_TestEnums() { CityDomainContext dp = new CityDomainContext(TestURIs.Cities); SubmitOperation so = null; LoadOperation lo = dp.Load(dp.GetStatesQuery().Where(s => s.TimeZone == Cities.TimeZone.Pacific), false); EnqueueConditional(() => lo.IsComplete); EnqueueCallback(() => { if (lo.Error != null) Assert.Fail("LoadOperation.Error: " + lo.Error.Message); // verify the TimeZones were serialized to the client properly State state = dp.States.Single(p => p.Name == "WA"); Assert.AreEqual(Cities.TimeZone.Pacific, state.TimeZone); Assert.IsFalse(dp.States.Any(p => p.Name == "OH")); // Now test update state.TimeZone = state.TimeZone = Cities.TimeZone.Central; Assert.AreEqual(EntityState.Modified, state.EntityState); EntityChangeSet cs = dp.EntityContainer.GetChanges(); Assert.IsTrue(cs.ModifiedEntities.Contains(state)); so = dp.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); }); EnqueueConditional(() => so.IsComplete); EnqueueCallback(() => { TestHelperMethods.AssertOperationSuccess(so); }); EnqueueTestComplete(); }
public void DomainContext_Submit_ValidationErrorOnServer() { CityDomainContext citiesProvider = new CityDomainContext(TestURIs.Cities); Zip newZip = null; SubmitOperation so = null; LoadOperation lo = citiesProvider.Load(citiesProvider.GetZipsQuery(), false); // wait for Load to complete, then invoke domain method that throws on server. Submit. EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { // Add an entity that will cause a Validation exception on the server (99999 is used as a way to signal failure for our validator) newZip = new Zip() { Code = 99999, FourDigit = 8625, CityName = "Redmond", CountyName = "King", StateName = "WA" }; citiesProvider.Zips.Add(newZip); newZip.ThrowException("InvalidOperationException"); so = citiesProvider.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); }); EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { DomainOperationException ex = so.Error as DomainOperationException; Assert.IsNotNull(ex); Assert.AreEqual(OperationErrorStatus.ValidationFailed, ex.Status); Assert.AreEqual(Resource.DomainContext_SubmitOperationFailed_Validation, ex.Message); IEnumerable<ValidationResult> errors = newZip.ValidationErrors; LogErrorListContents("newZip.ValidationErrors", errors); Assert.AreEqual(1, errors.Count()); UnitTestHelper.AssertListContains<ValidationResult>(errors, (e => e.ErrorMessage == "Server fails validation")); }); EnqueueTestComplete(); }
public void DomainContext_Submit_ErrorsClearOnReject() { int refZip = 0; CityDomainContext citiesProvider = new CityDomainContext(TestURIs.Cities); SubmitOperation so = null; LoadOperation lo = citiesProvider.Load(citiesProvider.GetZipsQuery(), false); // wait for Load to complete, then invoke domain method that throws on server. Submit. EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { // invoke methods that cause exception Zip[] zips = citiesProvider.Zips.ToArray(); zips[0].ThrowException("ValidationException"); so = citiesProvider.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); }); // wait for submitted event being fired and verify Entity.ValidationErrors is not empty EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { DomainOperationException ex = so.Error as DomainOperationException; Assert.IsNotNull(ex); Zip zip = citiesProvider.Zips.First(); IEnumerable<ValidationResult> errors = zip.ValidationErrors; LogErrorListContents("zips[0].ValidationErrors", errors); Assert.AreEqual(1, errors.Count()); // Verify that failed submission does not clear out the last invocation Assert.IsFalse(zip.CanThrowException); Assert.IsTrue(zip.EntityActions.Any(a => a.Name == "ThrowException")); // Add a custom validation error to ensure it gets cleared zip.ValidationErrors.Add(new ValidationResult("Temporary Error")); // Call RejectChanges and verify ValidationErrors collection is cleared citiesProvider.RejectChanges(); Assert.IsFalse(zip.ValidationErrors.Any()); // Invoke domain method that does not throw on same entity zip.ReassignZipCode(1, true); refZip = zip.Code; so = citiesProvider.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); }); // wait for submitted event being fired and verify Entity.ValidationErrors remains empty EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { Zip zip = citiesProvider.Zips.First(); Assert.IsNull(so.Error); Assert.IsFalse(zip.ValidationErrors.Any()); Assert.AreEqual(refZip + 1, zip.Code); }); EnqueueTestComplete(); }
public void Bug706066_CancelInCallback() { Cities.CityDomainContext cities = new CityDomainContext(TestURIs.Cities); bool callbackCalled = false; InvalidOperationException expectedException = null; Action<LoadOperation<City>> callback = (op) => { if (op.HasError) { op.MarkErrorAsHandled(); } // verify that CanCancel is false even though we'll // ignore this and try below Assert.IsFalse(op.CanCancel); try { op.Cancel(); } catch (InvalidOperationException io) { expectedException = io; } callbackCalled = true; }; var q = cities.GetCitiesQuery().Take(1); LoadOperation lo = cities.Load(q, callback, null); EnqueueConditional(() => lo.IsComplete && callbackCalled); EnqueueCallback(delegate { Assert.IsFalse(lo.IsCanceled); Assert.AreEqual(Resources.AsyncOperation_AlreadyCompleted, expectedException.Message); }); EnqueueTestComplete(); }
public void Bug706034_AccessCachedEntityResultsInCallback() { Cities.CityDomainContext cities = new CityDomainContext(TestURIs.Cities); bool callbackCalled = false; Exception callbackException = null; Action<LoadOperation<City>> callback = (op) => { if (op.HasError) { op.MarkErrorAsHandled(); } try { Assert.AreEqual(11, op.AllEntities.Count()); Assert.AreEqual(11, op.Entities.Count()); } catch (Exception e) { callbackException = e; } finally { callbackCalled = true; } }; var q = cities.GetCitiesQuery(); LoadOperation<City> lo = cities.Load(q, callback, null); // KEY to bug : access Entity collections to force them to cache IEnumerable<City> entities = lo.Entities; IEnumerable<Entity> allEntities = lo.AllEntities; EnqueueConditional(() => lo.IsComplete && callbackCalled); EnqueueCallback(delegate { Assert.IsNull(callbackException); Assert.IsNull(lo.Error); Assert.AreEqual(11, lo.AllEntities.Count()); Assert.AreEqual(11, lo.Entities.Count()); }); EnqueueTestComplete(); }
public void Cities_TestLoad_Demo() { CityDomainContext dp = new CityDomainContext(TestURIs.Cities); // Abs URI so runs on desktop too LoadOperation lo = dp.Load(dp.GetCitiesQuery(), false); After(() => lo.IsComplete); Then(() => { if (lo.Error != null) Assert.Fail("LoadOperation.Error: " + lo.Error.Message); }); Then(() => AssertSame(new CityData().Cities, dp.Cities)); EnqueueTestComplete(); }
public void ErrorPipeline_DomainServiceEx() { CityDomainContext citiesProvider = new CityDomainContext(TestURIs.Cities); LoadOperation lo = citiesProvider.Load(citiesProvider.GetZipsQuery(), false); SubmitOperation so = null; // wait for Load to complete, then invoke domain method that throws on server. Submit. EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { Zip zip = citiesProvider.Zips.First(); zip.ThrowException("DomainServiceExceptionWithErrorCode"); so = citiesProvider.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); }); EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { DomainException ex = so.Error as DomainException; Assert.IsNotNull(ex); Assert.AreEqual("testing with error code", ex.Message); Assert.AreEqual(10, ex.ErrorCode); }); EnqueueTestComplete(); }
public void DomainContext_Submit_DomainMethodsThrow_EntityValidationError() { List<string>[] propChanged = new List<string>[] { new List<string>(), new List<string>(), new List<string>() }; int refZip = 0; CityDomainContext citiesProvider = new CityDomainContext(TestURIs.Cities); SubmitOperation so = null; LoadOperation lo = citiesProvider.Load(citiesProvider.GetZipsQuery(), false); // wait for Load to complete, then invoke some domain methods EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { // invoke methods that cause exception Zip[] zips = citiesProvider.Zips.ToArray(); citiesProvider.ThrowException(zips[0], "EntityValidationException"); citiesProvider.ThrowException(zips[1], "EntityValidationException"); // invoke method that does not cause exception zips[2].ReassignZipCode(1, true); refZip = zips[2].Code; zips[0].PropertyChanged += delegate(object sender, System.ComponentModel.PropertyChangedEventArgs e) { propChanged[0].Add(e.PropertyName); }; zips[1].PropertyChanged += delegate(object sender, System.ComponentModel.PropertyChangedEventArgs e) { propChanged[1].Add(e.PropertyName); }; zips[2].PropertyChanged += delegate(object sender, System.ComponentModel.PropertyChangedEventArgs e) { propChanged[2].Add(e.PropertyName); }; so = citiesProvider.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); }); EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { Assert.IsNotNull(so.Error); DomainOperationException ex = so.Error as DomainOperationException; // this is a case where method invocations causes a ValidationException. Assert.AreEqual(OperationErrorStatus.ValidationFailed, ex.Status); Assert.AreEqual(Resource.DomainContext_SubmitOperationFailed_Validation, ex.Message); // verify ValidationError collection is correct Zip[] zips = citiesProvider.Zips.ToArray(); IEnumerable<ValidationResult> errors = zips[0].ValidationErrors; LogErrorListContents("citiesProvider.Zips[0].ValidationErrors", errors); Assert.AreEqual(1, errors.Count()); ValidationResult vr = errors.First(); Assert.AreEqual("Invalid Zip properties!", vr.ErrorMessage); Assert.AreEqual(2, vr.MemberNames.Count()); Assert.IsTrue(vr.MemberNames.Contains("CityName")); Assert.IsTrue(vr.MemberNames.Contains("CountyName")); errors = zips[1].ValidationErrors; LogErrorListContents("citiesProvider.Zips[0].ValidationErrors", errors); Assert.AreEqual(1, errors.Count()); vr = errors.First(); Assert.AreEqual("Invalid Zip properties!", vr.ErrorMessage); Assert.AreEqual(2, vr.MemberNames.Count()); Assert.IsTrue(vr.MemberNames.Contains("CityName")); Assert.IsTrue(vr.MemberNames.Contains("CountyName")); // verify the Entity.ValidationErrors collection is populated as expected Assert.IsTrue(propChanged[0].Contains("HasValidationErrors")); Assert.IsTrue(propChanged[1].Contains("HasValidationErrors")); // verify entities are not auto-synced back to the client because there were errors Assert.IsFalse(propChanged[2].Contains("Code")); Assert.IsFalse(propChanged[2].Contains("FourDigit")); Assert.IsFalse(propChanged[2].Contains("HasValidationErrors")); Assert.AreEqual(0, zips[2].ValidationErrors.Count()); Assert.AreEqual(refZip, zips[2].Code); }); EnqueueTestComplete(); }
public void Inherit_Run_Call_Derived_Custom_Method_On_Abstract_Base_() { // Inheritance is City <-- CityWithEditHistory <-- CityWithInfo // This test invokes a custom method declared on CityWithEditHistory via a CityWithInfo instance EntityChangeSet changeset; List<string> propChanged = new List<string>(); CityDomainContext citiesProvider = new CityDomainContext(TestURIs.Cities); CityWithInfo cityWithInfo = null; DateTime priorLastUpdated = DateTime.Now; LoadOperation lo = citiesProvider.Load(citiesProvider.GetCitiesWithInfoQuery()); SubmitOperation so = null; // wait for Load to complete, then invoke some domain methods EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { cityWithInfo = citiesProvider.Cities.FirstOrDefault() as CityWithInfo; Assert.IsNotNull(cityWithInfo, "Cities[0] should have been CityWithInfo but was " + citiesProvider.Cities.First().GetType().Name); changeset = citiesProvider.EntityContainer.GetChanges(); Assert.IsTrue(changeset.IsEmpty); cityWithInfo.PropertyChanged += delegate(object sender, System.ComponentModel.PropertyChangedEventArgs e) { // We filter to only those properties we see in the City hierarchy BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; bool isCityProperty = (typeof(CityWithInfo).GetProperty(e.PropertyName, flags) != null || typeof(CityWithEditHistory).GetProperty(e.PropertyName, flags) != null || typeof(City).GetProperty(e.PropertyName, flags) != null); if (isCityProperty) { propChanged.Add(e.PropertyName); } }; priorLastUpdated = cityWithInfo.LastUpdated; Assert.IsTrue(cityWithInfo.CanTouchHistory); cityWithInfo.TouchHistory("xxx"); }); // wait for prop changed for domain method guards EnqueueConditional(() => propChanged.Count > 0); // Inject small delay so DateTime.Now executed on server is later than value in cithWithInfo EnqueueDelay(50); // Test validation that we will, in fact, get a different time stamp EnqueueCallback(delegate { Assert.AreNotEqual(priorLastUpdated, DateTime.Now, "Expected difference in times after small delay"); }); EnqueueCallback(delegate { Assert.IsTrue(propChanged.Contains("CanTouchHistory")); propChanged.Clear(); changeset = citiesProvider.EntityContainer.GetChanges(); Assert.AreEqual(1, changeset.ModifiedEntities.Count); so = citiesProvider.SubmitChanges(); Assert.AreEqual(1, so.ChangeSet.ModifiedEntities.Count); Assert.AreEqual(0, so.ChangeSet.AddedEntities.Count); Assert.AreEqual(0, so.ChangeSet.RemovedEntities.Count); }); // wait for submit to complete, then verify invokedEntities in changeset EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { Assert.IsNull(so.Error); Assert.AreEqual(1, so.ChangeSet.ModifiedEntities.Count); // verify we got the property change notification for the city entity as a result of autosync Assert.AreEqual(12, propChanged.Count, "Received different property notifications than expected:\r\n" + string.Join(",", propChanged.ToArray())); Assert.AreEqual(1, propChanged.Count(prop => prop =="EditHistory")); Assert.AreEqual(1, propChanged.Count(prop => prop =="LastUpdated")); Assert.AreEqual(2, propChanged.Count(prop => prop =="CanAssignCityZone")); Assert.AreEqual(2, propChanged.Count(prop => prop =="CanAssignCityZoneIfAuthorized")); Assert.AreEqual(2, propChanged.Count(prop => prop =="CanAutoAssignCityZone")); Assert.AreEqual(1, propChanged.Count(prop => prop =="CanTouchHistory")); Assert.AreEqual(1, propChanged.Count(prop => prop =="IsTouchHistoryInvoked")); Assert.AreEqual(2, propChanged.Count(prop => prop =="CanSetCityInfo")); // verify entities are auto-synced back to the client as a result of the domain method execution on server CityWithInfo newCityWithInfo = citiesProvider.Cities.OfType<CityWithInfo>().SingleOrDefault<CityWithInfo>(c => (c.EditHistory.Contains("touch"))); Assert.IsNotNull(newCityWithInfo, "Did not find modified CityWithInfo after the submit"); Assert.AreNotEqual(newCityWithInfo.LastUpdated, priorLastUpdated, "Expected lastUpdated to be modified by submit"); Assert.IsTrue(newCityWithInfo.EditHistory.Contains("touch=xxx"), "EditHistory was" + newCityWithInfo.EditHistory); }); EnqueueTestComplete(); }
public void Inherit_Run_Call_Base_Custom_Method_On_Derived_Entity() { EntityChangeSet changeset; List<string> propChanged = new List<string>(); CityDomainContext citiesProvider = new CityDomainContext(TestURIs.Cities); LoadOperation lo = citiesProvider.Load(citiesProvider.GetCitiesQuery()); SubmitOperation so = null; CityWithInfo cityWithInfo = null; // wait for Load to complete, then invoke some domain methods EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { changeset = citiesProvider.EntityContainer.GetChanges(); Assert.IsTrue(changeset.IsEmpty); cityWithInfo = citiesProvider.Cities.OfType<CityWithInfo>().FirstOrDefault(); Assert.IsNotNull(cityWithInfo, "Expected to find a CityWithInfo type in entity list"); cityWithInfo.PropertyChanged += delegate(object sender, System.ComponentModel.PropertyChangedEventArgs e) { // We filter to only those properties we see in the City hierarchy BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; bool isCityProperty = (typeof(CityWithInfo).GetProperty(e.PropertyName, flags) != null || typeof(CityWithEditHistory).GetProperty(e.PropertyName, flags) != null || typeof(City).GetProperty(e.PropertyName, flags) != null); if (isCityProperty) { propChanged.Add(e.PropertyName); } }; Assert.IsTrue(cityWithInfo.CanAssignCityZone); cityWithInfo.AssignCityZone("Zone15"); }); // wait for prop changed for domain method guards EnqueueConditional(() => propChanged.Count > 0); EnqueueCallback(delegate { Assert.IsTrue(propChanged.Contains("CanAssignCityZone")); propChanged.Clear(); changeset = citiesProvider.EntityContainer.GetChanges(); Assert.AreEqual(1, changeset.ModifiedEntities.Count); so = citiesProvider.SubmitChanges(); Assert.AreEqual(1, so.ChangeSet.ModifiedEntities.Count); Assert.AreEqual(0, so.ChangeSet.AddedEntities.Count); Assert.AreEqual(0, so.ChangeSet.RemovedEntities.Count); }); // wait for submit to complete, then verify invokedEntities in changeset EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { if (so.Error != null) { Assert.Fail(so.Error.Message); } Assert.AreEqual(1, so.ChangeSet.ModifiedEntities.Count); // verify we got the property change notification for the city entity as a result of autosync Assert.AreEqual(13, propChanged.Count, "Received different property notifications than expected:\r\n" + string.Join(",", propChanged.ToArray())); Assert.AreEqual(1, propChanged.Count(prop => prop == "EditHistory")); Assert.AreEqual(1, propChanged.Count(prop => prop == "ZoneName")); Assert.AreEqual(1, propChanged.Count(prop => prop == "ZoneID")); Assert.AreEqual(1, propChanged.Count(prop => prop == "CanAssignCityZone")); Assert.AreEqual(1, propChanged.Count(prop => prop == "IsAssignCityZoneInvoked")); Assert.AreEqual(2, propChanged.Count(prop => prop == "CanAutoAssignCityZone")); Assert.AreEqual(2, propChanged.Count(prop => prop == "CanAssignCityZoneIfAuthorized")); Assert.AreEqual(2, propChanged.Count(prop => prop == "CanSetCityInfo")); Assert.AreEqual(2, propChanged.Count(prop => prop == "CanTouchHistory")); // verify entities are auto-synced back to the client as a result of the domain method execution on server Assert.AreEqual(15, citiesProvider.Cities.Single<City>(c => (c.ZoneName == "Zone15")).ZoneID); // verify unchanged entities Assert.AreEqual(0, citiesProvider.Cities.First(c => (c.ZoneName == null)).ZoneID); }); EnqueueTestComplete(); }
public void Cities_ShouldSupportLongQueries() { LoadOperation<Zip> lo = null; const int zipToFind = 98053; const int QUERY_ITERATIONS = 50; EnqueueCallback(() => { CityDomainContext dp = new CityDomainContext(TestURIs.Cities); // Abs URI so runs on desktop too // Generate a really long query // The load will result in a query where just the query part has length > 3000 var query = dp.GetZipsQuery(); // Create a query with QUERY_ITERATIONS where statements checking a range of QUERY_ITERATIONS each // this should in the end if simplified result in Code = zipToFind (zipToFind - 1 < Code <= zipToFind) for (int i = 0; i < QUERY_ITERATIONS; ++i) { int min = zipToFind + i - QUERY_ITERATIONS; int max = zipToFind + i; query = query.Where(c => min < c.Code && c.Code <= max); } lo = dp.Load(query, false); }); EnqueueConditional(() => lo.IsComplete); EnqueueCallback(() => { if (lo.Error != null) Assert.Fail("LoadOperation.Error: " + lo.Error.Message); var expected = new CityData().Zips.Single(z => z.Code == zipToFind); Assert.AreEqual(1, lo.Entities.Count(), "Wrong number of entities returned"); var returned = lo.Entities.Single(); Assert.AreEqual(expected.Code, returned.Code); Assert.AreEqual(expected.FourDigit, returned.FourDigit); Assert.AreEqual(expected.CityName, returned.CityName); Assert.AreEqual(expected.CountyName, returned.CountyName); Assert.AreEqual(expected.StateName, returned.StateName); }); EnqueueTestComplete(); }
public void Cities_Cities_In_County_Serialized_Query() { CityDomainContext dp = new CityDomainContext(TestURIs.Cities); // Abs URI so runs on desktop too // Pass the query to the server to select only cities in King county var cityQuery = dp.GetCitiesQuery().Where(c => c.CountyName == "King"); LoadOperation lo = dp.Load(cityQuery, false); EnqueueConditional(() => lo.IsComplete); EnqueueCallback(() => { if (lo.Error != null) Assert.Fail("LoadOperation.Error: " + lo.Error.Message); IEnumerable<City> expected = new CityData().Cities.Where(c => c.CountyName == "King"); AssertSame(expected, dp.Cities); }); EnqueueTestComplete(); }
public void TestEmptyStringParameter() { CityDomainContext dp = new CityDomainContext(TestURIs.Cities); LoadOperation lo = dp.Load(dp.GetCitiesInStateQuery(string.Empty), false); EnqueueConditional(() => lo.IsComplete); EnqueueCallback(() => { if (lo.Error != null) Assert.Fail("LoadOperation.Error: " + lo.Error.Message); Assert.AreEqual(0, dp.Cities.Count); }); EnqueueTestComplete(); }
public void Cities_Cities_In_State_Parameterized_Query() { CityDomainContext dp = new CityDomainContext(TestURIs.Cities); // Abs URI so runs on desktop too LoadOperation lo = dp.Load(dp.GetCitiesInStateQuery("WA"), false); EnqueueConditional(() => lo.IsComplete); EnqueueCallback(() => { if (lo.Error != null) Assert.Fail("LoadOperation.Error: " + lo.Error.Message); IEnumerable<City> expected = new CityData().Cities.Where(c => c.StateName.Equals("WA")); AssertSame(expected, dp.Cities); // Validate a [Editable(false)] property deserialized properly foreach (City c in dp.Cities) Assert.AreEqual(c.CountyName, c.CalculatedCounty); }); EnqueueTestComplete(); }
public void DomainContext_Submit_CUDOperationMethodValidation() { CityDomainContext ctxt = new CityDomainContext(TestURIs.Cities); LoadOperation lo = ctxt.Load(ctxt.GetCitiesQuery(), false); SubmitOperation so = null; EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { TestHelperMethods.AssertOperationSuccess(lo); // update City[] cities = ctxt.Cities.Where(p => p.GetType() == typeof(City)).ToArray(); City city = cities[0]; city.ZoneID = 693; // custom method city.AssignCityZone("Z1"); // delete City deletedCity = new City() { Name = "Issaquah", CountyName = "King", StateName = "WA", ZoneID = 693 }; ctxt.Cities.Attach(deletedCity); ctxt.Cities.Remove(deletedCity); // insert City newCity = new City() { Name = "Sylvannia", CountyName = "Lucas", StateName = "OH" }; newCity.ZoneID = 693; ctxt.Cities.Add(newCity); so = ctxt.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); }); EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { DomainOperationException ex = so.Error as DomainOperationException; Assert.IsNotNull(ex); Assert.AreEqual(OperationErrorStatus.ValidationFailed, ex.Status); Assert.AreEqual(Resource.DomainContext_SubmitOperationFailed_Validation, ex.Message); EntityChangeSet cs = so.ChangeSet; City city = (City)cs.AddedEntities.Single(); Assert.AreEqual("CityMethodValidator.ValidateMethod Failed (InsertCity)!", city.ValidationErrors.Single().ErrorMessage); city = (City)cs.ModifiedEntities.Single(); ValidationResult[] validationResults = city.ValidationErrors.ToArray(); Assert.AreEqual("CityMethodValidator.ValidateMethod Failed (UpdateCity)!", validationResults[0].ErrorMessage); Assert.AreEqual("CityMethodValidator.ValidateMethod Failed (AssignCityZone)!", validationResults[1].ErrorMessage); city = (City)cs.RemovedEntities.Single(); Assert.AreEqual("CityMethodValidator.ValidateMethod Failed (DeleteCity)!", city.ValidationErrors.Single().ErrorMessage); }); EnqueueTestComplete(); }
public void DomainContext_Submit_ValidationErrorDuringClientSubmit() { CityDomainContext citiesProvider = new CityDomainContext(TestURIs.Cities); Zip newZip = new Zip() { Code = 98765, FourDigit = 1234 }; Zip validZip = new Zip() { Code = 90000, FourDigit = 1000, CityName = "MyCity", StateName = "MY" }; City deletedCity = null; SubmitOperation so = null; LoadOperation loadCitiesOperation = citiesProvider.Load(citiesProvider.GetCitiesQuery(), false); LoadOperation loadZipsOperation = citiesProvider.Load(citiesProvider.GetZipsQuery(), false); // wait for Load to complete, then invoke domain method that throws on server. Submit. EnqueueConditional(() => loadCitiesOperation.IsComplete && loadZipsOperation.IsComplete); EnqueueCallback(delegate { // update entity in a way that caused entity validation to fail on client Zip[] zips = citiesProvider.Zips.ToArray(); zips[0].CityName = zips[0].StateName; // internally set domain method invocation to cause method param validation to fail on client zips[0].CustomMethodInvocation = new EntityAction("ReassignZipCode", new object[] { -10000, true }); // insert entity that caused object/property validation to fail on client citiesProvider.Zips.Add(newZip); // Add a temporary error to that invalid object to ensure errors are reset during submit newZip.ValidationErrors.Add(new ValidationResult("Temporary Error", new string[] { "StateName" })); // insert entity that is valid citiesProvider.Zips.Add(validZip); // Add a temporary error to that valid object to ensure errors are reset during submit validZip.ValidationErrors.Add(new ValidationResult("Temporary Error", new string[] { "StateName" })); // remove city City[] cities = citiesProvider.Cities.ToArray(); deletedCity = cities[1]; citiesProvider.Cities.Remove(deletedCity); so = citiesProvider.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); }); // wait for submitted event being fired and verify Entity.ValidationErrors is not empty EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { DomainOperationException ex = so.Error as DomainOperationException; Assert.IsNotNull(ex); Assert.AreEqual(OperationErrorStatus.ValidationFailed, ex.Status); Assert.AreEqual(Resource.DomainContext_SubmitOperationFailed_Validation, ex.Message); // verify errors are generated on the client side Zip[] zips = citiesProvider.Zips.ToArray(); IEnumerable<ValidationResult> errors = zips[0].ValidationErrors; LogErrorListContents("citiesProvider.Zips[0].ValidationErrors", errors); Assert.AreEqual(2, errors.Count()); UnitTestHelper.AssertListContains<ValidationResult>(errors, (e => e.ErrorMessage == "The field offset must be between -9999 and 9999.")); UnitTestHelper.AssertListContains<ValidationResult>(errors, (e => e.ErrorMessage == "Zip codes cannot have matching city and state names" && e.MemberNames.Contains("StateName") && e.MemberNames.Contains("CityName"))); LogErrorListContents("newZip.ValidationErrors", newZip.ValidationErrors); errors = newZip.ValidationErrors; // Expect only 2 errors for the properties. The entity level error is not checked if property level checks fail Assert.AreEqual(2, errors.Count()); UnitTestHelper.AssertListContains<ValidationResult>(errors, (e => e.ErrorMessage == "The CityName field is required.")); UnitTestHelper.AssertListContains<ValidationResult>(errors, (e => e.ErrorMessage == "The StateName field is required.")); Assert.AreEqual(0, deletedCity.ValidationErrors.Count(), "The deleted city shouldn't have any validation errors"); Assert.AreEqual(0, validZip.ValidationErrors.Count(), "The valid city shouldn't have any validation errors"); }); EnqueueTestComplete(); }
public void CustomMethodFlag_ChangeNotifications() { List<string> propChanged = new List<string>(); CityDomainContext ctxt = new CityDomainContext(TestURIs.Cities); City city = null; LoadOperation lo = ctxt.Load(ctxt.GetCitiesQuery(), false); SubmitOperation so = null; EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { city = ctxt.Cities.First(); city.PropertyChanged += (s, e) => { propChanged.Add(e.PropertyName); }; Assert.IsTrue(city.CanAssignCityZone); Assert.IsFalse(city.IsAssignCityZoneInvoked); city.AssignCityZone("Twilight"); Assert.IsFalse(city.CanAssignCityZone); Assert.IsTrue(city.IsAssignCityZoneInvoked); Assert.IsTrue(propChanged.Contains("CanAssignCityZone")); Assert.IsTrue(propChanged.Contains("IsAssignCityZoneInvoked")); propChanged.Clear(); so = ctxt.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); }); EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { Assert.IsFalse(so.HasError); Assert.IsTrue(city.CanAssignCityZone); Assert.IsFalse(city.IsAssignCityZoneInvoked); Assert.IsTrue(propChanged.Contains("CanAssignCityZone")); Assert.IsTrue(propChanged.Contains("IsAssignCityZoneInvoked")); }); EnqueueTestComplete(); }
public void ErrorPipeline_UnauthorizedEx() { CityDomainContext citiesProvider = new CityDomainContext(TestURIs.Cities); SubmitOperation so = null; LoadOperation lo = citiesProvider.Load(citiesProvider.GetZipsQuery(), false); // wait for Load to complete, then invoke domain method that throws on server. Submit. EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { Zip[] zips = citiesProvider.Zips.ToArray(); citiesProvider.Zips.Remove(zips[1]); so = citiesProvider.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); }); // wait for submitted event being fired and verify submittedEventArgs.Error is not null EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { DomainOperationException error = so.Error as DomainOperationException; Assert.IsNotNull(error); Assert.AreEqual(string.Format(Resource.DomainContext_SubmitOperationFailed, "Access to operation 'DeleteZip' was denied."), error.Message); }); EnqueueTestComplete(); }
public void DomainContext_Submit_DomainMethodAndCRUD() { List<string> propChanged_addedCity = new List<string>(); City newCity = new City { Name = "Sammamish", CountyName = "King", StateName = "WA" }; int refZipCode = 0; int refCityCount = 0; CityDomainContext citiesProvider = new CityDomainContext(TestURIs.Cities); LoadOperation lo = citiesProvider.Load(citiesProvider.GetCitiesQuery(), false); SubmitOperation so = null; // wait for LoadCities to complete, then LoadZips EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { refCityCount = citiesProvider.Cities.Count; lo = citiesProvider.Load(citiesProvider.GetZipsQuery(), false); }); // wait for Load to complete, then invoke some domain methods EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { // this test the following combinations of CRUD and Domain method in changeset: // - Invoke -> update // - Add -> invoke // - Remove // - Invoke only City[] cities = citiesProvider.Cities.ToArray(); cities[0].ZoneName = "Zone44"; cities[0].AssignCityZone("Zone1"); cities[1].AssignCityZone("Zone2"); citiesProvider.Cities.Add(newCity); newCity.AssignCityZone("Zone3"); citiesProvider.Cities.Remove(cities[4]); citiesProvider.Cities.Remove(cities[5]); // keep a reference zip code before invoking the method: this will increment Code by offset=1 on the server Zip zip = citiesProvider.Zips.First(); refZipCode = zip.Code; zip.ReassignZipCode(1, true); newCity.PropertyChanged += delegate(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName != "IsReadOnly" && e.PropertyName != "HasChanges" && e.PropertyName != "EntityState" && e.PropertyName != "ValidationErrors") { propChanged_addedCity.Add(e.PropertyName); } }; Assert.IsTrue(newCity.CanAssignCityZoneIfAuthorized); Assert.IsTrue(newCity.CanAutoAssignCityZone); so = citiesProvider.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); Assert.IsFalse(newCity.CanAssignCityZoneIfAuthorized); Assert.IsFalse(newCity.CanAutoAssignCityZone); Assert.AreEqual(3, so.ChangeSet.ModifiedEntities.Count); Assert.AreEqual(1, so.ChangeSet.AddedEntities.Count); Assert.AreEqual(2, so.ChangeSet.RemovedEntities.Count); }); EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { Assert.IsNull(so.Error, string.Format("SubmitOperation.Error should be null.\r\nMessage: {0}\r\nStack Trace:\r\n{1}", so.Error != null ? so.Error.Message : string.Empty, so.Error != null ? so.Error.StackTrace : string.Empty)); Assert.IsTrue(newCity.CanAssignCityZoneIfAuthorized); Assert.IsTrue(newCity.CanAutoAssignCityZone); Assert.IsTrue(newCity.CanAssignCityZone); // verify we got property change notifications for the new city entity (guard property should be reverted once SubmitChanges is called) Assert.AreEqual(9, propChanged_addedCity.Count); Assert.AreEqual(1, propChanged_addedCity.Count(prop => prop == "ZoneName")); Assert.AreEqual(1, propChanged_addedCity.Count(prop => prop == "ZoneID")); Assert.AreEqual(1, propChanged_addedCity.Count(prop => prop == "CanAssignCityZone")); Assert.AreEqual(1, propChanged_addedCity.Count(prop => prop == "IsAssignCityZoneInvoked")); // The other custom method invocations should have changed from true -> false during submit // and from false -> true after submit Assert.AreEqual(2, propChanged_addedCity.Count(prop => prop == "CanAssignCityZoneIfAuthorized")); Assert.AreEqual(2, propChanged_addedCity.Count(prop => prop == "CanAutoAssignCityZone")); // verify entities are auto-synced back to the client as a result of the domain method execution on server Assert.AreEqual(1, citiesProvider.Cities.Single<City>(c => (c.ZoneName == "Zone1" && c.CountyName == "King")).ZoneID); Assert.AreEqual(2, citiesProvider.Cities.Single<City>(c => (c.ZoneName == "Zone2")).ZoneID); Assert.AreEqual(3, citiesProvider.Cities.Single<City>(c => (c.ZoneName == "Zone3" && c.Name == newCity.Name)).ZoneID); Assert.IsTrue(citiesProvider.Zips.Any<Zip>(z => z.Code == refZipCode - 1)); // verify unchanged entities Assert.IsFalse(citiesProvider.Cities.Any(c => (c.ZoneName == null && c.ZoneID != 0))); // verify that after a successful submit, DM invocations on the entities have been accepted Assert.IsFalse(so.ChangeSet.ModifiedEntities.Any(p => p.EntityActions.Any())); EntityChangeSet changeSet = citiesProvider.EntityContainer.GetChanges(); Assert.IsTrue(changeSet.IsEmpty); }); EnqueueTestComplete(); }
public void Inherit_Run_CUD_Insert_Derived() { // Inheritance is City <-- CityWithEditHistory <-- CityWithInfo CityDomainContext citiesContext= new CityDomainContext(TestURIs.Cities); DateTime priorLastUpdated = DateTime.Now; // Load all cities, not just derived ones LoadOperation lo = citiesContext.Load(citiesContext.GetCitiesQuery()); SubmitOperation so = null; // wait for Load to complete EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { CityWithInfo newCity = new CityWithInfo() { Name = "CocoaVille", StateName = "WA", CountyName = "King", Info="stuff" }; citiesContext.Cities.Add(newCity); so = citiesContext.SubmitChanges(); }); // wait for submit to complete EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { if (so.Error != null) { Assert.Fail("Unexpected error on submit: " + so.Error.Message); } // verify entities are auto-synced back to the client as a result of the domain method execution on server CityWithInfo newCity = citiesContext.Cities.OfType<CityWithInfo>().SingleOrDefault<CityWithInfo>(c => (c.Name == "CocoaVille")); Assert.IsNotNull(newCity, "Did not find modified City after the submit"); Assert.IsTrue(newCity.EditHistory.Contains("insert"), "EditHistory was" + newCity.EditHistory); }); EnqueueTestComplete(); }
public void Cities_TestLoad() { CityDomainContext dp = new CityDomainContext(TestURIs.Cities); // Abs URI so runs on desktop too LoadOperation lo = dp.Load(dp.GetCitiesQuery(), false); EnqueueConditional(() => lo.IsComplete); EnqueueCallback(() => { if (lo.Error != null) Assert.Fail("LoadOperation.Error: " + lo.Error.Message); IEnumerable<City> expected = new CityData().Cities; AssertSame(expected, dp.Cities); }); EnqueueTestComplete(); }
public void DomainContext_Submit_DomainMethodOnly() { EntityChangeSet changeset; List<string> propChanged = new List<string>(); CityDomainContext citiesProvider = new CityDomainContext(TestURIs.Cities); LoadOperation lo = citiesProvider.Load(citiesProvider.GetCitiesQuery(), false); SubmitOperation so = null; City firstRootCity = null; City lastRootCity = null; // wait for Load to complete, then invoke some domain methods EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { changeset = citiesProvider.EntityContainer.GetChanges(); Assert.IsTrue(changeset.IsEmpty); // Find a root city. This test specifically does not want to accidently use a derived type firstRootCity = citiesProvider.Cities.Where(c => c.GetType() == typeof(City)).FirstOrDefault(); Assert.IsNotNull(firstRootCity, "Expected to find a root City type in entity list"); lastRootCity = citiesProvider.Cities.Where(c => c.GetType() == typeof(City)).LastOrDefault(); Assert.IsNotNull(lastRootCity, "Expected to find a root City type in entity list"); Assert.AreNotEqual(firstRootCity, lastRootCity, "Expected first and last city to be different"); firstRootCity.PropertyChanged += delegate(object sender, System.ComponentModel.PropertyChangedEventArgs e) { bool isEntityBaseProperty = typeof(City).GetProperty(e.PropertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) == null; if (!isEntityBaseProperty) { propChanged.Add(e.PropertyName); } }; Assert.IsTrue(firstRootCity.CanAssignCityZone); firstRootCity.AssignCityZone("Zone15"); }); // wait for prop changed for domain method guards EnqueueConditional(() => propChanged.Count > 0); EnqueueCallback(delegate { Assert.IsTrue(propChanged.Contains("CanAssignCityZone")); Assert.IsTrue(propChanged.Contains("IsAssignCityZoneInvoked")); Assert.IsFalse(propChanged.Contains("CanAutoAssignCityZone")); propChanged.Clear(); Assert.IsTrue(lastRootCity.CanAutoAssignCityZone); lastRootCity.AutoAssignCityZone(); changeset = citiesProvider.EntityContainer.GetChanges(); Assert.AreEqual(2, changeset.ModifiedEntities.Count); so = citiesProvider.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); Assert.AreEqual(2, so.ChangeSet.ModifiedEntities.Count); Assert.AreEqual(0, so.ChangeSet.AddedEntities.Count); Assert.AreEqual(0, so.ChangeSet.RemovedEntities.Count); }); // wait for submit to complete, then verify invoked entities in changeset EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { Assert.IsNull(so.Error); Assert.AreEqual(2, so.ChangeSet.ModifiedEntities.Count); // verify we got the property change notification for the city entity as a result of autosync Assert.AreEqual(8, propChanged.Count); Assert.AreEqual(1, propChanged.Count(prop => prop == "ZoneName")); Assert.AreEqual(1, propChanged.Count(prop => prop == "ZoneID")); Assert.AreEqual(1, propChanged.Count(prop => prop == "CanAssignCityZone")); Assert.AreEqual(1, propChanged.Count(prop => prop == "IsAssignCityZoneInvoked")); Assert.AreEqual(2, propChanged.Count(prop => prop == "CanAutoAssignCityZone")); Assert.AreEqual(2, propChanged.Count(prop => prop == "CanAssignCityZoneIfAuthorized")); // verify entities are auto-synced back to the client as a result of the domain method execution on server Assert.AreEqual(15, citiesProvider.Cities.Single<City>(c => (c.ZoneName == "Zone15")).ZoneID); Assert.AreEqual(1, citiesProvider.Cities.Single<City>(c => (c.ZoneName == "Auto_Zone1")).ZoneID); // verify unchanged entities Assert.AreEqual(0, citiesProvider.Cities.First(c => (c.ZoneName == null)).ZoneID); }); EnqueueTestComplete(); }
public void Inherit_Run_CUD_Update_Derived() { // Inheritance is City <-- CityWithEditHistory <-- CityWithInfo CityDomainContext citiesContext = new CityDomainContext(TestURIs.Cities); DateTime priorLastUpdated = DateTime.Now; // Load all cities, not just derived ones LoadOperation lo = citiesContext.Load(citiesContext.GetCitiesQuery()); SubmitOperation so = null; CityWithInfo cityWithInfo = null; string originalName = null; string originalStateName = null; string originalCountyName = null; // wait for Load to complete EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { cityWithInfo = citiesContext.Cities.OfType<CityWithInfo>().FirstOrDefault(); Assert.IsNotNull(cityWithInfo, "expected to find at least one CityWithInfo entity"); Assert.IsFalse(cityWithInfo.EditHistory.Contains("update"), "Did not expect edit history to be set yet."); originalName = cityWithInfo.Name; originalStateName = cityWithInfo.StateName; originalCountyName = cityWithInfo.CountyName; cityWithInfo.Info = "inserted new info"; so = citiesContext.SubmitChanges(); }); // wait for submit to complete EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { if (so.Error != null) { Assert.Fail("Unexpected error on submit: " + so.Error.Message); } // verify entities are auto-synced back to the client as a result of the domain method execution on server CityWithInfo updatedCity = citiesContext.Cities.OfType<CityWithInfo>().SingleOrDefault<CityWithInfo> (c => (c.Name == originalName && c.StateName == originalStateName && c.CountyName == originalCountyName)); Assert.IsNotNull(updatedCity, "Did not find modified City after the submit"); Assert.IsTrue(updatedCity.EditHistory.Contains("update"), "EditHistory was" + updatedCity.EditHistory); Assert.AreEqual("inserted new info", updatedCity.Info, "Updated Info did not get applied"); }); EnqueueTestComplete(); }
public void CustomMethod_ValidationExceptionRecovery() { bool completed = false; Zip zip = null; SubmitOperation submitOp = null; LoadOperation<Zip> loadOp = null; EventHandler completedDelegate = (sender, args) => completed = true; CityDomainContext context = new CityDomainContext(TestURIs.Cities); loadOp = context.Load(context.GetZipsQuery(), false); loadOp.Completed += completedDelegate; this.EnqueueConditional(() => completed); this.EnqueueCallback(() => { Assert.IsFalse(loadOp.HasError, "Failed to load Zips"); // Grab a Zip and invoke a custom operation that will throw a ValidationException. zip = context.Zips.First(); zip.ThrowException(typeof(ValidationException).Name); // Submit completed = false; submitOp = context.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); submitOp.Completed += completedDelegate; // Verify entity state Assert.IsTrue(zip.IsReadOnly, "Expected Zip to be in a read-only state."); Assert.IsTrue(zip.IsSubmitting, "Expected Zip to be in a submitting state."); Assert.AreEqual(1, zip.EntityActions.Count(), "Expected Zip EntityActions property to contain a single invocation"); }); this.EnqueueConditional(() => completed); this.EnqueueCallback(() => { // Verify results Assert.IsTrue(submitOp.HasError, "Expected errors."); Assert.AreEqual(1, submitOp.EntitiesInError.Count(), "Expected 1 Zip entity in error."); Assert.AreEqual(submitOp.EntitiesInError.Single(), zip, "Expected 1 Zip entity in error."); Assert.AreEqual(1, zip.ValidationErrors.Count, "Expected 1 validation error on Zip entity."); // Verify entity state Assert.IsFalse(zip.IsReadOnly, "Zip should not be in a read-only state."); Assert.IsFalse(zip.IsSubmitting, "Zip should not be in a submitting state."); Assert.AreEqual(1, zip.EntityActions.Count(), "Expected Zip EntityActions property to contain a single invocation"); // Explicitly set a property zip.StateName += "x"; }); this.EnqueueTestComplete(); }
public void Inherit_Run_CUD_Delete_Derived() { // Inheritance is City <-- CityWithEditHistory <-- CityWithInfo CityDomainContext citiesContext = new CityDomainContext(TestURIs.Cities); DateTime priorLastUpdated = DateTime.Now; LoadOperation lo = null; SubmitOperation so = null; CityWithInfo cityWithInfo = null; string originalName = null; string originalStateName = null; string originalCountyName = null; // Invoke service operation to clear out all static data // (we rely on static data for deleted cities so that it // survives across queries) InvokeOperation invoke = citiesContext.ResetData(null, null); EnqueueConditional(delegate { return invoke.IsComplete; }); EnqueueCallback(delegate { if (invoke.Error != null) { Assert.Fail("Failed on invoke of ResetData: " + invoke.Error.Message); } }); EnqueueCallback(delegate { // Load all cities, not just derived ones lo = citiesContext.Load(citiesContext.GetCitiesQuery()); }); // wait for Load to complete EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { cityWithInfo = citiesContext.Cities.OfType<CityWithInfo>().FirstOrDefault(); Assert.IsNotNull(cityWithInfo, "expected to find at least one CityWithInfo entity"); Assert.IsFalse(cityWithInfo.EditHistory.Contains("update"), "Did not expect edit history to be set yet."); originalName = cityWithInfo.Name; originalStateName = cityWithInfo.StateName; originalCountyName = cityWithInfo.CountyName; // Delete it. Note that the delete CUD method in the CityDomainService // moves the deleted city over into DeletedCities so it can still be found citiesContext.Cities.Remove(cityWithInfo); so = citiesContext.SubmitChanges(); }); // wait for submit to complete EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { if (so.Error != null) { Assert.Fail("Unexpected error on submit: " + so.Error.Message); } // verify entities are auto-synced back to the client as a result of the domain method execution on server CityWithInfo deletedCity = citiesContext.Cities.OfType<CityWithInfo>().SingleOrDefault<CityWithInfo> (c => (c.Name == originalName && c.StateName == originalStateName && c.CountyName == originalCountyName)); Assert.IsNull(deletedCity, "Did not expect to find deleted City after the submit"); // Load the deleted cities (it was tombstoned) citiesContext.Cities.Clear(); lo = citiesContext.Load(citiesContext.GetDeletedCitiesQuery()); }); // Wait for deleted city query to complete EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { if (lo.Error != null) { Assert.Fail("Unexpected error on load of deleted queries: " + lo.Error.Message); } // verify entities are auto-synced back to the client as a result of the domain method execution on server CityWithInfo deletedCity = citiesContext.Cities.OfType<CityWithInfo>().SingleOrDefault<CityWithInfo> (c => (c.Name == originalName && c.StateName == originalStateName && c.CountyName == originalCountyName)); Assert.IsNotNull(deletedCity, "Expected to find deleted City in the tombstone list"); Assert.IsTrue(deletedCity.EditHistory.Contains("delete"), "Expected edit history to show delete but it only shows: " + deletedCity.EditHistory); }); EnqueueTestComplete(); }