Skip to content
Open
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
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
################################################################################
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
################################################################################

/GeekHunters.Repository/obj/project.assets.json
/GeekHunters.Repository/obj/GeekHunters.Repository.csproj.nuget.g.targets
/GeekHunters.Repository/obj/GeekHunters.Repository.csproj.nuget.g.props
/GeekHunters.Repository/obj/GeekHunters.Repository.csproj.nuget.cache
/GeekHunters.Repository/obj/Debug/netstandard2.0/GeekHunters.Repository.csproj.CoreCompileInputs.cache
/GeekHunters.Repository/obj/Debug/netstandard2.0/GeekHunters.Repository.AssemblyInfoInputs.cache
/GeekHunters.Repository/obj/Debug/netstandard2.0/GeekHunters.Repository.AssemblyInfo.cs
/GeekHunters.UnitTest/obj/project.assets.json
/GeekHunters.UnitTest/obj/GeekHunters.UnitTest.csproj.nuget.g.targets
/GeekHunters.UnitTest/obj/GeekHunters.UnitTest.csproj.nuget.g.props
/GeekHunters.UnitTest/obj/GeekHunters.UnitTest.csproj.nuget.cache
/GeekHunters.UnitTest/obj/Debug/netcoreapp2.0/GeekHunters.UnitTest.Program.cs
/GeekHunters.UnitTest/obj/Debug/netcoreapp2.0/GeekHunters.UnitTest.csproj.CoreCompileInputs.cache
/GeekHunters.UnitTest/obj/Debug/netcoreapp2.0/GeekHunters.UnitTest.AssemblyInfoInputs.cache
/GeekHunters.UnitTest/obj/Debug/netcoreapp2.0/GeekHunters.UnitTest.AssemblyInfo.cs
Binary file added .vs/GeekHunters/v15/.suo
Binary file not shown.
Binary file added .vs/GeekHunters/v15/sqlite3/storage.ide
Binary file not shown.
Binary file removed GeekHunter.sqlite
Binary file not shown.
120 changes: 120 additions & 0 deletions GeekHunters.Repository/DocumentDBRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;

namespace GeekHunters.Repository
{
public static class DocumentDBRepository<T> where T : class
{
private static readonly string Endpoint = "https://solly-cosmos-db.documents.azure.com:443/";
private static readonly string Key = "UVfKKF6vLm3SV3HNj7wJ5LvYCC1Ctnl4WTcswJUXwbk3A1gEmOFvsScErzlFi3CwaRPTNJjvVcaUXhHjunyRPw==";
private static readonly string DatabaseId = "GeekHunters";
private static readonly string CollectionId = "Candidates";
private static DocumentClient client;

public static void Initialize()
{
client = new DocumentClient(new Uri(Endpoint), Key);
CreateDatabaseIfNotExistsAsync().Wait();
CreateCollectionIfNotExistsAsync().Wait();
}

public static async Task<T> GetItemAsync(string id)
{
try
{
Document document = await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id));
return (T)(dynamic)document;
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
else
{
throw;
}
}
}

public static async Task<IEnumerable<T>> GetItemsAsync(Expression<Func<T, bool>> predicate)
{
IDocumentQuery<T> query = client.CreateDocumentQuery<T>(
UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId),
new FeedOptions { MaxItemCount = -1 })
.Where(predicate)
.AsDocumentQuery();

List<T> results = new List<T>();
while (query.HasMoreResults)
{
results.AddRange(await query.ExecuteNextAsync<T>());
}

return results;
}

public static async Task<Document> CreateItemAsync(T item)
{
return await client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), item);
}

public static async Task<Document> UpdateItemAsync(string id, T item)
{
return await client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id), item);
}

public static async Task DeleteItemAsync(string id)
{
await client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id));
}

private static async Task CreateDatabaseIfNotExistsAsync()
{
try
{
await client.ReadDatabaseAsync(UriFactory.CreateDatabaseUri(DatabaseId));
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
await client.CreateDatabaseAsync(new Database { Id = DatabaseId });
}
else
{
throw;
}
}
}

private static async Task CreateCollectionIfNotExistsAsync()
{
try
{
await client.ReadDocumentCollectionAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId));
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
await client.CreateDocumentCollectionAsync(
UriFactory.CreateDatabaseUri(DatabaseId),
new DocumentCollection { Id = CollectionId },
new RequestOptions { OfferThroughput = 1000 });
}
else
{
throw;
}
}
}
}
}
11 changes: 11 additions & 0 deletions GeekHunters.Repository/GeekHunters.Repository.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Azure.DocumentDB.Core" Version="1.5.0" />
</ItemGroup>

</Project>
219 changes: 219 additions & 0 deletions GeekHunters.UnitTest/CandidateServiceTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
using GeekHunters.Interfaces;
using GeekHunters.Models;
using GeekHunters.Repository;
using Moq;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace GeekHunters.UnitTest
{
[TestFixture]
public class CandidateServiceTest
{
private List<Candidate> candidates;
private List<string> technologies;

[OneTimeSetUp]
public void RepositorySetUp()
{
DocumentDBRepository<Candidate>.Initialize();

candidates = new List<Candidate>() {
new Candidate(){ ID = Guid.NewGuid(), FirstName = "FirstName_1", LastName = "LastName_1" },
new Candidate(){ ID = Guid.NewGuid(), FirstName = "FirstName_2", LastName = "LastName_2" },
new Candidate(){ ID = Guid.NewGuid(), FirstName = "FirstName_3", LastName = "LastName_3" }
};

technologies = new List<string>() { "Azure", "SQL", "CSharp", "Angular" };
}

[Test]
public async Task GetAllCandidatesAsync_Success()
{
// Arrange
var mockService = new Mock<ICandidateService>();
mockService.Setup(x => x.GetAllAsync()).Returns(async () =>
{
await Task.Yield();
return candidates;
});

// Act
var actual = await mockService.Object.GetAllAsync();

// Assert
Assert.AreEqual(candidates.Count(), actual.Count());
}

[Test]
public async Task GetCandidateAsynch_Success()
{
// Arrange
var candidate = new Candidate
{
ID = Guid.NewGuid(),
FirstName = "Conor",
LastName = "Mcgregor",
Technologies = technologies.Take(2).ToArray()
};

var mockService = new Mock<ICandidateService>();
mockService.Setup(x => x.GetAsync(candidate.ID.ToString())).Returns(async () =>
{
await Task.Yield();
return candidate;
});

// Act
await mockService.Object.AddAsync(candidate);
var actual = await mockService.Object.GetAsync(candidate.ID.ToString());

// Assert
Assert.AreEqual(candidate, actual);
}

[Test]
public async Task GetCandidateAsynch_NotFound_Success()
{
// Arrange
var candidateId = Guid.NewGuid().ToString();
var mockService = new Mock<ICandidateService>();

mockService.Setup(x => x.GetAsync(candidateId)).Returns(async () =>
{
await Task.Yield();
return null;
});

// Act
var actual = await mockService.Object.GetAsync(candidateId);

// Assert
mockService.Verify(m => m.GetAsync(candidateId), Times.AtLeastOnce());
Assert.AreEqual(null, actual);
}

[Test]
public async Task AddCandidateAsynch_Candidate_Success()
{
// Arrange
var candidate = new Candidate
{
ID = Guid.NewGuid(),
FirstName = "Conor",
LastName = "Mcgregor",
Technologies = technologies.Take(2).ToArray()
};

var mockService = new Mock<ICandidateService>();
mockService.Setup(x => x.AddAsync(It.IsAny<Candidate>())).Returns(async () =>
{
await Task.Yield();
return candidate;
});

// Act
var actual = await mockService.Object.AddAsync(candidate);

// Assert
Assert.AreEqual(candidate, actual);
}

[Test]
public void AddCandidateAsynch_CandidateIsNull_Failure_Throws()
{
string errorMessage = "Candidate cannot be null";

// Arrange
var candidate = It.IsAny<Candidate>();

// Act and Assert
Assert.That(async () =>
await AddCandidateAsyncThrowException(candidate, errorMessage),
Throws.Exception.TypeOf<Exception>().And.Message.EqualTo(errorMessage));
}

[Test]
public void AddCandidateAsynch_CandidateFirstNameIsEmpty_Failure_Throws()
{
string errorMessage = "First name cannot be empty";

// Arrange
var candidate = new Candidate
{
ID = Guid.NewGuid(),
LastName = "Mcgregor",
Technologies = technologies.Take(2).ToArray()
};

// Act and Assert
Assert.That(async () =>
await AddCandidateAsyncThrowException(candidate, errorMessage),
Throws.Exception.TypeOf<Exception>().And.Message.EqualTo(errorMessage));
}

[Test]
public async Task UpdateCandidateAsynch_Success()
{
// Arrange
var candidate = new Candidate
{
ID = Guid.NewGuid(),
FirstName = "Conor",
LastName = "Mcgregor",
Technologies = technologies.Take(2).ToArray()
};

var mockService = new Mock<ICandidateService>();
mockService.Setup(x => x.UpdateAsync(candidate.ID.ToString(), It.IsAny<Candidate>())).Returns(async () =>
{
await Task.Yield();
});

// Act
await mockService.Object.UpdateAsync(candidate.ID.ToString(), candidate);

// Assert
mockService.Verify(m => m.UpdateAsync(candidate.ID.ToString(), It.IsAny<Candidate>()), Times.AtLeastOnce());
Assert.That(candidate.FirstName, Is.EqualTo("Conor"));
}

[Test]
public async Task DeleteCandidateAsynch_Success()
{
// Arrange
var candidate = new Candidate
{
ID = Guid.NewGuid(),
FirstName = "Conor",
LastName = "Mcgregor",
Technologies = technologies.Take(2).ToArray()
};

var mockService = new Mock<ICandidateService>();
mockService.Setup(x => x.DeleteAsync(candidate.ID.ToString())).Returns(async () =>
{
await Task.Yield();
});

// Act
await mockService.Object.DeleteAsync(candidate.ID.ToString());
var actual = await mockService.Object.GetAsync(candidate.ID.ToString());

// Assert
mockService.Verify(m => m.DeleteAsync(candidate.ID.ToString()));
mockService.Verify(m => m.GetAsync(candidate.ID.ToString()));
Assert.AreEqual(null, actual);
}

private async Task AddCandidateAsyncThrowException(Candidate candidate, string errorMessage)
{
var mockService = new Mock<ICandidateService>();
await mockService.Object.AddAsync(candidate).ConfigureAwait(false);
throw new Exception(errorMessage);
}
}
}
22 changes: 22 additions & 0 deletions GeekHunters.UnitTest/GeekHunters.UnitTest.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="Moq" Version="4.7.99" />
<PackageReference Include="MSTest.TestAdapter" Version="1.1.18" />
<PackageReference Include="MSTest.TestFramework" Version="1.1.18" />
<PackageReference Include="NUnit" Version="3.8.1" />
<PackageReference Include="NUnit3TestAdapter" Version="3.8.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\GeekHunters\GeekHunters.csproj" />
</ItemGroup>

</Project>
Loading