diff --git a/BuildRevisionCounter.Tests/App.config b/BuildRevisionCounter.Tests/App.config
index a0d182e..65a2e80 100644
--- a/BuildRevisionCounter.Tests/App.config
+++ b/BuildRevisionCounter.Tests/App.config
@@ -1,11 +1,18 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BuildRevisionCounter.Tests/BuildRevisionCounter.Tests.csproj b/BuildRevisionCounter.Tests/BuildRevisionCounter.Tests.csproj
index eb99439..6d60788 100644
--- a/BuildRevisionCounter.Tests/BuildRevisionCounter.Tests.csproj
+++ b/BuildRevisionCounter.Tests/BuildRevisionCounter.Tests.csproj
@@ -47,15 +47,24 @@
..\packages\MongoDB.Driver.Core.2.0.0\lib\net45\MongoDB.Driver.Core.dll
-
+
+ False
+ ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll
+
+
+ False
..\packages\NUnit.2.6.4\lib\nunit.framework.dll
-
+
+ False
+ ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
+
+
False
- ..\packages\Microsoft.AspNet.WebApi.Core.5.0.0\lib\net45\System.Web.Http.dll
+ ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
diff --git a/BuildRevisionCounter.Tests/Controllers/CounterControllerTest.cs b/BuildRevisionCounter.Tests/Controllers/CounterControllerTest.cs
index ba538e1..235c163 100644
--- a/BuildRevisionCounter.Tests/Controllers/CounterControllerTest.cs
+++ b/BuildRevisionCounter.Tests/Controllers/CounterControllerTest.cs
@@ -1,4 +1,7 @@
-using System.Net;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
using BuildRevisionCounter.Controllers;
@@ -33,7 +36,7 @@ public async Task CurrentThrowsExceptionIfRevisionNotFound()
{
try
{
- var rev = await _controller.Current("CurrentThrowsExceptionIfRevisionNotFound");
+ await _controller.Current("CurrentThrowsExceptionIfRevisionNotFound");
Assert.Fail();
}
catch (HttpResponseException ex)
@@ -43,10 +46,30 @@ public async Task CurrentThrowsExceptionIfRevisionNotFound()
}
[Test]
- public async Task BumpingNewRevisionReturnsOne()
+ public async Task BumpingNewRevisionReturnsZero()
{
var rev = await _controller.Bumping("BumpingNewRevisionReturnsZero");
- Assert.AreEqual(1, rev);
+ Assert.AreEqual(0, rev);
+ }
+
+ [Test]
+ public async Task BumpingNewRevisionMayBeInvokedMultipleTimes()
+ {
+ string revName = "BumpingNewRevisionMayBeInvokedMultipleTimes" + Guid.NewGuid().ToString();
+
+ // запустим сразу n потоков вставки
+ const int n = 5;
+ List taskList = new List();
+ for (int i = 0; i < n; i++)
+ {
+ taskList.Add(Task.Run(async () => await _controller.Bumping(revName)));
+ }
+ // дождемся окончания всех потококв
+ Task.WaitAll(taskList.ToArray());
+
+ // проверим результатнашего каунтера
+ var res = await _controller.Current(revName);
+ Assert.AreEqual(n - 1, res);
}
[Test]
@@ -64,5 +87,76 @@ public async Task CurrentReturnsSameValueAsPreviousBumping()
var rev2 = await _controller.Current("CurrentReturnSameValueAsPreviousBumping");
Assert.AreEqual(rev1, rev2);
}
+
+ [Test]
+ public async Task GetAllRevisionReturnsAllRevision()
+ {
+ const string revName1 = "BumpingIncrementsRevisionNumber1";
+ const string revName2 = "BumpingIncrementsRevisionNumber2";
+ const string revName3 = "BumpingIncrementsRevisionNumber3";
+
+ await _controller.Bumping(revName1);
+ await _controller.Bumping(revName1);
+ await _controller.Bumping(revName2);
+ await _controller.Bumping(revName3);
+
+ var rev1 = await _controller.Current(revName1);
+ var rev2 = await _controller.Current(revName2);
+ var rev3 = await _controller.Current(revName3);
+
+ var result = await _controller.GetAllRevision();
+
+ Assert.IsTrue(result.Any(x => x.Id == revName1 && x.NextNumber == rev1));
+ Assert.IsTrue(result.Any(x => x.Id == revName2 && x.NextNumber == rev2));
+ Assert.IsTrue(result.Any(x => x.Id == revName3 && x.NextNumber == rev3));
+ }
+
+ [Test]
+ public async Task GetAllRevisionReturnsSecondPage()
+ {
+ // пересоздадим БД перед этим тестом,
+ // он должен проводиться на чистой БД
+ SetUpAsync().Wait();
+
+ for (int i = 0; i < 10; i++)
+ {
+ string revName = "GetAllRevisionReturnsSecondPage" + i.ToString();
+ await _controller.Bumping(revName);
+ }
+
+ var result = await _controller.GetAllRevision(3, 2);
+
+ Assert.IsTrue(result.Any(x => x.Id == "GetAllRevisionReturnsSecondPage3"));
+ Assert.IsTrue(result.Any(x => x.Id == "GetAllRevisionReturnsSecondPage4"));
+ Assert.IsTrue(result.Any(x => x.Id == "GetAllRevisionReturnsSecondPage5"));
+ }
+
+ [Test]
+ public async Task GetAllRevisionArgumentExceptionPageSize()
+ {
+ try
+ {
+ await _controller.GetAllRevision(0, 2);
+ Assert.Fail();
+ }
+ catch (HttpResponseException ex)
+ {
+ Assert.AreEqual(HttpStatusCode.BadRequest, ex.Response.StatusCode);
+ }
+ }
+
+ [Test]
+ public async Task GetAllRevisionArgumentExceptionPageNumber()
+ {
+ try
+ {
+ await _controller.GetAllRevision(3, 0);
+ Assert.Fail();
+ }
+ catch (HttpResponseException ex)
+ {
+ Assert.AreEqual(HttpStatusCode.BadRequest, ex.Response.StatusCode);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/BuildRevisionCounter.Tests/packages.config b/BuildRevisionCounter.Tests/packages.config
index 4dd89e5..ac95f92 100644
--- a/BuildRevisionCounter.Tests/packages.config
+++ b/BuildRevisionCounter.Tests/packages.config
@@ -1,7 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/BuildRevisionCounter/BuildRevisionCounter.csproj b/BuildRevisionCounter/BuildRevisionCounter.csproj
index 596f9ab..e7ee5a4 100644
--- a/BuildRevisionCounter/BuildRevisionCounter.csproj
+++ b/BuildRevisionCounter/BuildRevisionCounter.csproj
@@ -41,10 +41,10 @@
- ..\packages\Microsoft.Owin.3.0.0\lib\net45\Microsoft.Owin.dll
+ ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll
- ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll
+ ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll
False
@@ -57,9 +57,9 @@
..\packages\MongoDB.Driver.Core.2.0.0\lib\net45\MongoDB.Driver.Core.dll
-
+
False
- ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll
+ ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll
False
@@ -71,13 +71,16 @@
..\packages\Ninject.Web.Common.3.2.3.0\lib\net45-full\Ninject.Web.Common.dll
-
+
+ False
..\packages\Ninject.Web.Common.OwinHost.3.2.3.0\lib\net45-full\Ninject.Web.Common.OwinHost.dll
-
+
+ False
..\packages\Ninject.Web.WebApi.3.2.4.0\lib\net45-full\Ninject.Web.WebApi.dll
-
+
+ False
..\packages\Ninject.Web.WebApi.OwinHost.3.2.4.0\lib\net45-full\Ninject.Web.WebApi.OwinHost.dll
@@ -85,9 +88,9 @@
-
+
False
- ..\packages\Microsoft.AspNet.WebApi.Client.5.0.0\lib\net45\System.Net.Http.Formatting.dll
+ ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
@@ -98,13 +101,13 @@
-
+
False
- ..\packages\Microsoft.AspNet.WebApi.Core.5.0.0\lib\net45\System.Web.Http.dll
+ ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
-
+
False
- ..\packages\Microsoft.AspNet.WebApi.Owin.5.0.0\lib\net45\System.Web.Http.Owin.dll
+ ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll
@@ -116,7 +119,9 @@
-
+
+ Designer
+
diff --git a/BuildRevisionCounter/Controllers/CounterController.cs b/BuildRevisionCounter/Controllers/CounterController.cs
index c0e65a8..0a366dd 100644
--- a/BuildRevisionCounter/Controllers/CounterController.cs
+++ b/BuildRevisionCounter/Controllers/CounterController.cs
@@ -1,5 +1,7 @@
using System;
+using System.Collections.Generic;
using System.Net;
+using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using BuildRevisionCounter.Interfaces;
@@ -27,6 +29,39 @@ public CounterController(IMongoDBStorage mongoDbStorage)
_mongoDbStorage = mongoDbStorage;
}
+ [HttpGet]
+ [Route("")]
+ [Authorize(Roles = "admin, editor, anonymous")]
+ public async Task> GetAllRevision([FromUri] Int32 pageSize=20, [FromUri] Int32 pageNumber=1)
+ {
+ if (pageSize < 1 || pageNumber < 1)
+ throw new HttpResponseException(HttpStatusCode.BadRequest);
+
+ CancellationTokenSource cts = new CancellationTokenSource();
+ var task = _mongoDbStorage.Revisions
+ .Find(r => true)
+ .Skip(pageSize * (pageNumber - 1))
+ .Limit(pageSize)
+ .ToListAsync(cts.Token);
+
+ // запустим паралельно 2 таска, второй таск в роли таймаута (30 сек)
+ const int timeout = 30*1000;
+ if (await Task.WhenAny(task, Task.Delay(timeout, cts.Token)) != task)
+ {
+ // посылаем команду прервать поток поиска
+ cts.Cancel();
+ // генерируем сообщение о том что не дождались ответа от монги
+ throw new HttpResponseException(HttpStatusCode.GatewayTimeout);
+ }
+ // прерываем поток таймаута
+ cts.Cancel();
+
+ if (task.Result == null)
+ throw new HttpResponseException(HttpStatusCode.NotFound);
+
+ return task.Result;
+ }
+
[HttpGet]
[Route("{revisionName}")]
[Authorize(Roles = "admin, editor, anonymous")]
@@ -46,6 +81,42 @@ public async Task Current([FromUri] string revisionName)
[Route("{revisionName}")]
[Authorize(Roles = "buildserver")]
public async Task Bumping([FromUri] string revisionName)
+ {
+ // попробуем обновить документ
+ var result = await FindOneAndUpdateRevisionModelAsync(revisionName);
+
+ if (result == null)
+ {
+ // если не получилось, значит документ еще не был создан
+ // создадим его с начальным значением 0
+ try
+ {
+ await _mongoDbStorage.Revisions
+ .InsertOneAsync(new RevisionModel
+ {
+ Id = revisionName,
+ NextNumber = 0,
+ Created = DateTime.UtcNow
+ });
+ return 0;
+ }
+ catch (MongoWriteException)
+ {
+ // если прои вставке произошла ошибка значит мы не успели и запись там уже есть
+ // и теперь попытка обновления должна пройти без ошибок
+ result = FindOneAndUpdateRevisionModelAsync(revisionName).Result;
+ }
+ }
+
+ return result.NextNumber;
+ }
+
+ ///
+ /// Инкриментит каунтер в БД
+ ///
+ ///
+ ///
+ private async Task FindOneAndUpdateRevisionModelAsync(string revisionName)
{
var result = await _mongoDbStorage.Revisions
.FindOneAndUpdateAsync(
@@ -56,12 +127,11 @@ public async Task Bumping([FromUri] string revisionName)
.Set(r => r.Updated, DateTime.UtcNow),
new FindOneAndUpdateOptions
{
- IsUpsert = true,
+ IsUpsert = false,
ReturnDocument = ReturnDocument.After
});
-
- return result.NextNumber;
+ return result;
}
}
}
\ No newline at end of file
diff --git a/BuildRevisionCounter/Startup.cs b/BuildRevisionCounter/Startup.cs
index fc77cfa..f5cef1b 100644
--- a/BuildRevisionCounter/Startup.cs
+++ b/BuildRevisionCounter/Startup.cs
@@ -1,24 +1,58 @@
-using System.Configuration;
+using System;
+using System.Configuration;
+using System.Net.Http.Formatting;
+using System.Reflection;
+using System.Web.Http;
using System.Web.Http.Filters;
+using BuildRevisionCounter;
+using BuildRevisionCounter.Interfaces;
using BuildRevisionCounter.Security;
using Microsoft.Owin;
using MongoDB.Driver;
using Ninject;
+using Ninject.Modules;
using Ninject.Web.Common.OwinHost;
using Ninject.Web.WebApi.FilterBindingSyntax;
using Ninject.Web.WebApi.OwinHost;
using Owin;
-using BuildRevisionCounter;
-using System.Web.Http;
-using System.Net.Http.Formatting;
-using BuildRevisionCounter.Interfaces;
[assembly: OwinStartup(typeof(Startup))]
namespace BuildRevisionCounter
{
+ public class MyAssemblyNameRetriever : AssemblyNameRetriever
+ {
+
+ }
+
public class Startup
{
+ static Startup()
+ {
+ AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
+ }
+
+ private static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
+ {
+ var name = new AssemblyName(args.Name);
+ //if (name.Name == "System.Web.Http")
+ //{
+ // name.Version = new Version(5, 2, 3, 0);
+ // return Assembly.Load(name);
+ //}
+ if (name.Name == "System.Web.Http.Owin")
+ {
+ name.Version = new Version(5, 2, 3, 0);
+ return Assembly.Load(name);
+ }
+ if (name.Name == "Microsoft.Owin")
+ {
+ name.Version = new Version(3, 0, 1, 0);
+ return Assembly.Load(name);
+ }
+ return null;
+ }
+
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
diff --git a/BuildRevisionCounter/Web.config b/BuildRevisionCounter/Web.config
index 210bf89..1e428b3 100644
--- a/BuildRevisionCounter/Web.config
+++ b/BuildRevisionCounter/Web.config
@@ -18,9 +18,9 @@
-
-
+
+
-
\ No newline at end of file
+
diff --git a/BuildRevisionCounter/packages.config b/BuildRevisionCounter/packages.config
index 80e8661..460b340 100644
--- a/BuildRevisionCounter/packages.config
+++ b/BuildRevisionCounter/packages.config
@@ -1,14 +1,14 @@
-
-
-
-
-
+
+
+
+
+
-
+