Skip to content

Commit

Permalink
Fix to #21402 - Test using OData
Browse files Browse the repository at this point in the history
Adding infrastructure and rudimentary tests using OData. Ported Northwind, ComplexNavigations and GearsOfWar models. Only setup for sqlserver currently.

Resolves #21402
  • Loading branch information
maumar committed Sep 15, 2020
1 parent 2008335 commit 9d1411f
Show file tree
Hide file tree
Showing 28 changed files with 2,033 additions and 2 deletions.
1 change: 1 addition & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ updates:
- dependency-name: Castle.Core
- dependency-name: Humanizer.Core
- dependency-name: IdentityServer4.EntityFramework
- dependency-name: Microsoft.AspNetCore.OData
- dependency-name: Microsoft.Azure.Cosmos
- dependency-name: Microsoft.CSharp
- dependency-name: Microsoft.Data.SqlClient
Expand Down
7 changes: 7 additions & 0 deletions All.sln
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Data.Sqlite.winsq
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Data.Sqlite.sqlite3.Tests", "test\Microsoft.Data.Sqlite.Tests\Microsoft.Data.Sqlite.sqlite3.Tests.csproj", "{E0FF35C8-8038-4394-9C2A-AF34BE3CC61F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFCore.OData.FunctionalTests", "test\EFCore.OData.FunctionalTests\EFCore.OData.FunctionalTests.csproj", "{7C0E5443-FE44-4436-8A7D-CE64D1F889BD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -288,6 +290,10 @@ Global
{E0FF35C8-8038-4394-9C2A-AF34BE3CC61F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0FF35C8-8038-4394-9C2A-AF34BE3CC61F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0FF35C8-8038-4394-9C2A-AF34BE3CC61F}.Release|Any CPU.Build.0 = Release|Any CPU
{7C0E5443-FE44-4436-8A7D-CE64D1F889BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C0E5443-FE44-4436-8A7D-CE64D1F889BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C0E5443-FE44-4436-8A7D-CE64D1F889BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C0E5443-FE44-4436-8A7D-CE64D1F889BD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -336,6 +342,7 @@ Global
{7B598E0C-B8E2-4F1F-B53C-ED84178E65BE} = {258D5057-81B9-40EC-A872-D21E27452749}
{B163761D-FB4A-4C80-BAB9-01905E1351EF} = {258D5057-81B9-40EC-A872-D21E27452749}
{E0FF35C8-8038-4394-9C2A-AF34BE3CC61F} = {258D5057-81B9-40EC-A872-D21E27452749}
{7C0E5443-FE44-4436-8A7D-CE64D1F889BD} = {258D5057-81B9-40EC-A872-D21E27452749}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {285A5EB4-BCF4-40EB-B9E1-DF6DBCB5E705}
Expand Down
1 change: 1 addition & 0 deletions EFCore.Relational.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"test\\EFCore.Design.Tests\\EFCore.Design.Tests.csproj",
"test\\EFCore.InMemory.FunctionalTests\\EFCore.InMemory.FunctionalTests.csproj",
"test\\EFCore.InMemory.Tests\\EFCore.InMemory.Tests.csproj",
"test\\EFCore.OData.FunctionalTests\\EFCore.OData.FunctionalTests.csproj",
"test\\EFCore.Proxies.Tests\\EFCore.Proxies.Tests.csproj",
"test\\EFCore.Relational.Specification.Tests\\EFCore.Relational.Specification.Tests.csproj",
"test\\EFCore.Relational.Tests\\EFCore.Relational.Tests.csproj",
Expand Down
3 changes: 2 additions & 1 deletion EFCore.Runtime.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"test\\EFCore.Design.Tests\\EFCore.Design.Tests.csproj",
"test\\EFCore.InMemory.FunctionalTests\\EFCore.InMemory.FunctionalTests.csproj",
"test\\EFCore.InMemory.Tests\\EFCore.InMemory.Tests.csproj",
"test\\EFCore.OData.FunctionalTests\\EFCore.OData.FunctionalTests.csproj",
"test\\EFCore.Proxies.Tests\\EFCore.Proxies.Tests.csproj",
"test\\EFCore.Relational.Specification.Tests\\EFCore.Relational.Specification.Tests.csproj",
"test\\EFCore.Relational.Tests\\EFCore.Relational.Tests.csproj",
Expand All @@ -31,7 +32,7 @@
"test\\EFCore.SqlServer.Tests\\EFCore.SqlServer.Tests.csproj",
"test\\EFCore.Sqlite.FunctionalTests\\EFCore.Sqlite.FunctionalTests.csproj",
"test\\EFCore.Sqlite.Tests\\EFCore.Sqlite.Tests.csproj",
"test\\EFCore.Tests\\EFCore.Tests.csproj"
"test\\EFCore.Tests\\EFCore.Tests.csproj",
]
}
}
1 change: 1 addition & 0 deletions EFCore.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"test\\EFCore.Design.Tests\\EFCore.Design.Tests.csproj",
"test\\EFCore.InMemory.FunctionalTests\\EFCore.InMemory.FunctionalTests.csproj",
"test\\EFCore.InMemory.Tests\\EFCore.InMemory.Tests.csproj",
"test\\EFCore.OData.FunctionalTests\\EFCore.OData.FunctionalTests.csproj",
"test\\EFCore.Proxies.Tests\\EFCore.Proxies.Tests.csproj",
"test\\EFCore.Relational.Specification.Tests\\EFCore.Relational.Specification.Tests.csproj",
"test\\EFCore.Relational.Tests\\EFCore.Relational.Tests.csproj",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
<AssemblyName>Microsoft.EntityFrameworkCore.OData.FunctionalTests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<IsPackable>true</IsPackable>
<SkipTests Condition="'$(OS)' != 'Windows_NT' AND '$(Test__SqlServer__DefaultConnection)' == ''">True</SkipTests>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OData" Version="7.4.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\EFCore.SqlServer.FunctionalTests\EFCore.SqlServer.FunctionalTests.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace Microsoft.EntityFrameworkCore.Extensions
{
public static class HttpContentExtensions
{
public static async Task<T> ReadAsObject<T>(this HttpContent content)
{
var json = await content.ReadAsStringAsync();

return JsonConvert.DeserializeObject<T>(json);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.EntityFrameworkCore.TestUtilities;

// Skip the entire assembly if not on Windows and no external SQL Server is configured
[assembly: SqlServerConfiguredCondition]
27 changes: 27 additions & 0 deletions test/EFCore.OData.FunctionalTests/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:64176",
"sslPort": 44376
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"EFCore.OData.Tests": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.OData;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore.TestModels.ComplexNavigationsModel;

namespace Microsoft.EntityFrameworkCore.Query
{
public class LevelOneController : TestODataController, IDisposable
{
private readonly ComplexNavigationsODataContext _context;

public LevelOneController(ComplexNavigationsODataContext context)
{
_context = context;
}

[HttpGet]
[EnableQuery]
public IEnumerable<Level1> Get()
{
return _context.LevelOne;
}

[HttpGet]
[EnableQuery]
public ITestActionResult Get([FromODataUri] int key)
{
var result = _context.LevelOne.FirstOrDefault(e => e.Id == key);
if (result == null)
{
return NotFound();
}

return Ok(result);
}

public void Dispose()
{
}
}

public class LevelTwoController : TestODataController, IDisposable
{
private readonly ComplexNavigationsODataContext _context;

public LevelTwoController(ComplexNavigationsODataContext context)
{
_context = context;
}

[HttpGet]
[EnableQuery]
public IEnumerable<Level2> Get()
{
return _context.LevelTwo;
}

[HttpGet]
[EnableQuery]
public ITestActionResult Get([FromODataUri] int key)
{
var result = _context.LevelTwo.FirstOrDefault(e => e.Id == key);
if (result == null)
{
return NotFound();
}

return Ok(result);
}

public void Dispose()
{
}
}

public class LevelThreeController : TestODataController, IDisposable
{
private readonly ComplexNavigationsODataContext _context;

public LevelThreeController(ComplexNavigationsODataContext context)
{
_context = context;
}

[HttpGet]
[EnableQuery]
public IEnumerable<Level3> Get()
{
return _context.LevelThree;
}

[HttpGet]
[EnableQuery]
public ITestActionResult Get([FromODataUri] int key)
{
var result = _context.LevelThree.FirstOrDefault(e => e.Id == key);
if (result == null)
{
return NotFound();
}

return Ok(result);
}

public void Dispose()
{
}
}

public class LevelFourController : TestODataController, IDisposable
{
private readonly ComplexNavigationsODataContext _context;

public LevelFourController(ComplexNavigationsODataContext context)
{
_context = context;
}

[HttpGet]
[EnableQuery]
public IEnumerable<Level4> Get()
{
return _context.LevelFour;
}

[HttpGet]
[EnableQuery]
public ITestActionResult Get([FromODataUri] int key)
{
var result = _context.LevelFour.FirstOrDefault(e => e.Id == key);
if (result == null)
{
return NotFound();
}

return Ok(result);
}

public void Dispose()
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.EntityFrameworkCore.TestModels.ComplexNavigationsModel;
using Microsoft.EntityFrameworkCore.TestUtilities;

namespace Microsoft.EntityFrameworkCore.Query
{
public class ComplexNavigationsODataContext : PoolableDbContext
{
public ComplexNavigationsODataContext(DbContextOptions options)
: base(options)
{
}

public DbSet<Level1> LevelOne { get; set; }
public DbSet<Level2> LevelTwo { get; set; }
public DbSet<Level3> LevelThree { get; set; }
public DbSet<Level4> LevelFour { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Level1>().Property(e => e.Id).ValueGeneratedNever();
modelBuilder.Entity<Level2>().Property(e => e.Id).ValueGeneratedNever();
modelBuilder.Entity<Level3>().Property(e => e.Id).ValueGeneratedNever();
modelBuilder.Entity<Level4>().Property(e => e.Id).ValueGeneratedNever();

modelBuilder.Entity<Level1>().HasOne(e => e.OneToOne_Optional_Self1).WithOne();
modelBuilder.Entity<Level1>().HasOne(e => e.OneToOne_Required_PK1).WithOne(e => e.OneToOne_Required_PK_Inverse2)
.HasPrincipalKey<Level1>(e => e.Id).HasForeignKey<Level2>(e => e.Id).IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Level1>().HasOne(e => e.OneToOne_Optional_PK1).WithOne(e => e.OneToOne_Optional_PK_Inverse2)
.HasPrincipalKey<Level1>(e => e.Id).IsRequired(false);
modelBuilder.Entity<Level1>().HasOne(e => e.OneToOne_Required_FK1).WithOne(e => e.OneToOne_Required_FK_Inverse2)
.HasForeignKey<Level2>(e => e.Level1_Required_Id).IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Level1>().HasOne(e => e.OneToOne_Optional_FK1).WithOne(e => e.OneToOne_Optional_FK_Inverse2)
.HasForeignKey<Level2>(e => e.Level1_Optional_Id).IsRequired(false);
modelBuilder.Entity<Level1>().HasMany(e => e.OneToMany_Required1).WithOne(e => e.OneToMany_Required_Inverse2).IsRequired()
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Level1>().HasMany(e => e.OneToMany_Optional1).WithOne(e => e.OneToMany_Optional_Inverse2).IsRequired(false);
modelBuilder.Entity<Level1>().HasMany(e => e.OneToMany_Required_Self1).WithOne(e => e.OneToMany_Required_Self_Inverse1)
.IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Level1>().HasMany(e => e.OneToMany_Optional_Self1).WithOne(e => e.OneToMany_Optional_Self_Inverse1)
.IsRequired(false);

modelBuilder.Entity<Level2>().HasOne(e => e.OneToOne_Optional_Self2).WithOne();
modelBuilder.Entity<Level2>().HasOne(e => e.OneToOne_Required_PK2).WithOne(e => e.OneToOne_Required_PK_Inverse3)
.HasPrincipalKey<Level2>(e => e.Id).HasForeignKey<Level3>(e => e.Id).IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Level2>().HasOne(e => e.OneToOne_Optional_PK2).WithOne(e => e.OneToOne_Optional_PK_Inverse3)
.HasPrincipalKey<Level2>(e => e.Id).IsRequired(false);
modelBuilder.Entity<Level2>().HasOne(e => e.OneToOne_Required_FK2).WithOne(e => e.OneToOne_Required_FK_Inverse3)
.HasForeignKey<Level3>(e => e.Level2_Required_Id).IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Level2>().HasOne(e => e.OneToOne_Optional_FK2).WithOne(e => e.OneToOne_Optional_FK_Inverse3)
.HasForeignKey<Level3>(e => e.Level2_Optional_Id).IsRequired(false);
modelBuilder.Entity<Level2>().HasMany(e => e.OneToMany_Required2).WithOne(e => e.OneToMany_Required_Inverse3).IsRequired()
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Level2>().HasMany(e => e.OneToMany_Optional2).WithOne(e => e.OneToMany_Optional_Inverse3).IsRequired(false);
modelBuilder.Entity<Level2>().HasMany(e => e.OneToMany_Required_Self2).WithOne(e => e.OneToMany_Required_Self_Inverse2)
.IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Level2>().HasMany(e => e.OneToMany_Optional_Self2).WithOne(e => e.OneToMany_Optional_Self_Inverse2)
.IsRequired(false);

modelBuilder.Entity<Level3>().HasOne(e => e.OneToOne_Optional_Self3).WithOne();
modelBuilder.Entity<Level3>().HasOne(e => e.OneToOne_Required_PK3).WithOne(e => e.OneToOne_Required_PK_Inverse4)
.HasPrincipalKey<Level3>(e => e.Id).HasForeignKey<Level4>(e => e.Id).IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Level3>().HasOne(e => e.OneToOne_Optional_PK3).WithOne(e => e.OneToOne_Optional_PK_Inverse4)
.HasPrincipalKey<Level3>(e => e.Id).IsRequired(false);
modelBuilder.Entity<Level3>().HasOne(e => e.OneToOne_Required_FK3).WithOne(e => e.OneToOne_Required_FK_Inverse4)
.HasForeignKey<Level4>(e => e.Level3_Required_Id).IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Level3>().HasOne(e => e.OneToOne_Optional_FK3).WithOne(e => e.OneToOne_Optional_FK_Inverse4)
.HasForeignKey<Level4>(e => e.Level3_Optional_Id).IsRequired(false);
modelBuilder.Entity<Level3>().HasMany(e => e.OneToMany_Required3).WithOne(e => e.OneToMany_Required_Inverse4).IsRequired()
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Level3>().HasMany(e => e.OneToMany_Optional3).WithOne(e => e.OneToMany_Optional_Inverse4).IsRequired(false);
modelBuilder.Entity<Level3>().HasMany(e => e.OneToMany_Required_Self3).WithOne(e => e.OneToMany_Required_Self_Inverse3)
.IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Level3>().HasMany(e => e.OneToMany_Optional_Self3).WithOne(e => e.OneToMany_Optional_Self_Inverse3)
.IsRequired(false);

modelBuilder.Entity<Level4>().HasOne(e => e.OneToOne_Optional_Self4).WithOne();
modelBuilder.Entity<Level4>().HasMany(e => e.OneToMany_Required_Self4).WithOne(e => e.OneToMany_Required_Self_Inverse4)
.IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Level4>().HasMany(e => e.OneToMany_Optional_Self4).WithOne(e => e.OneToMany_Optional_Self_Inverse4)
.IsRequired(false);
}
}
}
Loading

0 comments on commit 9d1411f

Please sign in to comment.