Skip to content

[Staging] Missing spec tests #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ dotnet: 1.0.0-preview2-1-003177
branches:
only:
- master
- staging
script:
- ./build.sh
- ./build.sh
3 changes: 2 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pull_requests:
branches:
only:
- master
- staging
nuget:
disable_publish_on_pr: true
build_script:
Expand All @@ -19,7 +20,7 @@ deploy:
secure: 6CeYcZ4Ze+57gxfeuHzqP6ldbUkPtF6pfpVM1Gw/K2jExFrAz763gNAQ++tiacq3
skip_symbols: true
on:
branch: master
branch: staging
- provider: NuGet
name: production
api_key:
Expand Down
6 changes: 4 additions & 2 deletions src/JsonApiDotNetCore/Builders/DocumentBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public Document Build(IIdentifiable entity)
var document = new Document
{
Data = _getData(contextEntity, entity),
Meta = _getMeta(entity)
Meta = _getMeta(entity),
Links = _jsonApiContext.PageManager.GetPageLinks(new LinkBuilder(_jsonApiContext))
};

document.Included = _appendIncludedObject(document.Included, contextEntity, entity);
Expand All @@ -45,7 +46,8 @@ public Documents Build(IEnumerable<IIdentifiable> entities)
var documents = new Documents
{
Data = new List<DocumentData>(),
Meta = _getMeta(entities.FirstOrDefault())
Meta = _getMeta(entities.FirstOrDefault()),
Links = _jsonApiContext.PageManager.GetPageLinks(new LinkBuilder(_jsonApiContext))
};

foreach (var entity in entities)
Expand Down
6 changes: 5 additions & 1 deletion src/JsonApiDotNetCore/Builders/LinkBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

using JsonApiDotNetCore.Extensions;
using JsonApiDotNetCore.Services;
using Microsoft.AspNetCore.Http;
Expand Down Expand Up @@ -45,5 +44,10 @@ public string GetRelatedRelationLink(string parent, string parentId, string chil
{
return $"{_context.BasePath}/{parent.Dasherize()}/{parentId}/{child.Dasherize()}";
}

public string GetPageLink(int pageOffset, int pageSize)
{
return $"{_context.BasePath}/{_context.RequestEntity.EntityName.Dasherize()}?page[size]={pageSize}&page[number]={pageOffset}";
}
}
}
32 changes: 32 additions & 0 deletions src/JsonApiDotNetCore/Internal/PageManager.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,42 @@
using System;
using JsonApiDotNetCore.Builders;
using JsonApiDotNetCore.Models;

namespace JsonApiDotNetCore.Internal
{
public class PageManager
{
public int TotalRecords { get; set; }
public int PageSize { get; set; }
public int DefaultPageSize { get; set; }
public int CurrentPage { get; set; }
public bool IsPaginated { get { return PageSize > 0; } }
public int TotalPages {
get { return (TotalRecords == 0) ? -1: (int)Math.Ceiling(decimal.Divide(TotalRecords, PageSize)); }
}

public RootLinks GetPageLinks(LinkBuilder linkBuilder)
{
if(!IsPaginated || (CurrentPage == 1 && TotalPages <= 0))
return null;

var rootLinks = new RootLinks();

var includePageSize = DefaultPageSize != PageSize;

if(CurrentPage > 1)
rootLinks.First = linkBuilder.GetPageLink(1, PageSize);

if(CurrentPage > 1)
rootLinks.Prev = linkBuilder.GetPageLink(CurrentPage - 1, PageSize);

if(CurrentPage < TotalPages)
rootLinks.Next = linkBuilder.GetPageLink(CurrentPage + 1, PageSize);

if(TotalPages > 0)
rootLinks.Last = linkBuilder.GetPageLink(TotalPages, PageSize);

return rootLinks;
}
}
}
8 changes: 8 additions & 0 deletions src/JsonApiDotNetCore/Models/DocumentBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ namespace JsonApiDotNetCore.Models
{
public class DocumentBase
{
[JsonProperty("links")]
public RootLinks Links { get; set; }

[JsonProperty("included")]
public List<DocumentData> Included { get; set; }

Expand All @@ -21,5 +24,10 @@ public bool ShouldSerializeMeta()
{
return (Meta != null);
}

public bool ShouldSerializeLinks()
{
return (Links != null);
}
}
}
48 changes: 48 additions & 0 deletions src/JsonApiDotNetCore/Models/RootLinks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Newtonsoft.Json;

namespace JsonApiDotNetCore.Models
{
public class RootLinks
{
[JsonProperty("self")]
public string Self { get; set; }

[JsonProperty("next")]
public string Next { get; set; }

[JsonProperty("prev")]
public string Prev { get; set; }

[JsonProperty("first")]
public string First { get; set; }

[JsonProperty("last")]
public string Last { get; set; }

// http://www.newtonsoft.com/json/help/html/ConditionalProperties.htm
public bool ShouldSerializeSelf()
{
return (!string.IsNullOrEmpty(Self));
}

public bool ShouldSerializeFirst()
{
return (!string.IsNullOrEmpty(First));
}

public bool ShouldSerializeNext()
{
return (!string.IsNullOrEmpty(Next));
}

public bool ShouldSerializePrev()
{
return (!string.IsNullOrEmpty(Prev));
}

public bool ShouldSerializeLast()
{
return (!string.IsNullOrEmpty(Last));
}
}
}
2 changes: 1 addition & 1 deletion src/JsonApiDotNetCore/Services/JsonApiContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JsonApiDotNetCore.Builders;
Expand Down Expand Up @@ -58,6 +57,7 @@ private PageManager GetPageManager()
var query = QuerySet?.PageQuery ?? new PageQuery();

return new PageManager {
DefaultPageSize = Options.DefaultPageSize,
CurrentPage = query.PageOffset > 0 ? query.PageOffset : 1,
PageSize = query.PageSize > 0 ? query.PageSize : Options.DefaultPageSize
};
Expand Down
2 changes: 1 addition & 1 deletion src/JsonApiDotNetCore/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.2.12",
"version": "1.0.0-beta1-*",

"dependencies": {
"Microsoft.NETCore.App": {
Expand Down
2 changes: 2 additions & 0 deletions src/JsonApiDotNetCoreExample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public virtual IServiceProvider ConfigureServices(IServiceCollection services)
{
opt.Namespace = "api/v1";
opt.DefaultPageSize = 5;
opt.IncludeTotalRecordCount = true;
});

services.AddDocumentationConfiguration(Config);
Expand All @@ -52,6 +53,7 @@ public virtual IServiceProvider ConfigureServices(IServiceCollection services)
var appContext = provider.GetRequiredService<AppDbContext>();
if(appContext == null)
throw new ArgumentException();

return provider;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using DotNetCoreDocs;
using DotNetCoreDocs.Writers;
using JsonApiDotNetCoreExample;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Newtonsoft.Json;
using Xunit;
using Person = JsonApiDotNetCoreExample.Models.Person;
using JsonApiDotNetCore.Models;
using JsonApiDotNetCoreExample.Data;
using Bogus;
using JsonApiDotNetCoreExample.Models;
using System.Linq;
using System;

namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec.DocumentTests
{
[Collection("WebHostCollection")]
public class PagingTests
{
private DocsFixture<Startup, JsonDocWriter> _fixture;
private AppDbContext _context;
private Faker<Person> _personFaker;
private Faker<TodoItem> _todoItemFaker;
private Faker<TodoItemCollection> _todoItemCollectionFaker;

public PagingTests(DocsFixture<Startup, JsonDocWriter> fixture)
{
_fixture = fixture;
_context = fixture.GetService<AppDbContext>();
_personFaker = new Faker<Person>()
.RuleFor(p => p.FirstName, f => f.Name.FirstName())
.RuleFor(p => p.LastName, f => f.Name.LastName());

_todoItemFaker = new Faker<TodoItem>()
.RuleFor(t => t.Description, f => f.Lorem.Sentence())
.RuleFor(t => t.Ordinal, f => f.Random.Number());

_todoItemCollectionFaker = new Faker<TodoItemCollection>()
.RuleFor(t => t.Name, f => f.Company.CatchPhrase());
}

[Fact]
public async Task Server_IncludesPagination_Links()
{
// arrange
var pageSize = 5;
const int minimumNumberOfRecords = 11;
_context.TodoItems.RemoveRange(_context.TodoItems);

for(var i=0; i < minimumNumberOfRecords; i++)
_context.TodoItems.Add(_todoItemFaker.Generate());

await _context.SaveChangesAsync();

var numberOfPages = (int)Math.Ceiling(decimal.Divide(minimumNumberOfRecords, pageSize));
var startPageNumber = 2;

var builder = new WebHostBuilder()
.UseStartup<Startup>();

var httpMethod = new HttpMethod("GET");
var route = $"/api/v1/todo-items?page[number]=2";

var server = new TestServer(builder);
var client = server.CreateClient();
var request = new HttpRequestMessage(httpMethod, route);

// act
var response = await client.SendAsync(request);
var documents = JsonConvert.DeserializeObject<Documents>(await response.Content.ReadAsStringAsync());
var links = documents.Links;

// assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotEmpty(links.First);
Assert.NotEmpty(links.Next);
Assert.NotEmpty(links.Last);

Assert.Equal($"http://localhost/api/v1/todo-items?page[size]={pageSize}&page[number]={startPageNumber+1}", links.Next);
Assert.Equal($"http://localhost/api/v1/todo-items?page[size]={pageSize}&page[number]={startPageNumber-1}", links.Prev);
Assert.Equal($"http://localhost/api/v1/todo-items?page[size]={pageSize}&page[number]={numberOfPages}", links.Last);
Assert.Equal($"http://localhost/api/v1/todo-items?page[size]={pageSize}&page[number]=1", links.First);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
using JsonApiDotNetCore.Models;
using JsonApiDotNetCoreExample.Data;
using System.Linq;
using Bogus;
using JsonApiDotNetCoreExample.Models;

namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec.DocumentTests
{
Expand All @@ -19,10 +21,15 @@ public class Relationships
{
private DocsFixture<Startup, JsonDocWriter> _fixture;
private AppDbContext _context;
private Faker<TodoItem> _todoItemFaker;

public Relationships(DocsFixture<Startup, JsonDocWriter> fixture)
{
_fixture = fixture;
_context = fixture.GetService<AppDbContext>();
_todoItemFaker = new Faker<TodoItem>()
.RuleFor(t => t.Description, f => f.Lorem.Sentence())
.RuleFor(t => t.Ordinal, f => f.Random.Number());
}

[Fact]
Expand All @@ -31,18 +38,22 @@ public async Task Correct_RelationshipObjects_For_ManyToOne_Relationships()
// arrange
var builder = new WebHostBuilder()
.UseStartup<Startup>();

var todoItem = _todoItemFaker.Generate();
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();

var httpMethod = new HttpMethod("GET");
var route = $"/api/v1/todo-items";
var route = $"/api/v1/todo-items/{todoItem.Id}";

var server = new TestServer(builder);
var client = server.CreateClient();
var request = new HttpRequestMessage(httpMethod, route);

// act
var response = await client.SendAsync(request);
var documents = JsonConvert.DeserializeObject<Documents>(await response.Content.ReadAsStringAsync());
var data = documents.Data[0];
var document = JsonConvert.DeserializeObject<Document>(await response.Content.ReadAsStringAsync());
var data = document.Data;
var expectedOwnerSelfLink = $"http://localhost/api/v1/todo-items/{data.Id}/relationships/owner";
var expectedOwnerRelatedLink = $"http://localhost/api/v1/todo-items/{data.Id}/owner";

Expand All @@ -56,13 +67,15 @@ public async Task Correct_RelationshipObjects_For_ManyToOne_Relationships()
public async Task Correct_RelationshipObjects_For_ManyToOne_Relationships_ById()
{
// arrange
var todoItemId = _context.TodoItems.Last().Id;

var builder = new WebHostBuilder()
.UseStartup<Startup>();

var todoItem = _todoItemFaker.Generate();
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();

var httpMethod = new HttpMethod("GET");
var route = $"/api/v1/todo-items/{todoItemId}";
var route = $"/api/v1/todo-items/{todoItem.Id}";

var server = new TestServer(builder);
var client = server.CreateClient();
Expand All @@ -72,8 +85,8 @@ public async Task Correct_RelationshipObjects_For_ManyToOne_Relationships_ById()
var response = await client.SendAsync(request);
var responseString = await response.Content.ReadAsStringAsync();
var data = JsonConvert.DeserializeObject<Document>(responseString).Data;
var expectedOwnerSelfLink = $"http://localhost/api/v1/todo-items/{todoItemId}/relationships/owner";
var expectedOwnerRelatedLink = $"http://localhost/api/v1/todo-items/{todoItemId}/owner";
var expectedOwnerSelfLink = $"http://localhost/api/v1/todo-items/{todoItem.Id}/relationships/owner";
var expectedOwnerRelatedLink = $"http://localhost/api/v1/todo-items/{todoItem.Id}/owner";

// assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Expand Down