-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding infrastructure and rudimentary tests using OData. Ported Northwind, ComplexNavigations and GearsOfWar models. Only setup for sqlserver currently. Resolves #21402
- Loading branch information
Showing
26 changed files
with
1,822 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
test/EFCore.OData.FunctionalTests/EFCore.OData.FunctionalTests.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<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> |
19 changes: 19 additions & 0 deletions
19
test/EFCore.OData.FunctionalTests/Extensions/HttpContentExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
test/EFCore.OData.FunctionalTests/Properties/TestAssemblyConditions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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] |
132 changes: 132 additions & 0 deletions
132
test/EFCore.OData.FunctionalTests/Query/ComplexNavigationsControllers.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
// 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); | ||
|
||
return result == null ? NotFound() : (ITestActionResult)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); | ||
|
||
return result == null ? NotFound() : (ITestActionResult)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); | ||
|
||
return result == null ? NotFound() : (ITestActionResult)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); | ||
|
||
return result == null ? NotFound() : (ITestActionResult)Ok(result); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
} | ||
} | ||
} |
86 changes: 86 additions & 0 deletions
86
test/EFCore.OData.FunctionalTests/Query/ComplexNavigationsODataContext.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} |
60 changes: 60 additions & 0 deletions
60
test/EFCore.OData.FunctionalTests/Query/ComplexNavigationsODataQueryTestFixture.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// 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 Microsoft.AspNet.OData.Builder; | ||
using Microsoft.EntityFrameworkCore.TestModels.ComplexNavigationsModel; | ||
using Microsoft.EntityFrameworkCore.TestUtilities; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.OData.Edm; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Query | ||
{ | ||
public class ComplexNavigationsODataQueryTestFixture : ComplexNavigationsQuerySqlServerFixture, IODataQueryTestFixture | ||
{ | ||
private IHost _selfHostServer; | ||
|
||
protected override string StoreName { get; } = "ODataComplexNavigations"; | ||
|
||
public ComplexNavigationsODataQueryTestFixture() | ||
{ | ||
(BaseAddress, ClientFactory, _selfHostServer) | ||
= ODataQueryTestFixtureInitializer.Initialize<ComplexNavigationsODataContext>(StoreName, GetEdmModel()); | ||
} | ||
|
||
public void UpdateConfigureServices<TContext>(IServiceCollection services, string storeName) | ||
where TContext : DbContext | ||
{ | ||
services.AddDbContext<TContext>(b => | ||
b.UseSqlServer( | ||
SqlServerTestStore.CreateConnectionString(storeName))); | ||
} | ||
|
||
private static IEdmModel GetEdmModel() | ||
{ | ||
var modelBuilder = new ODataConventionModelBuilder(); | ||
modelBuilder.EntitySet<Level1>("LevelOne"); | ||
modelBuilder.EntitySet<Level2>("LevelTwo"); | ||
modelBuilder.EntitySet<Level3>("LevelThree"); | ||
modelBuilder.EntitySet<Level4>("LevelFour"); | ||
|
||
return modelBuilder.GetEdmModel(); | ||
} | ||
|
||
public string BaseAddress { get; private set; } | ||
|
||
public IHttpClientFactory ClientFactory { get; private set; } | ||
|
||
public override async Task DisposeAsync() | ||
{ | ||
if (_selfHostServer != null) | ||
{ | ||
await _selfHostServer.StopAsync(); | ||
_selfHostServer.Dispose(); | ||
_selfHostServer = null; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.