From 4183672c6e15192de159c01d7ca2bdaa6d2709d4 Mon Sep 17 00:00:00 2001 From: johnataylor Date: Mon, 21 Jan 2013 16:26:18 -0800 Subject: [PATCH] moved aggregate stats from pages to stats --- Facts/Controllers/PagesControllerFacts.cs | 103 ------------------ .../Controllers/StatisticsControllerFacts.cs | 100 ++++++++++++++++- Facts/Facts.csproj | 1 - Website/App_Start/Routes.cs | 12 +- Website/Controllers/PagesController.cs | 42 +------ Website/Controllers/StatisticsController.cs | 79 +++++++++++++- Website/PagesController.generated.cs | 6 - Website/Services/CloudReportService.cs | 2 - Website/StatisticsController.generated.cs | 6 + .../ViewModels/StatisticsPackagesViewModel.cs | 22 ---- 10 files changed, 180 insertions(+), 193 deletions(-) delete mode 100644 Facts/Controllers/PagesControllerFacts.cs diff --git a/Facts/Controllers/PagesControllerFacts.cs b/Facts/Controllers/PagesControllerFacts.cs deleted file mode 100644 index 900297255e..0000000000 --- a/Facts/Controllers/PagesControllerFacts.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; -using Moq; -using Xunit; - -namespace NuGetGallery.Controllers -{ - public class PagesControllerFacts - { - public class TheStatsAction - { - [Fact] - public void UseServerCultureIfLanguageHeadersIsMissing() - { - // Arrange - var currentCulture = CultureInfo.CurrentCulture; - - try - { - Thread.CurrentThread.CurrentCulture = new CultureInfo("en-us"); - - var statsService = new Mock(MockBehavior.Strict); - var stats = new AggregateStats - { - Downloads = 2013, - TotalPackages = 1000, - UniquePackages = 500 - }; - statsService.Setup(s => s.GetAggregateStats()).Returns(stats); - - var controller = CreateController(statsService); - - // Act - var result = controller.Stats() as JsonResult; - - // Asssert - Assert.NotNull(result); - dynamic data = result.Data; - - Assert.Equal("2,013", (string)data.Downloads); - Assert.Equal("500", (string)data.UniquePackages); - Assert.Equal("1,000", (string)data.TotalPackages); - } - finally - { - Thread.CurrentThread.CurrentCulture = currentCulture; - } - } - - [Fact] - public void UseClientCultureIfLanguageHeadersIsPresent() - { - // Arrange - var statsService = new Mock(MockBehavior.Strict); - var stats = new AggregateStats - { - Downloads = 2013, - TotalPackages = 1000, - UniquePackages = 500 - }; - statsService.Setup(s => s.GetAggregateStats()).Returns(stats); - - var request = new Mock(); - request.Setup(r => r.UserLanguages).Returns(new string[] { "vi-VN" }); - - var controller = CreateController(statsService, request); - - // Act - var result = controller.Stats() as JsonResult; - - // Asssert - Assert.NotNull(result); - dynamic data = result.Data; - - Assert.Equal("2.013", (string)data.Downloads); - Assert.Equal("500", (string)data.UniquePackages); - Assert.Equal("1.000", (string)data.TotalPackages); - } - } - - public static PagesController CreateController(Mock statsService, Mock request = null) - { - request = request ?? new Mock(); - - var context = new Mock(); - context.SetupGet(s => s.Request).Returns(request.Object); - - var controller = new PagesController(statsService.Object); - controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller); - - return controller; - } - - } -} diff --git a/Facts/Controllers/StatisticsControllerFacts.cs b/Facts/Controllers/StatisticsControllerFacts.cs index 24ecfc7a37..aa0017d16a 100644 --- a/Facts/Controllers/StatisticsControllerFacts.cs +++ b/Facts/Controllers/StatisticsControllerFacts.cs @@ -3,6 +3,10 @@ using System.Threading.Tasks; using System.Web.Mvc; using Xunit; +using System.Globalization; +using System.Web; +using System.Threading; +using System.Web.Routing; namespace NuGetGallery { @@ -19,7 +23,7 @@ public async void StatisticsHomePage_ValidateReportStructureAndAvailability() fakeReportService.Setup(x => x.Load("RecentPopularity.json")).Returns(Task.FromResult(fakePackageReport)); fakeReportService.Setup(x => x.Load("RecentPopularityDetail.json")).Returns(Task.FromResult(fakePackageVersionReport)); - var controller = new StatisticsController(new JsonStatisticsService(fakeReportService.Object)); + var controller = new StatisticsController(new JsonStatisticsService(fakeReportService.Object), null); var model = (StatisticsPackagesViewModel)((ViewResult) await controller.Index()).Model; @@ -55,7 +59,7 @@ public async void StatisticsHomePage_ValidateFullReportStructureAndAvailability( fakeReportService.Setup(x => x.Load("RecentPopularity.json")).Returns(Task.FromResult(fakePackageReport)); fakeReportService.Setup(x => x.Load("RecentPopularityDetail.json")).Returns(Task.FromResult(fakePackageVersionReport)); - var controller = new StatisticsController(new JsonStatisticsService(fakeReportService.Object)); + var controller = new StatisticsController(new JsonStatisticsService(fakeReportService.Object), null); var model = (StatisticsPackagesViewModel)((ViewResult) await controller.Index()).Model; @@ -105,7 +109,7 @@ public async void StatisticsHomePage_Packages_ValidateReportStructureAndAvailabi fakeReportService.Setup(x => x.Load("RecentPopularity.json")).Returns(Task.FromResult(fakePackageReport)); - var controller = new StatisticsController(new JsonStatisticsService(fakeReportService.Object)); + var controller = new StatisticsController(new JsonStatisticsService(fakeReportService.Object), null); var model = (StatisticsPackagesViewModel)((ViewResult) await controller.Packages()).Model; @@ -128,7 +132,7 @@ public async void StatisticsHomePage_PackageVersions_ValidateReportStructureAndA fakeReportService.Setup(x => x.Load("RecentPopularityDetail.json")).Returns(Task.FromResult(fakePackageVersionReport)); - var controller = new StatisticsController(new JsonStatisticsService(fakeReportService.Object)); + var controller = new StatisticsController(new JsonStatisticsService(fakeReportService.Object), null); var model = (StatisticsPackagesViewModel)((ViewResult) await controller.PackageVersions()).Model; @@ -153,7 +157,7 @@ public async void StatisticsHomePage_Per_Package_ValidateReportStructureAndAvail fakeReportService.Setup(x => x.Load("RecentPopularity_" + PackageId + ".json")).Returns(Task.FromResult(fakeReport)); - var controller = new StatisticsController(new JsonStatisticsService(fakeReportService.Object)); + var controller = new StatisticsController(new JsonStatisticsService(fakeReportService.Object), null); var model = (StatisticsPackagesViewModel)((ViewResult) await controller.PackageDownloadsByVersion(PackageId)).Model; @@ -177,7 +181,7 @@ public async void StatisticsHomePage_Packages_Negative_ValidateThrowOnInvalidStr fakeReportService.Setup(x => x.Load("RecentPopularity.json")).Returns(Task.FromResult(fakePackageReport)); - var controller = new StatisticsController(new JsonStatisticsService(fakeReportService.Object)); + var controller = new StatisticsController(new JsonStatisticsService(fakeReportService.Object), null); bool hasException = false; @@ -197,6 +201,90 @@ public async void StatisticsHomePage_Packages_Negative_ValidateThrowOnInvalidStr throw new Exception("this exception thrown because expected exception was not thrown"); } } + + public class TheStatsAction + { + [Fact] + public void UseServerCultureIfLanguageHeadersIsMissing() + { + // Arrange + var currentCulture = CultureInfo.CurrentCulture; + + try + { + Thread.CurrentThread.CurrentCulture = new CultureInfo("en-us"); + + var statsService = new Mock(MockBehavior.Strict); + var stats = new AggregateStats + { + Downloads = 2013, + TotalPackages = 1000, + UniquePackages = 500 + }; + statsService.Setup(s => s.GetAggregateStats()).Returns(stats); + + var controller = CreateController(statsService); + + // Act + var result = controller.Totals() as JsonResult; + + // Asssert + Assert.NotNull(result); + dynamic data = result.Data; + + Assert.Equal("2,013", (string)data.Downloads); + Assert.Equal("500", (string)data.UniquePackages); + Assert.Equal("1,000", (string)data.TotalPackages); + } + finally + { + Thread.CurrentThread.CurrentCulture = currentCulture; + } + } + + [Fact] + public void UseClientCultureIfLanguageHeadersIsPresent() + { + // Arrange + var statsService = new Mock(MockBehavior.Strict); + var stats = new AggregateStats + { + Downloads = 2013, + TotalPackages = 1000, + UniquePackages = 500 + }; + statsService.Setup(s => s.GetAggregateStats()).Returns(stats); + + var request = new Mock(); + request.Setup(r => r.UserLanguages).Returns(new string[] { "vi-VN" }); + + var controller = CreateController(statsService, request); + + // Act + var result = controller.Totals() as JsonResult; + + // Asssert + Assert.NotNull(result); + dynamic data = result.Data; + + Assert.Equal("2.013", (string)data.Downloads); + Assert.Equal("500", (string)data.UniquePackages); + Assert.Equal("1.000", (string)data.TotalPackages); + } + } + + public static StatisticsController CreateController(Mock statsService, Mock request = null) + { + request = request ?? new Mock(); + + var context = new Mock(); + context.SetupGet(s => s.Request).Returns(request.Object); + + var controller = new StatisticsController(null, statsService.Object); + controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller); + + return controller; + } } } diff --git a/Facts/Facts.csproj b/Facts/Facts.csproj index 01542e5cc4..4201402b88 100644 --- a/Facts/Facts.csproj +++ b/Facts/Facts.csproj @@ -153,7 +153,6 @@ - diff --git a/Website/App_Start/Routes.cs b/Website/App_Start/Routes.cs index 2b85ed246f..a43009c1fe 100644 --- a/Website/App_Start/Routes.cs +++ b/Website/App_Start/Routes.cs @@ -14,16 +14,16 @@ public static void RegisterRoutes(RouteCollection routes) "", MVC.Pages.Home()); - routes.MapRoute( - RouteName.Stats, - "stats/totals", - MVC.Pages.Stats()); - routes.MapRoute( RouteName.StatisticsHome, - "stats/home", + "stats", new { controller = MVC.Statistics.Name, action = "Index" }); + routes.MapRoute( + RouteName.Stats, + "stats/totals", + MVC.Statistics.Totals()); + routes.MapRoute( RouteName.StatisticsPackages, "stats/packages", diff --git a/Website/Controllers/PagesController.cs b/Website/Controllers/PagesController.cs index 5678aecb60..7010a78f57 100644 --- a/Website/Controllers/PagesController.cs +++ b/Website/Controllers/PagesController.cs @@ -6,11 +6,8 @@ namespace NuGetGallery { public partial class PagesController : Controller { - private readonly IAggregateStatsService _statsService; - - public PagesController(IAggregateStatsService statsService) + public PagesController() { - _statsService = statsService; } public virtual ActionResult Home() @@ -27,42 +24,5 @@ public virtual ActionResult Privacy() { return View(); } - - [HttpGet] - [OutputCache(VaryByParam = "None", Duration = 120, Location = OutputCacheLocation.Server)] - public virtual JsonResult Stats() - { - var stats = _statsService.GetAggregateStats(); - - // if we fail to detect client locale from the Languages header, fall back to server locale - CultureInfo clientCulture = DetermineClientLocale() ?? CultureInfo.CurrentCulture; - return Json( - new - { - Downloads = stats.Downloads.ToString("n0", clientCulture), - UniquePackages = stats.UniquePackages.ToString("n0", clientCulture), - TotalPackages = stats.TotalPackages.ToString("n0", clientCulture) - }, - JsonRequestBehavior.AllowGet); - } - - private CultureInfo DetermineClientLocale() - { - CultureInfo clientCulture = null; - - string[] languages = Request.UserLanguages; - if (languages != null && languages.Length > 0) - { - try - { - clientCulture = CultureInfo.GetCultureInfo(languages[0].ToLowerInvariant().Trim()); - } - catch (CultureNotFoundException) - { - } - } - - return clientCulture; - } } } \ No newline at end of file diff --git a/Website/Controllers/StatisticsController.cs b/Website/Controllers/StatisticsController.cs index a156108524..b8432ca562 100644 --- a/Website/Controllers/StatisticsController.cs +++ b/Website/Controllers/StatisticsController.cs @@ -1,22 +1,74 @@ -using System.Threading.Tasks; +using System.Globalization; +using System.Net; +using System.Threading.Tasks; using System.Web.Mvc; +using System.Web.UI; namespace NuGetGallery { public partial class StatisticsController : Controller { private readonly IStatisticsService _statisticsService; + private readonly IAggregateStatsService _aggregateStatsService; - public StatisticsController(IStatisticsService statisticsService) + public StatisticsController(IAggregateStatsService aggregateStatsService) + { + _aggregateStatsService = aggregateStatsService; + } + + public StatisticsController(IStatisticsService statisticsService, IAggregateStatsService aggregateStatsService) { _statisticsService = statisticsService; + _aggregateStatsService = aggregateStatsService; + } + + [HttpGet] + [OutputCache(VaryByParam = "None", Duration = 120, Location = OutputCacheLocation.Server)] + public virtual JsonResult Totals() + { + var stats = _aggregateStatsService.GetAggregateStats(); + + // if we fail to detect client locale from the Languages header, fall back to server locale + CultureInfo clientCulture = DetermineClientLocale() ?? CultureInfo.CurrentCulture; + return Json( + new + { + Downloads = stats.Downloads.ToString("n0", clientCulture), + UniquePackages = stats.UniquePackages.ToString("n0", clientCulture), + TotalPackages = stats.TotalPackages.ToString("n0", clientCulture) + }, + JsonRequestBehavior.AllowGet); + } + + private CultureInfo DetermineClientLocale() + { + CultureInfo clientCulture = null; + + string[] languages = Request.UserLanguages; + if (languages != null && languages.Length > 0) + { + try + { + clientCulture = CultureInfo.GetCultureInfo(languages[0].ToLowerInvariant().Trim()); + } + catch (CultureNotFoundException) + { + } + } + + return clientCulture; } // - // GET: /Statistics/ + // GET: /stats public virtual async Task Index() { + if (_statisticsService == null) + { + return new HttpStatusCodeResult(HttpStatusCode.NotFound); + } + bool[] availablity = await Task.WhenAll(_statisticsService.LoadDownloadPackages(), _statisticsService.LoadDownloadPackageVersions()); var model = new StatisticsPackagesViewModel @@ -31,10 +83,15 @@ public virtual async Task Index() } // - // GET: /statistics/packages + // GET: /stats/packages public virtual async Task Packages() { + if (_statisticsService == null) + { + return new HttpStatusCodeResult(HttpStatusCode.NotFound); + } + bool isAvailable = await _statisticsService.LoadDownloadPackages(); var model = new StatisticsPackagesViewModel @@ -47,10 +104,15 @@ public virtual async Task Packages() } // - // GET: /statistics/packageversions + // GET: /stats/packageversions public virtual async Task PackageVersions() { + if (_statisticsService == null) + { + return new HttpStatusCodeResult(HttpStatusCode.NotFound); + } + bool isAvailable = await _statisticsService.LoadDownloadPackageVersions(); var model = new StatisticsPackagesViewModel @@ -63,10 +125,15 @@ public virtual async Task PackageVersions() } // - // GET: /statistics/package/{id} + // GET: /stats/package/{id} public virtual async Task PackageDownloadsByVersion(string id) { + if (_statisticsService == null) + { + return new HttpStatusCodeResult(HttpStatusCode.NotFound); + } + await _statisticsService.LoadPackageDownloadsByVersion(id); var model = new StatisticsPackagesViewModel(); diff --git a/Website/PagesController.generated.cs b/Website/PagesController.generated.cs index 74728b78bb..87f0a9a663 100644 --- a/Website/PagesController.generated.cs +++ b/Website/PagesController.generated.cs @@ -47,7 +47,6 @@ public class ActionNamesClass { public readonly string Home = "Home"; public readonly string Terms = "Terms"; public readonly string Privacy = "Privacy"; - public readonly string Stats = "Stats"; } @@ -81,11 +80,6 @@ public class T4MVC_PagesController: NuGetGallery.PagesController { return callInfo; } - public override System.Web.Mvc.JsonResult Stats() { - var callInfo = new T4MVC_JsonResult(Area, Name, ActionNames.Stats); - return callInfo; - } - } } diff --git a/Website/Services/CloudReportService.cs b/Website/Services/CloudReportService.cs index 04fb16e58c..236c02f5dd 100644 --- a/Website/Services/CloudReportService.cs +++ b/Website/Services/CloudReportService.cs @@ -23,8 +23,6 @@ public async Task Load(string name) CloudBlobContainer container = blobClient.GetContainerReference("popularity"); CloudBlockBlob blob = container.GetBlockBlobReference(name); - //TODO: async OpenRead - MemoryStream stream = new MemoryStream(); await Task.Factory.FromAsync(blob.BeginDownloadToStream(stream, null, null), blob.EndDownloadToStream); diff --git a/Website/StatisticsController.generated.cs b/Website/StatisticsController.generated.cs index 55538f3f62..f59b6f8965 100644 --- a/Website/StatisticsController.generated.cs +++ b/Website/StatisticsController.generated.cs @@ -44,6 +44,7 @@ public partial class StatisticsController { public ActionNamesClass ActionNames { get { return s_actions; } } [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public class ActionNamesClass { + public readonly string Totals = "Totals"; } @@ -63,6 +64,11 @@ public class ViewNames { public class T4MVC_StatisticsController: NuGetGallery.StatisticsController { public T4MVC_StatisticsController() : base(Dummy.Instance) { } + public override System.Web.Mvc.JsonResult Totals() { + var callInfo = new T4MVC_JsonResult(Area, Name, ActionNames.Totals); + return callInfo; + } + } } diff --git a/Website/ViewModels/StatisticsPackagesViewModel.cs b/Website/ViewModels/StatisticsPackagesViewModel.cs index 089b097dd7..142520c3ff 100644 --- a/Website/ViewModels/StatisticsPackagesViewModel.cs +++ b/Website/ViewModels/StatisticsPackagesViewModel.cs @@ -39,28 +39,6 @@ public IEnumerable PackageDownloadsByVersion public string PackageId { get; private set; } public int TotalPackageDownloads { get; private set; } - //public async Task LoadDownloadPackages() - //{ - // IsDownloadPackageAvailable = await _statisticsService.LoadDownloadPackages(); - //} - - //public async Task LoadDownloadPackageVersions() - //{ - // IsDownloadPackageDetailAvailable = await _statisticsService.LoadDownloadPackageVersions(); - //} - - //public async Task LoadPackageDownloadsByVersion(string id) - //{ - // await _statisticsService.LoadPackageDownloadsByVersion(id); - // PackageId = id; - // TotalPackageDownloads = 0; - - // foreach (StatisticsPackagesItemViewModel item in PackageDownloadsByVersion) - // { - // TotalPackageDownloads += item.Downloads; - // } - //} - public void SetPackageDownloadsByVersion(string id, IEnumerable packageDownloadsByVersion) { PackageId = id;