Browse Source

Tags icon and fixes in usage tracking.

pull/335/head
Sebastian Stehle 8 years ago
parent
commit
a3f17dc7b0
  1. 2
      src/Squidex.Domain.Apps.Entities/Assets/AssetUsageTracker.cs
  2. 22
      src/Squidex.Infrastructure/UsageTracking/BackgroundUsageTracker.cs
  3. 20
      src/Squidex.Infrastructure/UsageTracking/CachingUsageTracker.cs
  4. 6
      src/Squidex.Infrastructure/UsageTracking/IUsageTracker.cs
  5. 4
      src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs
  6. 4
      src/Squidex/Pipeline/ApiCostsFilter.cs
  7. 2
      src/Squidex/app/features/schemas/pages/schema/types/tags-ui.component.html
  8. 18
      src/Squidex/app/theme/icomoon/demo.html
  9. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.eot
  10. 1
      src/Squidex/app/theme/icomoon/fonts/icomoon.svg
  11. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.ttf
  12. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.woff
  13. 2
      src/Squidex/app/theme/icomoon/selection.json
  14. 13
      src/Squidex/app/theme/icomoon/style.css
  15. 52
      tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs
  16. 18
      tests/Squidex.Infrastructure.Tests/UsageTracking/CachingUsageTrackerTests.cs
  17. 12
      tests/Squidex.Tests/Pipeline/ApiCostsFilterTests.cs

2
src/Squidex.Domain.Apps.Entities/Assets/AssetUsageTracker.cs

@ -45,7 +45,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
{
var enriched = new List<AssetStats>();
var usagesFlat = await usageStore.QueryAsync(appId.ToString(), fromDate, toDate);
var usagesFlat = await usageStore.QueryAsync(GetKey(appId), fromDate, toDate);
for (var date = fromDate; date <= toDate; date = date.AddDays(1))
{

22
src/Squidex.Infrastructure/UsageTracking/BackgroundUsageTracker.cs

@ -96,9 +96,9 @@ namespace Squidex.Infrastructure.UsageTracking
}
}
public Task TrackAsync(Guid appId, string category, double weight, double elapsedMs)
public Task TrackAsync(string key, string category, double weight, double elapsedMs)
{
var key = GetKey(appId);
key = GetKey(key);
ThrowIfDisposed();
@ -112,11 +112,11 @@ namespace Squidex.Infrastructure.UsageTracking
return TaskHelper.Done;
}
public async Task<IReadOnlyDictionary<string, IReadOnlyList<DateUsage>>> QueryAsync(Guid appId, DateTime fromDate, DateTime toDate)
public async Task<IReadOnlyDictionary<string, IReadOnlyList<DateUsage>>> QueryAsync(string key, DateTime fromDate, DateTime toDate)
{
ThrowIfDisposed();
key = GetKey(key);
var key = GetKey(appId);
ThrowIfDisposed();
var usagesFlat = await usageRepository.QueryAsync(key, fromDate, toDate);
var usagesByCategory = usagesFlat.GroupBy(x => GetCategory(x.Category)).ToDictionary(x => x.Key, x => x.ToList());
@ -167,11 +167,11 @@ namespace Squidex.Infrastructure.UsageTracking
return result;
}
public async Task<long> GetMonthlyCallsAsync(Guid appId, DateTime date)
public async Task<long> GetMonthlyCallsAsync(string key, DateTime date)
{
ThrowIfDisposed();
key = GetKey(key);
var key = GetKey(appId);
ThrowIfDisposed();
var dateFrom = new DateTime(date.Year, date.Month, 1);
var dateTo = dateFrom.AddMonths(1).AddDays(-1);
@ -186,9 +186,11 @@ namespace Squidex.Infrastructure.UsageTracking
return !string.IsNullOrWhiteSpace(category) ? category.Trim() : "*";
}
private static string GetKey(Guid appId)
private static string GetKey(string key)
{
return $"{appId}_API";
Guard.NotNull(key, nameof(key));
return $"{key}_API";
}
}
}

20
src/Squidex.Infrastructure/UsageTracking/CachingUsageTracker.cs

@ -25,25 +25,31 @@ namespace Squidex.Infrastructure.UsageTracking
this.inner = inner;
}
public Task<IReadOnlyDictionary<string, IReadOnlyList<DateUsage>>> QueryAsync(Guid appId, DateTime fromDate, DateTime toDate)
public Task<IReadOnlyDictionary<string, IReadOnlyList<DateUsage>>> QueryAsync(string key, DateTime fromDate, DateTime toDate)
{
return inner.QueryAsync(appId, fromDate, toDate);
Guard.NotNull(key, nameof(key));
return inner.QueryAsync(key, fromDate, toDate);
}
public Task TrackAsync(Guid appId, string category, double weight, double elapsedMs)
public Task TrackAsync(string key, string category, double weight, double elapsedMs)
{
return inner.TrackAsync(appId, category, weight, elapsedMs);
Guard.NotNull(key, nameof(key));
return inner.TrackAsync(key, category, weight, elapsedMs);
}
public Task<long> GetMonthlyCallsAsync(Guid appId, DateTime date)
public Task<long> GetMonthlyCallsAsync(string key, DateTime date)
{
var cacheKey = string.Concat(appId, date);
Guard.NotNull(key, nameof(key));
var cacheKey = string.Concat(key, date);
return Cache.GetOrCreateAsync(cacheKey, entry =>
{
entry.AbsoluteExpirationRelativeToNow = CacheDuration;
return inner.GetMonthlyCallsAsync(appId, date);
return inner.GetMonthlyCallsAsync(key, date);
});
}
}

6
src/Squidex.Infrastructure/UsageTracking/IUsageTracker.cs

@ -13,10 +13,10 @@ namespace Squidex.Infrastructure.UsageTracking
{
public interface IUsageTracker
{
Task TrackAsync(Guid appId, string category, double weight, double elapsedMs);
Task TrackAsync(string key, string category, double weight, double elapsedMs);
Task<long> GetMonthlyCallsAsync(Guid appId, DateTime date);
Task<long> GetMonthlyCallsAsync(string key, DateTime date);
Task<IReadOnlyDictionary<string, IReadOnlyList<DateUsage>>> QueryAsync(Guid appId, DateTime fromDate, DateTime toDate);
Task<IReadOnlyDictionary<string, IReadOnlyList<DateUsage>>> QueryAsync(string key, DateTime fromDate, DateTime toDate);
}
}

4
src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs

@ -58,7 +58,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics
[ApiCosts(0)]
public async Task<IActionResult> GetMonthlyCalls(string app)
{
var count = await usageTracker.GetMonthlyCallsAsync(AppId, DateTime.Today);
var count = await usageTracker.GetMonthlyCallsAsync(AppId.ToString(), DateTime.Today);
var plan = appPlanProvider.GetPlanForApp(App);
@ -90,7 +90,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics
return BadRequest();
}
var entities = await usageTracker.QueryAsync(AppId, fromDate.Date, toDate.Date);
var entities = await usageTracker.QueryAsync(AppId.ToString(), fromDate.Date, toDate.Date);
var response = entities.ToDictionary(x => x.Key, x => x.Value.Select(CallsUsageDto.FromUsage).ToList());

4
src/Squidex/Pipeline/ApiCostsFilter.cs

@ -53,7 +53,7 @@ namespace Squidex.Pipeline
{
var plan = appPlanProvider.GetPlanForApp(appFeature.App);
var usage = await usageTracker.GetMonthlyCallsAsync(appFeature.App.Id, DateTime.Today);
var usage = await usageTracker.GetMonthlyCallsAsync(appFeature.App.Id.ToString(), DateTime.Today);
if (plan.MaxApiCalls >= 0 && usage > plan.MaxApiCalls * 1.1)
{
@ -72,7 +72,7 @@ namespace Squidex.Pipeline
{
var elapsedMs = watch.Stop();
await usageTracker.TrackAsync(appFeature.App.Id, context.HttpContext.User.OpenIdClientId(), FilterDefinition.Weight, elapsedMs);
await usageTracker.TrackAsync(appFeature.App.Id.ToString(), context.HttpContext.User.OpenIdClientId(), FilterDefinition.Weight, elapsedMs);
}
}
else

2
src/Squidex/app/features/schemas/pages/schema/types/tags-ui.component.html

@ -28,7 +28,7 @@
<label class="btn btn-radio" [class.active]="editForm.controls['editor'].value === 'Tags'">
<input type="radio" class="radio-input" formControlName="editor" value="Tags" />
<i class="icon-control-Input"></i>
<i class="icon-control-Tags"></i>
<span class="radio-label">Tags</span>
</label>

18
src/Squidex/app/theme/icomoon/demo.html

@ -9,7 +9,7 @@
<link rel="stylesheet" href="style.css"></head>
<body>
<div class="bgc1 clearfix">
<h1 class="mhmm mvm"><span class="fgc1">Font Name:</span> icomoon <small class="fgc1">(Glyphs:&nbsp;102)</small></h1>
<h1 class="mhmm mvm"><span class="fgc1">Font Name:</span> icomoon <small class="fgc1">(Glyphs:&nbsp;103)</small></h1>
</div>
<div class="clearfix mhl ptl">
<h1 class="mvm mtn fgc1">Grid Size: 24</h1>
@ -1372,6 +1372,22 @@
</div>
<div class="clearfix mhl ptl">
<h1 class="mvm mtn fgc1">Grid Size: 14</h1>
<div class="glyph fs6">
<div class="clearfix bshadow0 pbs">
<span class="icon-control-Tags">
</span>
<span class="mls"> icon-control-Tags</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e963" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe963;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
<div class="glyph fs6">
<div class="clearfix bshadow0 pbs">
<span class="icon-control-Checkboxes">

BIN
src/Squidex/app/theme/icomoon/fonts/icomoon.eot

Binary file not shown.

1
src/Squidex/app/theme/icomoon/fonts/icomoon.svg

@ -106,6 +106,7 @@
<glyph unicode="&#xe960;" glyph-name="control-Html" d="M159.073 285.257l-159.073 134.055 159.073 133.819 36.818-37.29-117.062-96.057 117.062-97.237zM493.247 414.828q0-33.042-9.441-57.115-9.205-24.073-25.961-40.122-16.521-15.813-39.178-23.601-22.657-7.552-49.327-7.552-26.197 0-48.855 4.012-22.421 3.776-42.954 10.385v323.338h57.587v-78.356l-2.36-47.203q12.981 16.757 30.21 26.905 17.465 10.149 41.774 10.149 21.241 0 37.762-8.496t27.614-24.309q11.329-15.577 17.229-37.998 5.9-22.185 5.9-50.035zM432.828 412.468q0 19.825-2.832 33.75t-8.26 22.893q-5.192 8.969-12.981 12.981-7.552 4.248-17.465 4.248-14.633 0-28.086-11.801-13.217-11.801-28.086-32.098v-104.79q6.844-2.596 16.757-4.248 10.149-1.652 20.533-1.652 13.689 0 24.781 5.664 11.329 5.664 19.117 16.049 8.024 10.385 12.273 25.253 4.248 15.105 4.248 33.75zM700.682 437.249q0.472 13.453-1.416 22.893-1.652 9.441-5.664 15.577-3.776 6.136-9.441 8.968t-12.981 2.832q-12.745 0-26.433-10.621-13.453-10.385-29.738-34.458v-151.756h-59.003v239.789h52.159l2.124-34.93q5.9 9.205 13.217 16.521 7.552 7.316 16.521 12.509 9.205 5.428 20.297 8.26t24.309 2.832q18.173 0 32.098-6.372 14.161-6.136 23.601-18.409 9.677-12.273 14.161-30.918 4.72-18.409 4.012-42.718zM864.927 553.132l159.073-133.819-159.073-134.055-36.582 37.29 116.826 96.293-116.826 97.001z" />
<glyph unicode="&#xe961;" glyph-name="drag2" d="M170 298.667v86h684v-86h-684zM854 554.667v-86h-684v86h684z" />
<glyph unicode="&#xe962;" glyph-name="control-Checkboxes" d="M384 771.657h614.4c14.157 0 25.6 11.443 25.6 25.6s-11.443 25.6-25.6 25.6h-614.4c-14.131 0-25.6-11.443-25.6-25.6s11.469-25.6 25.6-25.6zM998.4 464.457h-614.4c-14.131 0-25.6-11.443-25.6-25.6s11.469-25.6 25.6-25.6h614.4c14.157 0 25.6 11.443 25.6 25.6s-11.443 25.6-25.6 25.6zM998.4 106.057h-614.4c-38.406-15.539-22.811-37.543 0-51.2h614.4c14.157 0 25.6 11.443 25.6 25.6s-11.443 25.6-25.6 25.6zM0 950.857v-307.2h307.2v307.2zM47.4 903.457h212.4v-212.4h-212.4zM0 234.057v-307.2h307.2v307.2zM47.4 186.657h212.4v-212.4h-212.4zM0 592.457v-307.2h307.2v307.2zM47.4 545.057h212.4v-212.4h-212.4zM89.6 861.257h128v-128h-128v128z" />
<glyph unicode="&#xe963;" glyph-name="control-Tags" horiz-adv-x="1140" d="M498.787 620.534v49.548h112.31v66.065c0 49.548-39.639 89.187-89.187 89.187s-89.187-39.639-89.187-89.187v-541.729l89.187-161.858 89.187 161.858v426.116zM360.052 234.057h-66.065c-59.458 0-105.703 46.245-105.703 105.703v254.348c0 59.458 46.245 105.703 105.703 105.703h66.065v42.942h-66.065c-82.581 0-148.645-66.065-148.645-148.645v-254.348c0-82.581 66.065-148.645 148.645-148.645h66.065zM852.232 689.902c-26.426 33.032-66.065 52.852-109.006 52.852h-59.458v-42.942h39.639c42.942 0 82.581-19.819 109.006-52.852l145.342-181.677-142.039-178.374c-26.426-33.032-69.368-52.852-112.31-52.852h-36.335v-42.942h56.155c42.942 0 85.884 19.819 112.31 52.852l178.374 221.316z" />
<glyph unicode="&#xe9ca;" glyph-name="earth" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512-0.002c-62.958 0-122.872 13.012-177.23 36.452l233.148 262.29c5.206 5.858 8.082 13.422 8.082 21.26v96c0 17.674-14.326 32-32 32-112.99 0-232.204 117.462-233.374 118.626-6 6.002-14.14 9.374-22.626 9.374h-128c-17.672 0-32-14.328-32-32v-192c0-12.122 6.848-23.202 17.69-28.622l110.31-55.156v-187.886c-116.052 80.956-192 215.432-192 367.664 0 68.714 15.49 133.806 43.138 192h116.862c8.488 0 16.626 3.372 22.628 9.372l128 128c6 6.002 9.372 14.14 9.372 22.628v77.412c40.562 12.074 83.518 18.588 128 18.588 70.406 0 137.004-16.26 196.282-45.2-4.144-3.502-8.176-7.164-12.046-11.036-36.266-36.264-56.236-84.478-56.236-135.764s19.97-99.5 56.236-135.764c36.434-36.432 85.218-56.264 135.634-56.26 3.166 0 6.342 0.080 9.518 0.236 13.814-51.802 38.752-186.656-8.404-372.334-0.444-1.744-0.696-3.488-0.842-5.224-81.324-83.080-194.7-134.656-320.142-134.656z" />
<glyph unicode="&#xf00a;" glyph-name="grid" d="M292.571 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM292.571 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM292.571 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857z" />
<glyph unicode="&#xf0c9;" glyph-name="list1" horiz-adv-x="878" d="M877.714 182.857v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571zM877.714 475.428v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571zM877.714 768v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571z" />

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 82 KiB

BIN
src/Squidex/app/theme/icomoon/fonts/icomoon.ttf

Binary file not shown.

BIN
src/Squidex/app/theme/icomoon/fonts/icomoon.woff

Binary file not shown.

2
src/Squidex/app/theme/icomoon/selection.json

File diff suppressed because one or more lines are too long

13
src/Squidex/app/theme/icomoon/style.css

@ -1,10 +1,10 @@
@font-face {
font-family: 'icomoon';
src: url('fonts/icomoon.eot?l0yskd');
src: url('fonts/icomoon.eot?l0yskd#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?l0yskd') format('truetype'),
url('fonts/icomoon.woff?l0yskd') format('woff'),
url('fonts/icomoon.svg?l0yskd#icomoon') format('svg');
src: url('fonts/icomoon.eot?2tmnw3');
src: url('fonts/icomoon.eot?2tmnw3#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?2tmnw3') format('truetype'),
url('fonts/icomoon.woff?2tmnw3') format('woff'),
url('fonts/icomoon.svg?2tmnw3#icomoon') format('svg');
font-weight: normal;
font-style: normal;
}
@ -276,6 +276,9 @@
.icon-user:before {
content: "\e928";
}
.icon-control-Tags:before {
content: "\e963";
}
.icon-control-Checkboxes:before {
content: "\e962";
}

52
tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs

@ -19,7 +19,7 @@ namespace Squidex.Infrastructure.UsageTracking
{
private readonly IUsageRepository usageStore = A.Fake<IUsageRepository>();
private readonly ISemanticLog log = A.Fake<ISemanticLog>();
private readonly Guid appId = Guid.NewGuid();
private readonly string key = Guid.NewGuid().ToString();
private readonly BackgroundUsageTracker sut;
public BackgroundUsageTrackerTests()
@ -32,7 +32,7 @@ namespace Squidex.Infrastructure.UsageTracking
{
sut.Dispose();
return Assert.ThrowsAsync<ObjectDisposedException>(() => sut.TrackAsync(appId, "category1", 1, 1000));
return Assert.ThrowsAsync<ObjectDisposedException>(() => sut.TrackAsync(key, "category1", 1, 1000));
}
[Fact]
@ -40,7 +40,7 @@ namespace Squidex.Infrastructure.UsageTracking
{
sut.Dispose();
return Assert.ThrowsAsync<ObjectDisposedException>(() => sut.QueryAsync(appId, DateTime.Today, DateTime.Today.AddDays(1)));
return Assert.ThrowsAsync<ObjectDisposedException>(() => sut.QueryAsync(key, DateTime.Today, DateTime.Today.AddDays(1)));
}
[Fact]
@ -48,7 +48,7 @@ namespace Squidex.Infrastructure.UsageTracking
{
sut.Dispose();
return Assert.ThrowsAsync<ObjectDisposedException>(() => sut.GetMonthlyCallsAsync(appId, DateTime.Today));
return Assert.ThrowsAsync<ObjectDisposedException>(() => sut.GetMonthlyCallsAsync(key, DateTime.Today));
}
[Fact]
@ -64,10 +64,10 @@ namespace Squidex.Infrastructure.UsageTracking
new StoredUsage("category1", date.AddDays(7), Counters(17, 22))
};
A.CallTo(() => usageStore.QueryAsync($"{appId}_API", new DateTime(2016, 1, 1), new DateTime(2016, 1, 31)))
A.CallTo(() => usageStore.QueryAsync($"{key}_API", new DateTime(2016, 1, 1), new DateTime(2016, 1, 31)))
.Returns(originalData);
var result = await sut.GetMonthlyCallsAsync(appId, date);
var result = await sut.GetMonthlyCallsAsync(key, date);
Assert.Equal(55, result);
}
@ -87,10 +87,10 @@ namespace Squidex.Infrastructure.UsageTracking
new StoredUsage(null, f.AddDays(2), Counters(11, 14))
};
A.CallTo(() => usageStore.QueryAsync($"{appId}_API", f, t))
A.CallTo(() => usageStore.QueryAsync($"{key}_API", f, t))
.Returns(originalData);
var result = await sut.QueryAsync(appId, f, t);
var result = await sut.QueryAsync(key, f, t);
var expected = new Dictionary<string, List<DateUsage>>
{
@ -121,10 +121,10 @@ namespace Squidex.Infrastructure.UsageTracking
var f = DateTime.Today;
var t = DateTime.Today.AddDays(4);
A.CallTo(() => usageStore.QueryAsync($"{appId}_API", f, t))
A.CallTo(() => usageStore.QueryAsync($"{key}_API", f, t))
.Returns(new List<StoredUsage>());
var result = await sut.QueryAsync(appId, f, t);
var result = await sut.QueryAsync(key, f, t);
var expected = new Dictionary<string, List<DateUsage>>
{
@ -144,8 +144,8 @@ namespace Squidex.Infrastructure.UsageTracking
[Fact]
public async Task Should_not_track_if_weight_less_than_zero()
{
await sut.TrackAsync(appId, "MyCategory", -1, 1000);
await sut.TrackAsync(appId, "MyCategory", 0, 1000);
await sut.TrackAsync(key, "MyCategory", -1, 1000);
await sut.TrackAsync(key, "MyCategory", 0, 1000);
sut.Next();
sut.Dispose();
@ -157,22 +157,22 @@ namespace Squidex.Infrastructure.UsageTracking
[Fact]
public async Task Should_aggregate_and_store_on_dispose()
{
var appId1 = Guid.NewGuid();
var appId2 = Guid.NewGuid();
var appId3 = Guid.NewGuid();
var key1 = Guid.NewGuid().ToString();
var key2 = Guid.NewGuid().ToString();
var key3 = Guid.NewGuid().ToString();
var today = DateTime.Today;
await sut.TrackAsync(appId1, "MyCategory1", 1, 1000);
await sut.TrackAsync(key1, "MyCategory1", 1, 1000);
await sut.TrackAsync(appId2, "MyCategory1", 1.0, 2000);
await sut.TrackAsync(appId2, "MyCategory1", 0.5, 3000);
await sut.TrackAsync(key2, "MyCategory1", 1.0, 2000);
await sut.TrackAsync(key2, "MyCategory1", 0.5, 3000);
await sut.TrackAsync(appId3, "MyCategory1", 0.3, 4000);
await sut.TrackAsync(appId3, "MyCategory1", 0.1, 5000);
await sut.TrackAsync(key3, "MyCategory1", 0.3, 4000);
await sut.TrackAsync(key3, "MyCategory1", 0.1, 5000);
await sut.TrackAsync(appId3, null, 0.5, 2000);
await sut.TrackAsync(appId3, null, 0.5, 6000);
await sut.TrackAsync(key3, null, 0.5, 2000);
await sut.TrackAsync(key3, null, 0.5, 6000);
UsageUpdate[] updates = null;
@ -184,10 +184,10 @@ namespace Squidex.Infrastructure.UsageTracking
updates.Should().BeEquivalentTo(new[]
{
new UsageUpdate(today, $"{appId1}_API", "MyCategory1", Counters(1.0, 1000)),
new UsageUpdate(today, $"{appId2}_API", "MyCategory1", Counters(1.5, 5000)),
new UsageUpdate(today, $"{appId3}_API", "MyCategory1", Counters(0.4, 9000)),
new UsageUpdate(today, $"{appId3}_API", "*", Counters(1, 8000))
new UsageUpdate(today, $"{key1}_API", "MyCategory1", Counters(1.0, 1000)),
new UsageUpdate(today, $"{key2}_API", "MyCategory1", Counters(1.5, 5000)),
new UsageUpdate(today, $"{key3}_API", "MyCategory1", Counters(0.4, 9000)),
new UsageUpdate(today, $"{key3}_API", "*", Counters(1, 8000))
}, o => o.ComparingByMembers<UsageUpdate>());
A.CallTo(() => usageStore.TrackUsagesAsync(A<UsageUpdate[]>.Ignored))

18
tests/Squidex.Infrastructure.Tests/UsageTracking/CachingUsageTrackerTests.cs

@ -17,7 +17,7 @@ namespace Squidex.Infrastructure.UsageTracking
public class CachingUsageTrackerTests
{
private readonly MemoryCache cache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
private readonly Guid appId = Guid.NewGuid();
private readonly string key = Guid.NewGuid().ToString();
private readonly IUsageTracker inner = A.Fake<IUsageTracker>();
private readonly IUsageTracker sut;
@ -29,34 +29,34 @@ namespace Squidex.Infrastructure.UsageTracking
[Fact]
public async Task Should_forward_track_call()
{
await sut.TrackAsync(appId, "MyCategory", 123, 456);
await sut.TrackAsync(key, "MyCategory", 123, 456);
A.CallTo(() => inner.TrackAsync(appId, "MyCategory", 123, 456))
A.CallTo(() => inner.TrackAsync(key, "MyCategory", 123, 456))
.MustHaveHappened();
}
[Fact]
public async Task Should_forward_query_call()
{
await sut.QueryAsync(appId, DateTime.MaxValue, DateTime.MinValue);
await sut.QueryAsync(key, DateTime.MaxValue, DateTime.MinValue);
A.CallTo(() => inner.QueryAsync(appId, DateTime.MaxValue, DateTime.MinValue))
A.CallTo(() => inner.QueryAsync(key, DateTime.MaxValue, DateTime.MinValue))
.MustHaveHappened();
}
[Fact]
public async Task Should_cache_monthly_usage()
{
A.CallTo(() => inner.GetMonthlyCallsAsync(appId, DateTime.Today))
A.CallTo(() => inner.GetMonthlyCallsAsync(key, DateTime.Today))
.Returns(100);
var result1 = await sut.GetMonthlyCallsAsync(appId, DateTime.Today);
var result2 = await sut.GetMonthlyCallsAsync(appId, DateTime.Today);
var result1 = await sut.GetMonthlyCallsAsync(key, DateTime.Today);
var result2 = await sut.GetMonthlyCallsAsync(key, DateTime.Today);
Assert.Equal(100, result1);
Assert.Equal(100, result2);
A.CallTo(() => inner.GetMonthlyCallsAsync(appId, DateTime.Today))
A.CallTo(() => inner.GetMonthlyCallsAsync(key, DateTime.Today))
.MustHaveHappened(Repeated.Exactly.Once);
}
}

12
tests/Squidex.Tests/Pipeline/ApiCostsFilterTests.cs

@ -57,7 +57,7 @@ namespace Squidex.Pipeline
A.CallTo(() => appPlan.MaxApiCalls)
.ReturnsLazily(x => apiCallsMax);
A.CallTo(() => usageTracker.GetMonthlyCallsAsync(A<Guid>.Ignored, DateTime.Today))
A.CallTo(() => usageTracker.GetMonthlyCallsAsync(A<string>.Ignored, DateTime.Today))
.ReturnsLazily(x => Task.FromResult(apiCallsCurrent));
next = () =>
@ -85,7 +85,7 @@ namespace Squidex.Pipeline
Assert.Equal(429, (actionContext.Result as StatusCodeResult).StatusCode);
Assert.False(isNextCalled);
A.CallTo(() => usageTracker.TrackAsync(A<Guid>.Ignored, A<string>.Ignored, A<double>.Ignored, A<double>.Ignored))
A.CallTo(() => usageTracker.TrackAsync(A<string>.Ignored, A<string>.Ignored, A<double>.Ignored, A<double>.Ignored))
.MustNotHaveHappened();
}
@ -103,7 +103,7 @@ namespace Squidex.Pipeline
Assert.True(isNextCalled);
A.CallTo(() => usageTracker.TrackAsync(A<Guid>.Ignored, A<string>.Ignored, 13, A<double>.Ignored))
A.CallTo(() => usageTracker.TrackAsync(A<string>.Ignored, A<string>.Ignored, 13, A<double>.Ignored))
.MustHaveHappened();
}
@ -121,7 +121,7 @@ namespace Squidex.Pipeline
Assert.True(isNextCalled);
A.CallTo(() => usageTracker.TrackAsync(A<Guid>.Ignored, A<string>.Ignored, 13, A<double>.Ignored))
A.CallTo(() => usageTracker.TrackAsync(A<string>.Ignored, A<string>.Ignored, 13, A<double>.Ignored))
.MustHaveHappened();
}
@ -139,7 +139,7 @@ namespace Squidex.Pipeline
Assert.True(isNextCalled);
A.CallTo(() => usageTracker.TrackAsync(A<Guid>.Ignored, A<string>.Ignored, A<double>.Ignored, A<double>.Ignored))
A.CallTo(() => usageTracker.TrackAsync(A<string>.Ignored, A<string>.Ignored, A<double>.Ignored, A<double>.Ignored))
.MustNotHaveHappened();
}
@ -155,7 +155,7 @@ namespace Squidex.Pipeline
Assert.True(isNextCalled);
A.CallTo(() => usageTracker.TrackAsync(A<Guid>.Ignored, A<string>.Ignored, A<double>.Ignored, A<double>.Ignored))
A.CallTo(() => usageTracker.TrackAsync(A<string>.Ignored, A<string>.Ignored, A<double>.Ignored, A<double>.Ignored))
.MustNotHaveHappened();
}

Loading…
Cancel
Save