public async Task Cannot_update_HasOne_relationship_for_other_parent_tenant()
        {
            // Arrange
            WebProduct existingProduct = _fakers.WebProduct.Generate();

            existingProduct.Shop          = _fakers.WebShop.Generate();
            existingProduct.Shop.TenantId = OtherTenantId;

            await _testContext.RunOnDatabaseAsync(async dbContext =>
            {
                dbContext.WebProducts.Add(existingProduct);
                await dbContext.SaveChangesAsync();
            });

            var requestBody = new
            {
                data = (object)null
            };

            string route = $"/nld/products/{existingProduct.StringId}/relationships/shop";

            // 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 'webProducts' with ID '{existingProduct.StringId}' does not exist.");
        }
        public async Task Can_delete_resource()
        {
            // Arrange
            WebProduct existingProduct = _fakers.WebProduct.Generate();

            existingProduct.Shop          = _fakers.WebShop.Generate();
            existingProduct.Shop.TenantId = ThisTenantId;

            await _testContext.RunOnDatabaseAsync(async dbContext =>
            {
                dbContext.WebProducts.Add(existingProduct);
                await dbContext.SaveChangesAsync();
            });

            string route = "/nld/products/" + existingProduct.StringId;

            // Act
            (HttpResponseMessage httpResponse, string responseDocument) = await _testContext.ExecuteDeleteAsync <string>(route);

            // Assert
            httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent);

            responseDocument.Should().BeEmpty();

            await _testContext.RunOnDatabaseAsync(async dbContext =>
            {
                WebProduct productInDatabase = await dbContext.WebProducts.IgnoreQueryFilters().FirstWithIdOrDefaultAsync(existingProduct.Id);

                productInDatabase.Should().BeNull();
            });
        }
        public async Task Cannot_get_secondary_resource_from_other_parent_tenant()
        {
            // Arrange
            WebProduct product = _fakers.WebProduct.Generate();

            product.Shop          = _fakers.WebShop.Generate();
            product.Shop.TenantId = OtherTenantId;

            await _testContext.RunOnDatabaseAsync(async dbContext =>
            {
                dbContext.WebProducts.Add(product);
                await dbContext.SaveChangesAsync();
            });

            string route = $"/nld/products/{product.StringId}/shop";

            // Act
            (HttpResponseMessage httpResponse, ErrorDocument responseDocument) = await _testContext.ExecuteGetAsync <ErrorDocument>(route);

            // 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 'webProducts' with ID '{product.StringId}' does not exist.");
        }
        public async Task Cannot_create_resource_with_HasMany_relationship_to_other_tenant()
        {
            // Arrange
            WebProduct existingProduct = _fakers.WebProduct.Generate();

            existingProduct.Shop          = _fakers.WebShop.Generate();
            existingProduct.Shop.TenantId = OtherTenantId;

            string newShopUrl = _fakers.WebShop.Generate().Url;

            await _testContext.RunOnDatabaseAsync(async dbContext =>
            {
                dbContext.WebProducts.Add(existingProduct);
                await dbContext.SaveChangesAsync();
            });

            var requestBody = new
            {
                data = new
                {
                    type       = "webShops",
                    attributes = new
                    {
                        url = newShopUrl
                    },
                    relationships = new
                    {
                        products = new
                        {
                            data = new[]
                            {
                                new
                                {
                                    type = "webProducts",
                                    id   = existingProduct.StringId
                                }
                            }
                        }
                    }
                }
            };

            const string route = "/nld/shops";

            // Act
            (HttpResponseMessage httpResponse, ErrorDocument responseDocument) = await _testContext.ExecutePostAsync <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("A related resource does not exist.");
            error.Detail.Should().Be($"Related resource of type 'webProducts' with ID '{existingProduct.StringId}' in relationship 'products' does not exist.");
        }
        public async Task Cannot_update_resource_with_HasOne_relationship_to_other_tenant()
        {
            // Arrange
            WebProduct existingProduct = _fakers.WebProduct.Generate();

            existingProduct.Shop          = _fakers.WebShop.Generate();
            existingProduct.Shop.TenantId = ThisTenantId;

            WebShop existingShop = _fakers.WebShop.Generate();

            existingShop.TenantId = OtherTenantId;

            await _testContext.RunOnDatabaseAsync(async dbContext =>
            {
                dbContext.AddRange(existingProduct, existingShop);
                await dbContext.SaveChangesAsync();
            });

            var requestBody = new
            {
                data = new
                {
                    type          = "webProducts",
                    id            = existingProduct.StringId,
                    relationships = new
                    {
                        shop = new
                        {
                            data = new
                            {
                                type = "webShops",
                                id   = existingShop.StringId
                            }
                        }
                    }
                }
            };

            string route = "/nld/products/" + existingProduct.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("A related resource does not exist.");
            error.Detail.Should().Be($"Related resource of type 'webShops' with ID '{existingShop.StringId}' in relationship 'shop' does not exist.");
        }
        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 Cannot_update_resource_from_other_tenant()
        {
            // Arrange
            WebProduct existingProduct = _fakers.WebProduct.Generate();

            existingProduct.Shop          = _fakers.WebShop.Generate();
            existingProduct.Shop.TenantId = OtherTenantId;

            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, 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 'webProducts' with ID '{existingProduct.StringId}' does not exist.");
        }