public async Task Can_update_user_password() { // Arrange var user = _fakers.User.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Users.Add(user); await dbContext.SaveChangesAsync(); }); user.Password = _fakers.User.Generate().Password; var serializer = GetRequestSerializer <User>(p => new { p.Password }); string requestBody = serializer.Serialize(user); var route = $"/api/v1/users/{user.Id}"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.SingleData.Attributes.Should().NotContainKey("password"); responseDocument.SingleData.Attributes["userName"].Should().Be(user.UserName); await _testContext.RunOnDatabaseAsync(async dbContext => { var userInDatabase = await dbContext.Users.FirstAsync(u => u.Id == user.Id); userInDatabase.Password.Should().Be(user.Password); }); }
public async Task Can_clear_HasMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); existingWorkItem.Subscribers = _fakers.UserAccount.Generate(2).ToHashSet(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.WorkItems.Add(existingWorkItem); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new object[0] }; string route = $"/workItems/{existingWorkItem.StringId}/relationships/subscribers"; // Act (HttpResponseMessage httpResponse, string responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { WorkItem workItemInDatabase = await dbContext.WorkItems.Include(workItem => workItem.Subscribers).FirstWithIdAsync(existingWorkItem.Id); workItemInDatabase.Subscribers.Should().BeEmpty(); }); }
public async Task Can_create_OneToOne_relationship() { // Arrange var existingCar = new Car { RegionId = 123, LicensePlate = "AA-BB-11" }; var existingEngine = new Engine { SerialCode = "1234567890" }; await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <Car>(); dbContext.AddRange(existingCar, existingEngine); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "engines", id = existingEngine.StringId, relationships = new { car = new { data = new { type = "cars", id = existingCar.StringId } } } } }; string route = "/engines/" + existingEngine.StringId; // Act (HttpResponseMessage httpResponse, string responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { Engine engineInDatabase = await dbContext.Engines.Include(engine => engine.Car).FirstWithIdAsync(existingEngine.Id); engineInDatabase.Car.Should().NotBeNull(); engineInDatabase.Car.Id.Should().Be(existingCar.StringId); }); }
public async Task Can_update_resource_through_primary_endpoint() { // Arrange var existingMan = new Man { FamilyName = "Smith", IsRetired = false, HasBeard = true }; var newMan = new Man { FamilyName = "Jackson", IsRetired = true, HasBeard = false }; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Men.Add(existingMan); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "men", id = existingMan.StringId, attributes = new { familyName = newMan.FamilyName, isRetired = newMan.IsRetired, hasBeard = newMan.HasBeard } } }; var route = "/men/" + existingMan.StringId; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { var manInDatabase = await dbContext.Men .FirstAsync(man => man.Id == existingMan.Id); manInDatabase.FamilyName.Should().Be(newMan.FamilyName); manInDatabase.IsRetired.Should().Be(newMan.IsRetired); manInDatabase.HasBeard.Should().Be(newMan.HasBeard); }); }
public async Task Decrypts_on_update_resource() { // Arrange var encryptionService = _testContext.Factory.Services.GetRequiredService <IEncryptionService>(); var hitCounter = _testContext.Factory.Services.GetRequiredService <SerializationHitCounter>(); Student existingStudent = _fakers.Student.Generate(); string newSocialSecurityNumber = _fakers.Student.Generate().SocialSecurityNumber; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Students.Add(existingStudent); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "students", id = existingStudent.StringId, attributes = new { socialSecurityNumber = encryptionService.Encrypt(newSocialSecurityNumber) } } }; string route = "/students/" + existingStudent.StringId; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePatchAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.SingleData.Should().NotBeNull(); string socialSecurityNumber = encryptionService.Decrypt((string)responseDocument.SingleData.Attributes["socialSecurityNumber"]); socialSecurityNumber.Should().Be(newSocialSecurityNumber); await _testContext.RunOnDatabaseAsync(async dbContext => { Student studentInDatabase = await dbContext.Students.FirstWithIdAsync(existingStudent.Id); studentInDatabase.SocialSecurityNumber.Should().Be(newSocialSecurityNumber); }); hitCounter.DeserializeCount.Should().Be(1); hitCounter.SerializeCount.Should().Be(1); }
public async Task Can_update_resource() { // Arrange Table existingTable = _fakers.Table.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Tables.Add(existingTable); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "tables", id = existingTable.StringId, attributes = new { } } }; string route = "/tables/" + existingTable.StringId; // Act (HttpResponseMessage httpResponse, _) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); }
public async Task Can_update_resource() { // Arrange var existingSofa = _fakers.Sofa.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Sofas.Add(existingSofa); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "sofas", id = existingSofa.StringId, attributes = new { } } }; var route = "/sofas/" + existingSofa.StringId; // Act var(httpResponse, _) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); }
public async Task Can_update_resource() { // Arrange var existingBuilding = _fakers.Building.Generate(); existingBuilding.PrimaryDoor = _fakers.Door.Generate(); existingBuilding.SecondaryDoor = _fakers.Door.Generate(); existingBuilding.Windows = _fakers.Window.Generate(2); var newBuildingNumber = _fakers.Building.Generate().Number; var newPrimaryDoorColor = _fakers.Door.Generate().Color; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Buildings.Add(existingBuilding); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "buildings", id = existingBuilding.StringId, attributes = new { number = newBuildingNumber, primaryDoorColor = newPrimaryDoorColor } } }; var route = "/buildings/" + existingBuilding.StringId; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { var buildingInDatabase = await dbContext.Buildings .Include(building => building.PrimaryDoor) .Include(building => building.SecondaryDoor) .Include(building => building.Windows) .FirstOrDefaultAsync(building => building.Id == existingBuilding.Id); buildingInDatabase.Should().NotBeNull(); buildingInDatabase.Number.Should().Be(newBuildingNumber); buildingInDatabase.PrimaryDoor.Should().NotBeNull(); buildingInDatabase.PrimaryDoor.Color.Should().Be(newPrimaryDoorColor); buildingInDatabase.SecondaryDoor.Should().NotBeNull(); buildingInDatabase.Windows.Should().HaveCount(2); }); }
public async Task Can_archive_resource() { // Arrange TelevisionBroadcast existingBroadcast = _fakers.TelevisionBroadcast.Generate(); existingBroadcast.ArchivedAt = null; DateTimeOffset newArchivedAt = _fakers.TelevisionBroadcast.Generate().ArchivedAt !.Value; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Broadcasts.Add(existingBroadcast); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "televisionBroadcasts", id = existingBroadcast.StringId, attributes = new { archivedAt = newArchivedAt } } }; string route = "/televisionBroadcasts/" + existingBroadcast.StringId; // Act (HttpResponseMessage httpResponse, string responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { TelevisionBroadcast broadcastInDatabase = await dbContext.Broadcasts.FirstWithIdAsync(existingBroadcast.Id); broadcastInDatabase.ArchivedAt.Should().BeCloseTo(newArchivedAt); }); }
public async Task Update_resource_with_side_effects_and_include_returns_relative_links() { // Arrange var existingPhoto = _fakers.Photo.Generate(); var existingAlbum = _fakers.PhotoAlbum.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.AddRange(existingPhoto, existingAlbum); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "photos", id = existingPhoto.StringId, relationships = new { album = new { data = new { type = "photoAlbums", id = existingAlbum.StringId } } } } }; var route = $"/api/photos/{existingPhoto.StringId}?include=album"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.Links.Self.Should().Be($"/api/photos/{existingPhoto.StringId}?include=album"); responseDocument.Links.Related.Should().BeNull(); responseDocument.Links.First.Should().BeNull(); responseDocument.Links.Last.Should().BeNull(); responseDocument.Links.Prev.Should().BeNull(); responseDocument.Links.Next.Should().BeNull(); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Links.Self.Should().Be($"/api/photos/{existingPhoto.StringId}"); responseDocument.SingleData.Relationships["album"].Links.Self.Should().Be($"/api/photos/{existingPhoto.StringId}/relationships/album"); responseDocument.SingleData.Relationships["album"].Links.Related.Should().Be($"/api/photos/{existingPhoto.StringId}/album"); responseDocument.Included.Should().HaveCount(1); responseDocument.Included[0].Links.Self.Should().Be($"/api/photoAlbums/{existingAlbum.StringId}"); responseDocument.Included[0].Relationships["photos"].Links.Self.Should().Be($"/api/photoAlbums/{existingAlbum.StringId}/relationships/photos"); responseDocument.Included[0].Relationships["photos"].Links.Related.Should().Be($"/api/photoAlbums/{existingAlbum.StringId}/photos"); }
public async Task Cannot_update_deleted_resource() { // Arrange var company = new Company { IsSoftDeleted = true }; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Companies.Add(company); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "companies", id = company.StringId, attributes = new { name = "Umbrella Corporation" } } }; var route = "/companies/" + company.StringId; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <ErrorDocument>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NotFound); responseDocument.Errors.Should().HaveCount(1); var error = responseDocument.Errors[0]; error.StatusCode.Should().Be(HttpStatusCode.NotFound); error.Title.Should().Be("The requested resource does not exist."); error.Detail.Should().Be($"Resource of type 'companies' with ID '{company.StringId}' does not exist."); error.Source.Parameter.Should().BeNull(); }
public async Task Can_update_resource_with_side_effects() { // Arrange var existingAttendee = _fakers.MeetingAttendee.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Attendees.Add(existingAttendee); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "meetingAttendees", id = existingAttendee.StringId, attributes = new { displayName = existingAttendee.DisplayName } } }; var route = "/meetingAttendees/" + existingAttendee.StringId; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.Should().BeJson(@"{ ""links"": { ""self"": ""http://localhost/meetingAttendees/" + existingAttendee.StringId + @""" }, ""data"": { ""type"": ""meetingAttendees"", ""id"": """ + existingAttendee.StringId + @""", ""attributes"": { ""displayName"": """ + existingAttendee.DisplayName + @""" }, ""relationships"": { ""meeting"": { ""links"": { ""self"": ""http://localhost/meetingAttendees/" + existingAttendee.StringId + @"/relationships/meeting"", ""related"": ""http://localhost/meetingAttendees/" + existingAttendee.StringId + @"/meeting"" } } }, ""links"": { ""self"": ""http://localhost/meetingAttendees/" + existingAttendee.StringId + @""" } } }"); }
public async Task Can_clear_ManyToOne_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); existingWorkItem.Assignee = _fakers.UserAccount.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.WorkItems.Add(existingWorkItem); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "workItems", id = existingWorkItem.StringId, relationships = new { assignee = new { data = (object)null } } } }; string route = "/workItems/" + existingWorkItem.StringId; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePatchAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.SingleData.Should().NotBeNull(); await _testContext.RunOnDatabaseAsync(async dbContext => { WorkItem workItemInDatabase = await dbContext.WorkItems.Include(workItem => workItem.Assignee).FirstWithIdAsync(existingWorkItem.Id); workItemInDatabase.Assignee.Should().BeNull(); }); }
public async Task Can_update_resource_with_omitted_required_attribute_value() { // Arrange var directory = new SystemDirectory { Name = "Projects", IsCaseSensitive = true }; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Directories.Add(directory); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "systemDirectories", id = directory.StringId, attributes = new { sizeInBytes = 100 } } }; string route = "/systemDirectories/" + directory.StringId; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); }
public async Task Fails_on_ETag_in_PATCH_request() { // Arrange Meeting existingMeeting = _fakers.Meeting.Generate(); string newTitle = _fakers.Meeting.Generate().Title; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Meetings.Add(existingMeeting); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "meetings", id = existingMeeting.StringId, attributes = new { title = newTitle } } }; string route = "/meetings/" + existingMeeting.StringId; Action <HttpRequestHeaders> setRequestHeaders = headers => { headers.IfMatch.ParseAdd("\"12345\""); }; // Act (HttpResponseMessage httpResponse, ErrorDocument responseDocument) = await _testContext.ExecutePatchAsync <ErrorDocument>(route, requestBody, setRequestHeaders : setRequestHeaders); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.PreconditionFailed); responseDocument.Errors.Should().HaveCount(1); Error error = responseDocument.Errors[0]; error.StatusCode.Should().Be(HttpStatusCode.PreconditionFailed); error.Title.Should().Be("Detection of mid-air edit collisions using ETags is not supported."); error.Detail.Should().BeNull(); }
public async Task Can_update_resource_with_zero_ID() { // Arrange var existingGame = _fakers.Game.Generate(); existingGame.Id = 0; var newTitle = _fakers.Game.Generate().Title; await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <Game>(); dbContext.Games.Add(existingGame); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "games", id = "0", attributes = new { title = newTitle } } }; var route = "/games/0"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Id.Should().Be("0"); responseDocument.SingleData.Attributes["title"].Should().Be(newTitle); await _testContext.RunOnDatabaseAsync(async dbContext => { var gameInDatabase = await dbContext.Games .FirstAsync(game => game.Id == 0); gameInDatabase.Should().NotBeNull(); gameInDatabase.Title.Should().Be(newTitle); }); }
public async Task Can_update_resource() { // Arrange WebProduct existingProduct = _fakers.WebProduct.Generate(); existingProduct.Shop = _fakers.WebShop.Generate(); existingProduct.Shop.TenantId = ThisTenantId; string newProductName = _fakers.WebProduct.Generate().Name; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.WebProducts.Add(existingProduct); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "webProducts", id = existingProduct.StringId, attributes = new { name = newProductName } } }; string route = "/nld/products/" + existingProduct.StringId; // Act (HttpResponseMessage httpResponse, string responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { WebProduct productInDatabase = await dbContext.WebProducts.IgnoreQueryFilters().FirstWithIdAsync(existingProduct.Id); productInDatabase.Name.Should().Be(newProductName); productInDatabase.Price.Should().Be(existingProduct.Price); }); }
public async Task Can_update_resource_with_empty_ID() { // Arrange var existingMap = _fakers.Map.Generate(); existingMap.Id = Guid.Empty; var newName = _fakers.Map.Generate().Name; await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <Map>(); dbContext.Maps.Add(existingMap); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "maps", id = Guid.Empty, attributes = new { name = newName } } }; var route = "/maps/00000000-0000-0000-0000-000000000000"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { var mapInDatabase = await dbContext.Maps .FirstAsync(game => game.Id == Guid.Empty); mapInDatabase.Should().NotBeNull(); mapInDatabase.Name.Should().Be(newName); }); }
public async Task Cannot_transition_to_invalid_stage() { // Arrange var existingWorkflow = new Workflow { Stage = WorkflowStage.OnHold }; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Workflows.Add(existingWorkflow); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "workflows", id = existingWorkflow.StringId, attributes = new { stage = WorkflowStage.Succeeded } } }; string route = "/workflows/" + existingWorkflow.StringId; // Act (HttpResponseMessage httpResponse, ErrorDocument responseDocument) = await _testContext.ExecutePatchAsync <ErrorDocument>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.UnprocessableEntity); responseDocument.Errors.Should().HaveCount(1); Error error = responseDocument.Errors[0]; error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity); error.Title.Should().Be("Invalid workflow stage."); error.Detail.Should().Be("Cannot transition from 'OnHold' to 'Succeeded'."); error.Source.Pointer.Should().Be("/data/attributes/stage"); }
public async Task Applies_casing_convention_on_source_pointer_from_ModelState() { // Arrange var existingBoard = _fakers.DivingBoard.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.DivingBoards.Add(existingBoard); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "diving-boards", id = existingBoard.StringId, attributes = new Dictionary <string, object> { ["height-in-meters"] = -1 } } }; var route = "/public-api/diving-boards/" + existingBoard.StringId; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <ErrorDocument>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.UnprocessableEntity); responseDocument.Errors.Should().HaveCount(1); var error = responseDocument.Errors[0]; error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity); error.Title.Should().Be("Input validation failed."); error.Detail.Should().Be("The field HeightInMeters must be between 1 and 20."); error.Source.Pointer.Should().Be("/data/attributes/height-in-meters"); }
public async Task Cannot_clear_required_ManyToOne_relationship_through_primary_endpoint() { // Arrange var existingOrder = _fakers.Orders.Generate(); existingOrder.Shipment = _fakers.Shipments.Generate(); existingOrder.Customer = _fakers.Customers.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Orders.Add(existingOrder); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { id = existingOrder.Id, type = "orders", relationships = new { customer = new { data = (object)null } } } }; var route = $"/orders/{existingOrder.Id}"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <ErrorDocument>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.BadRequest); responseDocument.Errors.Should().HaveCount(1); var error = responseDocument.Errors[0]; error.StatusCode.Should().Be(HttpStatusCode.BadRequest); error.Title.Should().Be("Failed to clear a required relationship."); error.Detail.Should().Be($"The relationship 'customer' of resource type 'orders' with ID '{existingOrder.StringId}' " + "cannot be cleared because it is a required relationship."); }
public async Task Cannot_update_resource() { // Arrange var existingBed = _fakers.Bed.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Beds.Add(existingBed); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "beds", id = existingBed.StringId, attributes = new { } } }; var route = "/beds/" + existingBed.StringId; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <ErrorDocument>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.MethodNotAllowed); responseDocument.Errors.Should().HaveCount(1); var error = responseDocument.Errors[0]; error.StatusCode.Should().Be(HttpStatusCode.MethodNotAllowed); error.Title.Should().Be("The request method is not allowed."); error.Detail.Should().Be("Resource does not support PATCH requests."); }
public async Task Hides_resource_count_in_update_resource_response() { // Arrange var existingTicket = _fakers.SupportTicket.Generate(); var newDescription = _fakers.SupportTicket.Generate().Description; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.SupportTickets.Add(existingTicket); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "supportTickets", id = existingTicket.StringId, attributes = new { description = newDescription } } }; var route = "/supportTickets/" + existingTicket.StringId; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.Meta.Should().BeNull(); }
public async Task Cannot_update_soft_deleted_resource() { // Arrange Company existingCompany = _fakers.Company.Generate(); existingCompany.SoftDeletedAt = SoftDeletionTime; string newCompanyName = _fakers.Company.Generate().Name; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Companies.Add(existingCompany); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "companies", id = existingCompany.StringId, attributes = new { name = newCompanyName } } }; string route = "/companies/" + existingCompany.StringId; // Act (HttpResponseMessage httpResponse, ErrorDocument responseDocument) = await _testContext.ExecutePatchAsync <ErrorDocument>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NotFound); responseDocument.Errors.Should().HaveCount(1); Error error = responseDocument.Errors[0]; error.StatusCode.Should().Be(HttpStatusCode.NotFound); error.Title.Should().Be("The requested resource does not exist."); error.Detail.Should().Be($"Resource of type 'companies' with ID '{existingCompany.StringId}' does not exist."); }
public async Task Can_clear_ManyToOne_relationship() { // Arrange var existingWorkItem = _fakers.WorkItem.Generate(); existingWorkItem.Assignee = _fakers.UserAccount.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.WorkItems.Add(existingWorkItem); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = (object)null }; var route = $"/workItems/{existingWorkItem.StringId}/relationships/assignee"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { var workItemInDatabase = await dbContext.WorkItems .Include(workItem => workItem.Assignee) .FirstAsync(workItem => workItem.Id == existingWorkItem.Id); workItemInDatabase.Assignee.Should().BeNull(); }); }
public async Task Can_clear_HasMany_relationship() { // Arrange var existingWorkItem = _fakers.WorkItem.Generate(); existingWorkItem.Subscribers = _fakers.UserAccount.Generate(2).ToHashSet(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.WorkItems.Add(existingWorkItem); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "workItems", id = existingWorkItem.StringId, relationships = new { subscribers = new { data = new object[0] } } } }; var route = "/workItems/" + existingWorkItem.StringId; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.SingleData.Should().NotBeNull(); await _testContext.RunOnDatabaseAsync(async dbContext => { var workItemInDatabase = await dbContext.WorkItems .Include(workItem => workItem.Subscribers) .FirstAsync(workItem => workItem.Id == existingWorkItem.Id); workItemInDatabase.Subscribers.Should().BeEmpty(); }); }
public async Task Can_update_resource_with_relationship() { // Arrange var existingBankAccount = _fakers.BankAccount.Generate(); existingBankAccount.Cards = _fakers.DebitCard.Generate(1); var existingDebitCard = _fakers.DebitCard.Generate(); var newIban = _fakers.BankAccount.Generate().Iban; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.AddRange(existingBankAccount, existingDebitCard); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "bankAccounts", id = existingBankAccount.StringId, attributes = new { iban = newIban }, relationships = new { cards = new { data = new[] { new { type = "debitCards", id = existingDebitCard.StringId } } } } } }; var route = "/bankAccounts/" + existingBankAccount.StringId; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { var bankAccountInDatabase = await dbContext.BankAccounts .Include(bankAccount => bankAccount.Cards) .FirstAsync(bankAccount => bankAccount.Id == existingBankAccount.Id); bankAccountInDatabase.Iban.Should().Be(newIban); bankAccountInDatabase.Cards.Should().HaveCount(1); bankAccountInDatabase.Cards[0].Id.Should().Be(existingDebitCard.Id); bankAccountInDatabase.Cards[0].StringId.Should().Be(existingDebitCard.StringId); }); }
public async Task Can_update_resource_without_attributes_or_relationships() { // Arrange UserAccount existingUserAccount = _fakers.UserAccount.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.UserAccounts.Add(existingUserAccount); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "userAccounts", id = existingUserAccount.StringId, attributes = new { }, relationships = new { } } }; string route = "/userAccounts/" + existingUserAccount.StringId; // Act (HttpResponseMessage httpResponse, string responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { UserAccount userAccountInDatabase = await dbContext.UserAccounts.FirstWithIdAsync(existingUserAccount.Id); userAccountInDatabase.FirstName.Should().Be(existingUserAccount.FirstName); userAccountInDatabase.LastName.Should().Be(existingUserAccount.LastName); }); }
public async Task Can_update_resource() { // Arrange Building existingBuilding = _fakers.Building.Generate(); existingBuilding.PrimaryDoor = _fakers.Door.Generate(); existingBuilding.SecondaryDoor = _fakers.Door.Generate(); existingBuilding.Windows = _fakers.Window.Generate(2); string newBuildingNumber = _fakers.Building.Generate().Number; string newPrimaryDoorColor = _fakers.Door.Generate().Color; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Buildings.Add(existingBuilding); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "buildings", id = existingBuilding.StringId, attributes = new { number = newBuildingNumber, primaryDoorColor = newPrimaryDoorColor } } }; string route = "/buildings/" + existingBuilding.StringId; // Act (HttpResponseMessage httpResponse, string responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { // @formatter:wrap_chained_method_calls chop_always // @formatter:keep_existing_linebreaks true Building buildingInDatabase = await dbContext.Buildings .Include(building => building.PrimaryDoor) .Include(building => building.SecondaryDoor) .Include(building => building.Windows) .FirstWithIdOrDefaultAsync(existingBuilding.Id); // @formatter:keep_existing_linebreaks restore // @formatter:wrap_chained_method_calls restore buildingInDatabase.Should().NotBeNull(); buildingInDatabase.Number.Should().Be(newBuildingNumber); buildingInDatabase.PrimaryDoor.Should().NotBeNull(); buildingInDatabase.PrimaryDoor.Color.Should().Be(newPrimaryDoorColor); buildingInDatabase.SecondaryDoor.Should().NotBeNull(); buildingInDatabase.Windows.Should().HaveCount(2); }); }
public async Task Can_update_resource_with_ToMany_relationship() { // Arrange var clock = (FrozenSystemClock)_testContext.Factory.Services.GetRequiredService <ISystemClock>(); clock.UtcNow = 19.March(1998).At(6, 34); PostOffice existingOffice = _fakers.PostOffice.Generate(); existingOffice.GiftCertificates = _fakers.GiftCertificate.Generate(1); string newAddress = _fakers.PostOffice.Generate().Address; await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.PostOffice.Add(existingOffice); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "postOffices", id = existingOffice.StringId, attributes = new { address = newAddress }, relationships = new { giftCertificates = new { data = new[] { new { type = "giftCertificates", id = existingOffice.GiftCertificates[0].StringId } } } } } }; string route = "/postOffices/" + existingOffice.StringId; // Act (HttpResponseMessage httpResponse, string responseDocument) = await _testContext.ExecutePatchAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { PostOffice officeInDatabase = await dbContext.PostOffice.Include(postOffice => postOffice.GiftCertificates).FirstWithIdAsync(existingOffice.Id); officeInDatabase.Address.Should().Be(newAddress); officeInDatabase.GiftCertificates.Should().HaveCount(1); officeInDatabase.GiftCertificates[0].Id.Should().Be(existingOffice.GiftCertificates[0].Id); }); }