예제 #1
0
        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);
            });
        }
예제 #2
0
        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();
            });
        }
예제 #3
0
        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);
        }
예제 #7
0
        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);
            });
        }
예제 #9
0
        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);
            });
        }
예제 #10
0
        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");
        }
예제 #11
0
        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();
        }
예제 #12
0
        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 + @"""
    }
  }
}");
        }
예제 #13
0
        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();
        }
예제 #15
0
        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();
        }
예제 #16
0
        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);
            });
        }
예제 #18
0
        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);
            });
        }
예제 #19
0
        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");
        }
예제 #20
0
        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.");
        }
예제 #22
0
        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();
            });
        }
예제 #26
0
        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();
            });
        }
예제 #27
0
        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);
            });
        }
예제 #28
0
        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);
            });
        }
예제 #29
0
        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);
            });
        }