Skip to content

Commit

Permalink
Improve tests stability (#16)
Browse files Browse the repository at this point in the history
* Improve tests stability
  • Loading branch information
olsh authored Oct 10, 2022
1 parent 6325d33 commit 7e3d3b8
Show file tree
Hide file tree
Showing 31 changed files with 308 additions and 99 deletions.
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
root = true

[*]
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

[{*.csproj,*.json,*.config}]
indent_size = 2

[*.cs]
dotnet_separate_import_directive_groups = true
dotnet_sort_system_directives_first = true
6 changes: 3 additions & 3 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
version: 1.0.{build}
image: Visual Studio 2019
image: Visual Studio 2022
install:
- dotnet tool install -g Cake.Tool --version 1.3.0
- SET JAVA_HOME=C:\Program Files\Java\jdk11
- dotnet tool install -g Cake.Tool --version 2.2.0
- SET JAVA_HOME=C:\Program Files\Java\jdk17
- SET PATH=%JAVA_HOME%\bin;%PATH%
build_script:
- cmd: dotnet cake --Target=CI
Expand Down
24 changes: 13 additions & 11 deletions build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#addin nuget:?package=Cake.Codecov&version=1.0.1

#tool nuget:?package=MSBuild.SonarQube.Runner.Tool&version=4.8.0
#addin nuget:?package=Cake.Sonar&version=1.1.25
#addin nuget:?package=Cake.Sonar&version=1.1.30

var target = Argument("target", "Default");

Expand All @@ -28,55 +28,57 @@ Task("UpdateBuildVersion")
Task("Build")
.Does(() =>
{
var settings = new DotNetCoreBuildSettings
var settings = new DotNetBuildSettings
{
Configuration = buildConfiguration
};

DotNetCoreBuild(string.Format("{0}.sln", projectName), settings);
DotNetBuild(string.Format("{0}.sln", projectName), settings);
});

Task("Test")
.IsDependentOn("Build")
.Does(() =>
{
var settings = new DotNetCoreTestSettings
var settings = new DotNetTestSettings
{
Configuration = buildConfiguration
Configuration = buildConfiguration,
Loggers = new List<string> { "console;verbosity=detailed" }
};

DotNetCoreTest(testProjectFile, settings);
DotNetTest(testProjectFile, settings);
});

Task("CodeCoverage")
.IsDependentOn("Build")
.Does(() =>
{
var settings = new DotNetCoreTestSettings
var settings = new DotNetTestSettings
{
Configuration = buildConfiguration,
Loggers = new List<string> { "console;verbosity=detailed" },
ArgumentCustomization = args => args
.Append("/p:CollectCoverage=true")
.Append("/p:CoverletOutputFormat=opencover")
.Append("/p:Include=\"[Todoist.Net]*\"")
};

DotNetCoreTest(testProjectFile, settings);
DotNetTest(testProjectFile, settings);

Codecov(string.Format("{0}coverage.netcoreapp3.1.opencover.xml", testProjectFolder), EnvironmentVariable("codecov:token"));
Codecov(string.Format("{0}coverage.net6.0.opencover.xml", testProjectFolder), EnvironmentVariable("codecov:token"));
});

Task("NugetPack")
.IsDependentOn("Build")
.Does(() =>
{
var settings = new DotNetCorePackSettings
var settings = new DotNetPackSettings
{
Configuration = buildConfiguration,
OutputDirectory = "."
};

DotNetCorePack(projectFolder, settings);
DotNetPack(projectFolder, settings);
});

Task("CreateArtifact")
Expand Down
6 changes: 6 additions & 0 deletions src/Todoist.Net.Tests/Extensions/Constants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Todoist.Net.Tests.Extensions;

internal static class Constants
{
public const string TodoistApiTestCollectionName = "todoist-api-tests";
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Xunit.Sdk;
using Xunit.Sdk;

namespace Todoist.Net.Tests.Extensions
{
Expand Down
3 changes: 2 additions & 1 deletion src/Todoist.Net.Tests/Models/DueDateTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;

using Todoist.Net.Models;

using Todoist.Net.Tests.Extensions;
using Xunit;

namespace Todoist.Net.Tests.Models
{
[Unit]
public class DueDateTests
{
[Fact]
Expand Down
41 changes: 35 additions & 6 deletions src/Todoist.Net.Tests/RateLimitAwareRestClient.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
using System;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

using Xunit.Abstractions;

namespace Todoist.Net.Tests
{
public sealed class RateLimitAwareRestClient : ITodoistRestClient
{
private readonly ITestOutputHelper _outputHelper;

private readonly TodoistRestClient restClient;

public RateLimitAwareRestClient()
public RateLimitAwareRestClient(ITestOutputHelper outputHelper)
{
_outputHelper = outputHelper;
restClient = new TodoistRestClient();
}

Expand All @@ -25,21 +32,21 @@ public async Task<HttpResponseMessage> ExecuteRequest(Func<Task<HttpResponseMess

// For each user, you can make a maximum of 450 requests within a 15 minute period.
const int maxRetryCount = 35;
const int delaySeconds = 30;

int retryCount = 0;
do
{
result = await request().ConfigureAwait(false);

if ((int)result.StatusCode != 429 /*Requests limit*/ &&
(int)result.StatusCode < 500 /*Server side errors happen randomly*/)
{
return result;
}

await Task.Delay(TimeSpan.FromSeconds(delaySeconds));
var cooldown = await GetRateLimitCooldown(result).ConfigureAwait(false);
retryCount++;

_outputHelper.WriteLine("[{0:G}] Received [{1}] status code from Todoist API, retry #{2} in {3}", DateTime.UtcNow, result.StatusCode, retryCount, cooldown);
await Task.Delay(cooldown);
}
while (retryCount < maxRetryCount);

Expand All @@ -61,5 +68,27 @@ public async Task<HttpResponseMessage> PostFormAsync(
return await ExecuteRequest(() => restClient.PostFormAsync(resource, parameters, files))
.ConfigureAwait(false);
}

public async Task<TimeSpan> GetRateLimitCooldown(HttpResponseMessage response)
{
var defaultCooldown = TimeSpan.FromSeconds(30);
if (response.StatusCode == HttpStatusCode.TooManyRequests)
{
try
{
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
JObject json = JObject.Parse(content);

return TimeSpan.FromSeconds(json["error_extra"]["retry_after"].Value<double>());
}
catch
{
return defaultCooldown;
}
}

// Default cooldown
return defaultCooldown;
}
}
}
15 changes: 11 additions & 4 deletions src/Todoist.Net.Tests/Services/ActivityServiceTests.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
using System.Linq;

using Todoist.Net.Models;
using Todoist.Net.Tests.Extensions;

using Xunit;
using Xunit.Abstractions;

namespace Todoist.Net.Tests.Services
{
[Collection(Constants.TodoistApiTestCollectionName)]
[IntegrationPremium]
public class ActivityServiceTests
{
private readonly ITestOutputHelper _outputHelper;

public ActivityServiceTests(ITestOutputHelper outputHelper)
{
_outputHelper = outputHelper;
}

[Fact]
public void GetActivity_HasEntries()
{
var client = TodoistClientFactory.Create();
var client = TodoistClientFactory.Create(_outputHelper);

var logEntries = client.Activity.GetAsync(new LogFilter() { Limit = 50 }).Result.Events;

Expand All @@ -23,7 +30,7 @@ public void GetActivity_HasEntries()
[Fact]
public void GetActivityWithEventObjectFilter_HasEntries()
{
var client = TodoistClientFactory.Create();
var client = TodoistClientFactory.Create(_outputHelper);

var logFilter = new LogFilter();
logFilter.ObjectEventTypes.Add(new ObjectEventTypes() { ObjectType = "project" });
Expand Down
14 changes: 11 additions & 3 deletions src/Todoist.Net.Tests/Services/BackupServiceTests.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
using System.Linq;
using System.Linq;
using Todoist.Net.Tests.Extensions;
using Todoist.Net.Tests.Settings;

using Xunit;
using Xunit.Abstractions;

namespace Todoist.Net.Tests.Services
{
[Collection(Constants.TodoistApiTestCollectionName)]
public class BackupServiceTests
{
private readonly ITestOutputHelper _outputHelper;

public BackupServiceTests(ITestOutputHelper outputHelper)
{
_outputHelper = outputHelper;
}

[Fact]
[IntegrationFree]
public void GetBackups_Success()
{
var client = TodoistClientFactory.Create();
var client = TodoistClientFactory.Create(_outputHelper);

var backups = client.Backups.GetAsync().Result;

Expand Down
13 changes: 11 additions & 2 deletions src/Todoist.Net.Tests/Services/EmailServiceTests.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
using System;
using System;

using Todoist.Net.Models;
using Todoist.Net.Tests.Extensions;

using Xunit;
using Xunit.Abstractions;

namespace Todoist.Net.Tests.Services
{
[Collection(Constants.TodoistApiTestCollectionName)]
public class EmailServiceTests
{
private readonly ITestOutputHelper _outputHelper;

public EmailServiceTests(ITestOutputHelper outputHelper)
{
_outputHelper = outputHelper;
}

[Fact]
[IntegrationPremium]
public void GetOrCreateAsyncDisable_NewProject_Success()
{
var client = TodoistClientFactory.Create();
var client = TodoistClientFactory.Create(_outputHelper);

var projectId = client.Projects.AddAsync(new Project(Guid.NewGuid().ToString())).Result;
var emailInfo = client.Emails.GetOrCreateAsync(ObjectType.Project, projectId).Result;
Expand Down
15 changes: 12 additions & 3 deletions src/Todoist.Net.Tests/Services/FiltersServiceTests.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
using System;
using System;
using System.Linq;

using Todoist.Net.Models;
using Todoist.Net.Tests.Extensions;

using Xunit;
using Xunit.Abstractions;

namespace Todoist.Net.Tests.Services
{
[Collection(Constants.TodoistApiTestCollectionName)]
[IntegrationPremium]
public class FiltersServiceTests
{
private readonly ITestOutputHelper _outputHelper;

public FiltersServiceTests(ITestOutputHelper outputHelper)
{
_outputHelper = outputHelper;
}

[Fact]
public void GetFilterInfo_Success()
{
var client = TodoistClientFactory.Create();
var client = TodoistClientFactory.Create(_outputHelper);

var filters = client.Filters.GetAsync().Result;

Expand All @@ -28,7 +37,7 @@ public void GetFilterInfo_Success()
[Fact]
public void CreateUpdateDelete_Success()
{
var client = TodoistClientFactory.Create();
var client = TodoistClientFactory.Create(_outputHelper);

var filter = new Filter(Guid.NewGuid().ToString(), "today");
client.Filters.AddAsync(filter).Wait();
Expand Down
Loading

0 comments on commit 7e3d3b8

Please sign in to comment.