Skip to content

Commit

Permalink
adds TogglProxy business logic tests using Moq to mock togglapi
Browse files Browse the repository at this point in the history
  • Loading branch information
Toumash committed Feb 11, 2020
1 parent 4829149 commit 5df0577
Show file tree
Hide file tree
Showing 14 changed files with 355 additions and 44 deletions.
1 change: 1 addition & 0 deletions DailyStatus.Common/DailyStatus.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
<Compile Include="Exceptions\OfflineException.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Exceptions\TogglApiException.cs" />
<Compile Include="Services\ITogglReportApi.cs" />
<Compile Include="Services\TogglProxy.cs" />
<Compile Include="Services\TogglReportApi.cs" />
<Compile Include="Model\TogglStatus.cs" />
Expand Down
11 changes: 11 additions & 0 deletions DailyStatus.Common/Services/ITogglReportApi.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using System.Threading.Tasks;

namespace DailyStatus.Common.Services
{
public interface ITogglReportApi
{
Task<TimeSpan> GetHoursSum(DateTime since, DateTime until, long userId, long workspaceId);
Task<long> GetUserId();
}
}
78 changes: 45 additions & 33 deletions DailyStatus.Common/Services/TogglProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,24 @@
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Toggl.Multivac.Models;
using Toggl.Ultrawave;
using Toggl.Ultrawave.Network;

namespace DailyStatus.Common.Services
{
public partial class TogglProxy
public class TogglProxy
{
ITogglApi _togglApi;
Workspace _workspace;
List<Workspace> _workspaces;
private TogglReportApi _togglReportApi;
private ITogglReportApi _togglReportApi;

public TogglProxy(ITogglReportApi togglReportApi, ITogglApi api)
{
_togglReportApi = togglReportApi;
_togglApi = api;
}

public void SetWorkspace(Workspace workspace)
{
Expand All @@ -25,6 +32,7 @@ public void SetWorkspace(Workspace workspace)
else
throw new ArgumentException("given workspace does not exist on current toggl account");
}

public async Task<Workspace> GetWorkspace()
{
if (_workspace == null)
Expand All @@ -42,6 +50,32 @@ public TimeSpan GetExpectedWorkingTime(WorkDay dayConfig, DateTime since, List<D
dayConfig.NumberOfWorkingHoursPerDay, holidays);
}

public static TogglProxy Create(string apiToken)
{
return new TogglProxy(new TogglReportApi(apiToken), TogglApiWith(Credentials.WithApiToken(apiToken)));
}

public static bool TestApiToken(string apiToken)
{
try
{
var user = TogglApiWith(Credentials.WithApiToken(apiToken)).User.Get().GetAwaiter().Wait();
return true;
}
catch (Toggl.Ultrawave.Exceptions.UnauthorizedException)
{
return false;
}
catch (Toggl.Ultrawave.Exceptions.OfflineException)
{
return false;
}
catch (Toggl.Ultrawave.Exceptions.BadRequestException)
{
return false;
}
}

public TimeSpan GetDifference(TimeSpan expected, TimeSpan sum)
{
var diff = sum - expected;
Expand All @@ -58,11 +92,7 @@ public async Task<TogglStatus> GetStatus(DateTime since)
var sum = await _togglReportApi.GetHoursSum(since, DateTime.Now.Date.AddDays(-1), userId, workspace.Id);


var todayEntries = await _togglApi.TimeEntries.GetAllSince(DateTime.Now.Date)
.SelectMany(e => e)
.Where(e => !e.ServerDeletedAt.HasValue)
.Where(e => e.WorkspaceId == workspace.Id)
.ToList();
var todayEntries = await GetTodayEntries(workspace);

var currentTaskElement = todayEntries
.FirstOrDefault(e => !e.Duration.HasValue);
Expand Down Expand Up @@ -99,39 +129,21 @@ public async Task<TogglStatus> GetStatus(DateTime since)
}
}

public bool TestConnection()
public IObservable<IList<ITimeEntry>> GetTodayEntries(Workspace workspace)
{
try
{
var user = _togglApi.User.Get().GetAwaiter().Wait();
return true;
}
catch (Toggl.Ultrawave.Exceptions.UnauthorizedException)
{
return false;
}
catch (Toggl.Ultrawave.Exceptions.OfflineException)
{
return false;
}
catch (Toggl.Ultrawave.Exceptions.BadRequestException)
{
return false;
}
return _togglApi.TimeEntries.GetAllSince(DateTime.Now.Date)
.SelectMany(e => e)
.Where(e => !e.ServerDeletedAt.HasValue)
.Where(e => e.WorkspaceId == workspace.Id)
.ToList();
}

public ITogglApi TogglApiWith(Credentials credentials)
public static ITogglApi TogglApiWith(Credentials credentials)
=> new TogglApi(ConfigurationFor(credentials));

public ApiConfiguration ConfigurationFor(Credentials credentials)
public static ApiConfiguration ConfigurationFor(Credentials credentials)
=> new ApiConfiguration(ApiEnvironment.Production, credentials, new UserAgent("toumash.dailystatus", "1"));

public void Configure(string key)
{
_togglReportApi = new TogglReportApi(key);
var credentials = Credentials.WithApiToken(key);
_togglApi = TogglApiWith(credentials);
}

public async Task<List<Workspace>> GetAllWorkspaces()
{
Expand Down
2 changes: 1 addition & 1 deletion DailyStatus.Common/Services/TogglReportApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace DailyStatus.Common.Services
{
public class TogglReportApi
public class TogglReportApi : ITogglReportApi
{
private readonly string apiToken;

Expand Down
35 changes: 35 additions & 0 deletions DailyStatus.CommonTests/DailyStatus.CommonTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,52 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="FluentAssertions, Version=5.10.2.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.5.10.2\lib\net45\FluentAssertions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.1.2.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.1.2.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
</Reference>
<Reference Include="Moq, Version=4.13.0.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<HintPath>..\packages\Moq.4.13.1\lib\net45\Moq.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Reactive, Version=4.3.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reactive.4.3.2\lib\net46\System.Reactive.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Windows" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="Toggl.Multivac, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Reference Include="Toggl.Ultrawave, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\dlls\Toggl.Ultrawave.dll</HintPath>
</Reference>
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="ExpectedTimeCalculatorTests.cs" />
<Compile Include="TogglProxyTests.cs" />
<Compile Include="TogglReportApiTests.cs" />
<Compile Include="BusinessDaysCalculatorTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
70 changes: 70 additions & 0 deletions DailyStatus.CommonTests/TogglProxyTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using DailyStatus.Common.Services;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using Toggl.Multivac.Models;
using Toggl.Ultrawave;

namespace DailyStatus.CommonTests
{
[TestClass()]
public class TogglProxyTests
{
[TestMethod]
public async Task Given3hYesterdayAnd5hToday_WhenGettingStatus_ShouldIncludeTodayHours()
{
const int HoursWithoutToday = 3;
const int HoursToday = 5;

const long WorkSpaceId = -1L;
var yesterdayEntry = new Mock<ITimeEntry>();
yesterdayEntry.Setup(e => e.ServerDeletedAt).Returns(() => null);
yesterdayEntry.Setup(e => e.WorkspaceId).Returns(() => WorkSpaceId);
yesterdayEntry.Setup(e => e.Duration).Returns(() => (long)TimeSpan.FromHours(HoursToday).TotalSeconds);
yesterdayEntry.Setup(e => e.Start).Returns(() => DateTime.Today.AddHours(1));

var observable = Observable.Create<List<ITimeEntry>>((obs) =>
{
obs.OnNext(new List<ITimeEntry>() { yesterdayEntry.Object });
obs.OnCompleted();
return () => { };
});

var togglMock = new Mock<ITogglApi>();
togglMock.Setup(t => t.TimeEntries.GetAllSince(It.IsAny<DateTimeOffset>()))
.Returns(observable);

var workspaceMock = new Mock<IWorkspace>();
workspaceMock.Setup(w => w.Name).Returns("test");
workspaceMock.Setup(w => w.Id).Returns(WorkSpaceId);

var observableWorkspace = Observable.Create<List<IWorkspace>>((obs) =>
{
obs.OnNext(new List<IWorkspace>() { workspaceMock.Object });
obs.OnCompleted();
return () => { };
});

togglMock.Setup(t => t.Workspaces.GetAll())
.Returns(observableWorkspace);

var reportMock = new Mock<ITogglReportApi>();
reportMock.Setup(r => r.GetUserId()).Returns(Task.FromResult(-1L));
reportMock.Setup(r => r.GetHoursSum(It.IsAny<DateTime>(), It.IsAny<DateTime>(),
It.IsAny<long>(), It.IsAny<long>()))
.Returns(Task.FromResult(TimeSpan.FromHours(HoursWithoutToday)));


var sut = new TogglProxy(reportMock.Object, togglMock.Object);
var status = await sut.GetStatus(new DateTime(2020, 02, 04));
status.TodaysHours.Should().Be(TimeSpan.FromHours(HoursToday));
status.TimeInMonth.Should().BeGreaterThan(TimeSpan.FromHours(HoursToday));
}
}
}
8 changes: 8 additions & 0 deletions DailyStatus.CommonTests/app.config
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
7 changes: 7 additions & 0 deletions DailyStatus.CommonTests/packages.config
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Castle.Core" version="4.4.0" targetFramework="net461" />
<package id="FluentAssertions" version="5.10.2" targetFramework="net461" />
<package id="Moq" version="4.13.1" targetFramework="net461" />
<package id="MSTest.TestAdapter" version="1.2.0" targetFramework="net461" />
<package id="MSTest.TestFramework" version="1.2.0" targetFramework="net461" />
<package id="System.Reactive" version="4.3.2" targetFramework="net461" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net461" />
<package id="System.Threading.Tasks.Extensions" version="4.5.3" targetFramework="net461" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net461" />
</packages>
Loading

0 comments on commit 5df0577

Please sign in to comment.