public async Task Cannot_update_HasMany_relationship_for_other_parent_tenant()
        {
            // Arrange
            WebShop existingShop = _fakers.WebShop.Generate();

            existingShop.TenantId = OtherTenantId;
            existingShop.Products = _fakers.WebProduct.Generate(1);

            await _testContext.RunOnDatabaseAsync(async dbContext =>
            {
                dbContext.WebShops.Add(existingShop);
                await dbContext.SaveChangesAsync();
            });

            var requestBody = new
            {
                data = new object[0]
            };

            string route = $"/nld/shops/{existingShop.StringId}/relationships/products";

            // 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 'webShops' with ID '{existingShop.StringId}' does not exist.");
        }
        public async Task Cannot_get_secondary_resources_from_other_parent_tenant()
        {
            // Arrange
            WebShop shop = _fakers.WebShop.Generate();

            shop.TenantId = OtherTenantId;
            shop.Products = _fakers.WebProduct.Generate(1);

            await _testContext.RunOnDatabaseAsync(async dbContext =>
            {
                dbContext.WebShops.Add(shop);
                await dbContext.SaveChangesAsync();
            });

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

            // 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 'webShops' with ID '{shop.StringId}' does not exist.");
        }
        public async Task Cannot_update_resource_with_HasMany_relationship_to_other_tenant()
        {
            // Arrange
            WebShop existingShop = _fakers.WebShop.Generate();

            existingShop.TenantId = ThisTenantId;

            WebProduct existingProduct = _fakers.WebProduct.Generate();

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

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

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

            string route = "/nld/shops/" + existingShop.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 'webProducts' with ID '{existingProduct.StringId}' in relationship 'products' does not exist.");
        }
        public async Task Cannot_create_resource_with_HasOne_relationship_to_other_tenant()
        {
            // Arrange
            WebShop existingShop = _fakers.WebShop.Generate();

            existingShop.TenantId = OtherTenantId;

            string newProductName = _fakers.WebProduct.Generate().Name;

            await _testContext.RunOnDatabaseAsync(async dbContext =>
            {
                dbContext.WebShops.Add(existingShop);
                await dbContext.SaveChangesAsync();
            });

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

            const string route = "/nld/products";

            // 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 'webShops' with ID '{existingShop.StringId}' in relationship 'shop' does not exist.");
        }
        public async Task Renders_links_with_tenant_route_parameter()
        {
            // Arrange
            WebShop shop = _fakers.WebShop.Generate();

            shop.TenantId = ThisTenantId;
            shop.Products = _fakers.WebProduct.Generate(1);

            await _testContext.RunOnDatabaseAsync(async dbContext =>
            {
                await dbContext.ClearTableAsync <WebShop>();
                dbContext.WebShops.Add(shop);
                await dbContext.SaveChangesAsync();
            });

            const string route = "/nld/shops?include=products";

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

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

            responseDocument.Links.Self.Should().Be(route);
            responseDocument.Links.Related.Should().BeNull();
            responseDocument.Links.First.Should().Be(route);
            responseDocument.Links.Last.Should().BeNull();
            responseDocument.Links.Prev.Should().BeNull();
            responseDocument.Links.Next.Should().BeNull();

            string shopLink = $"/nld/shops/{shop.StringId}";

            responseDocument.ManyData.Should().HaveCount(1);
            responseDocument.ManyData[0].Links.Self.Should().Be(shopLink);
            responseDocument.ManyData[0].Relationships["products"].Links.Self.Should().Be(shopLink + "/relationships/products");
            responseDocument.ManyData[0].Relationships["products"].Links.Related.Should().Be(shopLink + "/products");

            string productLink = $"/nld/products/{shop.Products[0].StringId}";

            responseDocument.Included.Should().HaveCount(1);
            responseDocument.Included[0].Links.Self.Should().Be(productLink);
            responseDocument.Included[0].Relationships["shop"].Links.Self.Should().Be(productLink + "/relationships/shop");
            responseDocument.Included[0].Relationships["shop"].Links.Related.Should().Be(productLink + "/shop");
        }
        public async Task Can_create_resource()
        {
            // Arrange
            string newShopUrl = _fakers.WebShop.Generate().Url;

            var requestBody = new
            {
                data = new
                {
                    type       = "webShops",
                    attributes = new
                    {
                        url = newShopUrl
                    }
                }
            };

            const string route = "/nld/shops";

            // Act
            (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody);

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

            responseDocument.SingleData.Should().NotBeNull();
            responseDocument.SingleData.Attributes["url"].Should().Be(newShopUrl);
            responseDocument.SingleData.Relationships.Should().NotBeNull();

            int newShopId = int.Parse(responseDocument.SingleData.Id);

            await _testContext.RunOnDatabaseAsync(async dbContext =>
            {
                WebShop shopInDatabase = await dbContext.WebShops.IgnoreQueryFilters().FirstWithIdAsync(newShopId);

                shopInDatabase.Url.Should().Be(newShopUrl);
                shopInDatabase.TenantId.Should().Be(ThisTenantId);
            });
        }