diff --git a/NucuCar.Common/HttpClient.cs b/NucuCar.Common/HttpClient.cs
index b123951..1520c12 100644
--- a/NucuCar.Common/HttpClient.cs
+++ b/NucuCar.Common/HttpClient.cs
@@ -186,10 +186,12 @@ namespace NucuCar.Common
///
private sNetHttp.HttpRequestMessage _makeRequest(sNetHttp.HttpMethod method, string path)
{
+ var uri = _httpClient.BaseAddress == null ? new Uri(path) : new Uri(_httpClient.BaseAddress, path);
+
var requestMessage = new sNetHttp.HttpRequestMessage
{
Method = method,
- RequestUri = new Uri(_httpClient.BaseAddress, path)
+ RequestUri = uri
};
requestMessage.Headers.Authorization = _httpClient.DefaultRequestHeaders.Authorization;
diff --git a/NucuCar.Domain/Telemetry/TelemetryPublisher.cs b/NucuCar.Domain/Telemetry/TelemetryPublisher.cs
index 86f4644..0220e43 100644
--- a/NucuCar.Domain/Telemetry/TelemetryPublisher.cs
+++ b/NucuCar.Domain/Telemetry/TelemetryPublisher.cs
@@ -96,7 +96,7 @@ namespace NucuCar.Domain.Telemetry
/// It also adds metadata information such as: source and timestamp.
///
/// A dictionary containing all telemetry data.
- protected Dictionary GetTelemetry()
+ protected virtual Dictionary GetTelemetry()
{
var data = new List>();
foreach (var telemeter in RegisteredTelemeters)
diff --git a/NucuCar.Telemetry/TelemetryPublisherFirestore.cs b/NucuCar.Telemetry/TelemetryPublisherFirestore.cs
index 4b4e6c2..a981325 100644
--- a/NucuCar.Telemetry/TelemetryPublisherFirestore.cs
+++ b/NucuCar.Telemetry/TelemetryPublisherFirestore.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
@@ -26,7 +27,7 @@ namespace NucuCar.Telemetry
///
public class TelemetryPublisherFirestore : TelemetryPublisher
{
- private readonly HttpClient _httpClient;
+ protected HttpClient HttpClient;
private string _idToken;
@@ -44,6 +45,7 @@ namespace NucuCar.Telemetry
Logger?.LogCritical(
$"Can't start {nameof(TelemetryPublisherFirestore)}! Malformed connection string! " +
$"Missing ProjectId!");
+ throw new ArgumentException("Malformed connection string!");
}
if (!options.TryGetValue("CollectionName", out var firestoreCollection))
@@ -51,6 +53,7 @@ namespace NucuCar.Telemetry
Logger?.LogCritical(
$"Can't start {nameof(TelemetryPublisherFirestore)}! Malformed connection string! " +
$"Missing CollectionName!");
+ throw new ArgumentException("Malformed connection string!");
}
var timeout = int.Parse(options.GetValueOrDefault("Timeout", "10000") ?? "10000");
@@ -61,7 +64,7 @@ namespace NucuCar.Telemetry
// Setup HttpClient
var requestUrl = $"https://firestore.googleapis.com/v1/projects/{firestoreProjectId}/" +
$"databases/(default)/documents/{firestoreCollection}/";
- _httpClient = new HttpClient(requestUrl) {Timeout = timeout, Logger = Logger};
+ HttpClient = new HttpClient(requestUrl) {Timeout = timeout, Logger = Logger};
Logger?.LogInformation($"Initialized {nameof(TelemetryPublisherFirestore)}");
Logger?.LogInformation($"ProjectId: {firestoreProjectId}; CollectionName: {firestoreCollection}.");
}
@@ -77,13 +80,13 @@ namespace NucuCar.Telemetry
["returnSecureToken"] = true
};
- var response = await _httpClient.PostAsync(requestUrl, data);
+ var response = await HttpClient.PostAsync(requestUrl, data);
if (response?.StatusCode == HttpStatusCode.OK)
{
var jsonContent = await response.GetJson();
_idToken = jsonContent.GetProperty("idToken").ToString();
- _httpClient.Authorization(_idToken);
+ HttpClient.Authorization(_idToken);
}
else
{
@@ -100,7 +103,7 @@ namespace NucuCar.Telemetry
}
var data = FirebaseRestTranslator.Translator.Translate(null, GetTelemetry());
- var responseMessage = await _httpClient.PostAsync("", data);
+ var responseMessage = await HttpClient.PostAsync("", data);
switch (responseMessage?.StatusCode)
{
@@ -111,7 +114,7 @@ namespace NucuCar.Telemetry
{
Logger?.LogError($"Failed to publish telemetry data! {responseMessage.StatusCode}. Retrying...");
await SetupAuthorization();
- responseMessage = await _httpClient.PostAsync("", data);
+ responseMessage = await HttpClient.PostAsync("", data);
if (responseMessage != null && responseMessage.IsSuccessStatusCode)
{
Logger?.LogInformation("Published data to Firestore on retry!");
diff --git a/NucuCar.Domain/Telemetry/TelemetryPublisherType.cs b/NucuCar.Telemetry/TelemetryPublisherType.cs
similarity index 84%
rename from NucuCar.Domain/Telemetry/TelemetryPublisherType.cs
rename to NucuCar.Telemetry/TelemetryPublisherType.cs
index fdc8f52..a49a219 100644
--- a/NucuCar.Domain/Telemetry/TelemetryPublisherType.cs
+++ b/NucuCar.Telemetry/TelemetryPublisherType.cs
@@ -1,4 +1,6 @@
-namespace NucuCar.Domain.Telemetry
+using NucuCar.Domain.Telemetry;
+
+namespace NucuCar.Telemetry
{
///
/// TelemetryPublisherType holds constants for instantiating ,
diff --git a/NucuCar.UnitTests/NucuCar.Domain.Tests/Utilities/ConnectionStringParserTest.cs b/NucuCar.UnitTests/NucuCar.Common.Tests/ConnectionStringParserTest.cs
similarity index 94%
rename from NucuCar.UnitTests/NucuCar.Domain.Tests/Utilities/ConnectionStringParserTest.cs
rename to NucuCar.UnitTests/NucuCar.Common.Tests/ConnectionStringParserTest.cs
index 7858881..c614e4f 100644
--- a/NucuCar.UnitTests/NucuCar.Domain.Tests/Utilities/ConnectionStringParserTest.cs
+++ b/NucuCar.UnitTests/NucuCar.Common.Tests/ConnectionStringParserTest.cs
@@ -1,61 +1,61 @@
-using System;
-using System.Collections.Generic;
-using NucuCar.Common.Utilities;
-using Xunit;
-
-namespace NucuCar.UnitTests.NucuCar.Domain.Tests.Utilities
-{
- public class ConnectionStringParserTest
- {
- [Fact]
- private void Test_ConnectionStringParser_Valid()
- {
- const string connectionString = "Test=1;Test2=2";
- var parsedString = ConnectionStringParser.Parse(connectionString);
-
- Assert.Equal("1", parsedString.GetValueOrDefault("Test"));
- Assert.Equal("2", parsedString.GetValueOrDefault("Test2"));
- }
-
- [Fact]
- private void Test_ConnectionStringParser_EmptyValue()
- {
- const string connectionString = "Test=1;Test2=";
- var parsedString = ConnectionStringParser.Parse(connectionString);
-
- Assert.Equal("1", parsedString.GetValueOrDefault("Test"));
- Assert.Equal(string.Empty, parsedString.GetValueOrDefault("Test2"));
- }
-
- [Fact]
- private void Test_ConnectionStringParser_EmptyValue2()
- {
- Assert.Throws(() =>
- {
- ConnectionStringParser.Parse(string.Empty);
- });
- }
-
- [Fact]
- private void Test_ConnectionStringParser_Invalid()
- {
- const string connectionString = "Test=1;Test2=;d";
- Assert.Throws(() =>
- {
- ConnectionStringParser.Parse(connectionString);
- });
- }
-
- [Fact]
- private void Test_ConnectionStringParser_ValueWithMultipleEquals()
- {
- const string connectionString = "Test=1;Test2=base64=";
- var parsedString = ConnectionStringParser.Parse(connectionString);
-
- Assert.Equal("1", parsedString.GetValueOrDefault("Test"));
- Assert.Equal("base64=", parsedString.GetValueOrDefault("Test2"));
- }
-
-
- }
+using System;
+using System.Collections.Generic;
+using NucuCar.Common.Utilities;
+using Xunit;
+
+namespace NucuCar.UnitTests.NucuCar.Common.Tests
+{
+ public class ConnectionStringParserTest
+ {
+ [Fact]
+ private void Test_ConnectionStringParser_Valid()
+ {
+ const string connectionString = "Test=1;Test2=2";
+ var parsedString = ConnectionStringParser.Parse(connectionString);
+
+ Assert.Equal("1", parsedString.GetValueOrDefault("Test"));
+ Assert.Equal("2", parsedString.GetValueOrDefault("Test2"));
+ }
+
+ [Fact]
+ private void Test_ConnectionStringParser_EmptyValue()
+ {
+ const string connectionString = "Test=1;Test2=";
+ var parsedString = ConnectionStringParser.Parse(connectionString);
+
+ Assert.Equal("1", parsedString.GetValueOrDefault("Test"));
+ Assert.Equal(string.Empty, parsedString.GetValueOrDefault("Test2"));
+ }
+
+ [Fact]
+ private void Test_ConnectionStringParser_EmptyValue2()
+ {
+ Assert.Throws(() =>
+ {
+ ConnectionStringParser.Parse(string.Empty);
+ });
+ }
+
+ [Fact]
+ private void Test_ConnectionStringParser_Invalid()
+ {
+ const string connectionString = "Test=1;Test2=;d";
+ Assert.Throws(() =>
+ {
+ ConnectionStringParser.Parse(connectionString);
+ });
+ }
+
+ [Fact]
+ private void Test_ConnectionStringParser_ValueWithMultipleEquals()
+ {
+ const string connectionString = "Test=1;Test2=base64=";
+ var parsedString = ConnectionStringParser.Parse(connectionString);
+
+ Assert.Equal("1", parsedString.GetValueOrDefault("Test"));
+ Assert.Equal("base64=", parsedString.GetValueOrDefault("Test2"));
+ }
+
+
+ }
}
\ No newline at end of file
diff --git a/NucuCar.UnitTests/NucuCar.Domain.Tests/Telemetry/TelemetryPublisherFirestoreTest.cs b/NucuCar.UnitTests/NucuCar.Domain.Tests/Telemetry/TelemetryPublisherFirestoreTest.cs
deleted file mode 100644
index ef69901..0000000
--- a/NucuCar.UnitTests/NucuCar.Domain.Tests/Telemetry/TelemetryPublisherFirestoreTest.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace NucuCar.UnitTests.NucuCar.Domain.Tests.Telemetry
-{
- public class TelemetryPublisherFirestoreTest
- {
- // TODO after refactoring
- }
-}
\ No newline at end of file
diff --git a/NucuCar.UnitTests/NucuCar.Domain.Tests/Telemetry/TelemetryPublisherFactoryTest.cs b/NucuCar.UnitTests/NucuCar.Telemetry.Tests/TelemetryPublisherFactoryTest.cs
similarity index 71%
rename from NucuCar.UnitTests/NucuCar.Domain.Tests/Telemetry/TelemetryPublisherFactoryTest.cs
rename to NucuCar.UnitTests/NucuCar.Telemetry.Tests/TelemetryPublisherFactoryTest.cs
index 17afc64..572f2b4 100644
--- a/NucuCar.UnitTests/NucuCar.Domain.Tests/Telemetry/TelemetryPublisherFactoryTest.cs
+++ b/NucuCar.UnitTests/NucuCar.Telemetry.Tests/TelemetryPublisherFactoryTest.cs
@@ -1,9 +1,8 @@
using System;
-using NucuCar.Domain.Telemetry;
using NucuCar.Telemetry;
using Xunit;
-namespace NucuCar.UnitTests.NucuCar.Domain.Tests.Telemetry
+namespace NucuCar.UnitTests.NucuCar.Telemetry.Tests
{
public class TelemetryPublisherFactoryTest
{
@@ -26,6 +25,16 @@ namespace NucuCar.UnitTests.NucuCar.Domain.Tests.Telemetry
TelemetryPublisherFactory.CreateFromConnectionString(TelemetryPublisherType.Disk, connectionString);
Assert.IsType(telemetryPublisher);
}
+
+ [Fact]
+ private void Test_Build_TelemetryPublisherFiresstore()
+ {
+ const string connectionString =
+ "ProjectId=test;CollectionName=test";
+ var telemetryPublisher =
+ TelemetryPublisherFactory.CreateFromConnectionString(TelemetryPublisherType.Firestore, connectionString);
+ Assert.IsType(telemetryPublisher);
+ }
[Fact]
private void Test_Build_ThrowsOnInvalidType()
diff --git a/NucuCar.UnitTests/NucuCar.Telemetry.Tests/TelemetryPublisherFirestoreTest.cs b/NucuCar.UnitTests/NucuCar.Telemetry.Tests/TelemetryPublisherFirestoreTest.cs
new file mode 100644
index 0000000..784187b
--- /dev/null
+++ b/NucuCar.UnitTests/NucuCar.Telemetry.Tests/TelemetryPublisherFirestoreTest.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Moq;
+using NucuCar.Domain.Telemetry;
+using NucuCar.Telemetry;
+using Xunit;
+using HttpClient = NucuCar.Common.HttpClient;
+
+namespace NucuCar.UnitTests.NucuCar.Telemetry.Tests
+{
+ ///
+ /// Class used to test the TelemetryPublisherFirestore by mocking the GetTelemetry method and HttpClient field.
+ ///
+ internal class MockTelemetryPublisherFirestore : TelemetryPublisherFirestore
+ {
+ private Dictionary _mockData;
+
+ public MockTelemetryPublisherFirestore(TelemetryPublisherBuilderOptions opts) : base(opts)
+ {
+ _mockData = new Dictionary();
+ }
+
+ public void SetHttpClient(HttpClient client)
+ {
+ HttpClient = client;
+ }
+
+ public void SetMockData(Dictionary data)
+ {
+ _mockData = data;
+ }
+
+ protected override Dictionary GetTelemetry()
+ {
+ return _mockData;
+ }
+ }
+
+ public class TelemetryPublisherFirestoreTest
+ {
+ [Fact]
+ private void Test_Construct_BadProjectId()
+ {
+ // Setup
+ var opts = new TelemetryPublisherBuilderOptions()
+ {
+ ConnectionString = "ProjectIdBAD=test;CollectionName=test"
+ };
+
+ // Run & Assert
+ Assert.Throws(() => { new MockTelemetryPublisherFirestore(opts); });
+ }
+
+ [Fact]
+ private void Test_Construct_BadCollectiontName()
+ {
+ // Setup
+ var opts = new TelemetryPublisherBuilderOptions()
+ {
+ ConnectionString = "ProjectId=test;CollectionNameBAD=test"
+ };
+
+ // Run & Assert
+ Assert.Throws(() => { new MockTelemetryPublisherFirestore(opts); });
+ }
+
+ [Fact]
+ private async Task Test_PublishAsync_OK()
+ {
+ // Setup
+ var opts = new TelemetryPublisherBuilderOptions()
+ {
+ ConnectionString = "ProjectId=test;CollectionName=test"
+ };
+ var publisher = new MockTelemetryPublisherFirestore(opts);
+ var mockHttpClient = new Mock("http://testing.com");
+ mockHttpClient.Setup(c => c.SendAsync(It.IsAny()))
+ .Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)));
+
+ publisher.SetHttpClient(mockHttpClient.Object);
+ publisher.SetMockData(new Dictionary {["testData"] = 1});
+
+ // Run
+ await publisher.PublishAsync(CancellationToken.None);
+
+ // Assert
+ var expectedContent = "{\"fields\":{\"testData\":{\"integerValue\":1}}}";
+ mockHttpClient.Verify(
+ m => m.SendAsync(
+ It.Is(
+ request => request.Method.Equals(HttpMethod.Post))));
+ mockHttpClient.Verify(
+ m => m.SendAsync(
+ It.Is(
+ request => request.RequestUri.Equals(new Uri("http://testing.com")))));
+ mockHttpClient.Verify(
+ m => m.SendAsync(
+ It.Is(
+ request => request.Content.ReadAsStringAsync().GetAwaiter().GetResult()
+ .Equals(expectedContent))));
+ }
+
+ [Fact]
+ private async Task Test_PublishAsync_Cancel()
+ {
+ // Setup
+ var opts = new TelemetryPublisherBuilderOptions()
+ {
+ ConnectionString = "ProjectId=test;CollectionName=test"
+ };
+ var publisher = new MockTelemetryPublisherFirestore(opts);
+ var mockHttpClient = new Mock("http://testing.com");
+ mockHttpClient.Setup(c => c.SendAsync(It.IsAny()))
+ .Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)));
+
+ publisher.SetHttpClient(mockHttpClient.Object);
+ publisher.SetMockData(new Dictionary {["testData"] = 1});
+ var cts = new CancellationTokenSource();
+ cts.Cancel();
+
+ // Run
+ await publisher.PublishAsync(cts.Token);
+
+ // Assert
+ mockHttpClient.Verify(m => m.SendAsync(It.IsAny()), Times.Never());
+ }
+
+ [Fact]
+ private async Task Test_PublishAsync_Authorization_OK()
+ {
+ // Setup
+ var sendAsyncInvocations = new List();
+
+ var opts = new TelemetryPublisherBuilderOptions()
+ {
+ ConnectionString = "ProjectId=test;CollectionName=test"
+ };
+ var publisher = new MockTelemetryPublisherFirestore(opts);
+ var mockHttpClient = new Mock("http://testing.com");
+ mockHttpClient.SetupSequence(c => c.SendAsync(It.IsAny()))
+ .Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.Forbidden)))
+ .Returns(Task.FromResult(
+ new HttpResponseMessage(HttpStatusCode.OK)
+ {Content = new StringContent("{\"idToken\":\"testauthtoken\"}")}
+ ))
+ .Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)));
+
+
+ publisher.SetHttpClient(mockHttpClient.Object);
+ publisher.SetMockData(new Dictionary {["testData"] = 1});
+
+ // Run
+ await publisher.PublishAsync(CancellationToken.None);
+
+ // Assert
+ // Can't verify because moq doesn't support that, damn C#.
+ }
+ }
+}
\ No newline at end of file
diff --git a/NucuCar.sln.DotSettings.user b/NucuCar.sln.DotSettings.user
index a20925d..f13c6ee 100644
--- a/NucuCar.sln.DotSettings.user
+++ b/NucuCar.sln.DotSettings.user
@@ -2,4 +2,44 @@
<AssemblyExplorer>
<Assembly Path="/home/denis/.nuget/packages/iot.device.bindings/1.0.0/lib/netcoreapp2.1/Iot.Device.Bindings.dll" />
<Assembly Path="/home/denis/.nuget/packages/firebaseresttranslator/0.1.1/lib/netcoreapp3.0/FirebaseRestTranslator.dll" />
-</AssemblyExplorer>
\ No newline at end of file
+</AssemblyExplorer>
+ <SessionState ContinuousTestingIsOn="False" ContinuousTestingMode="0" FrameworkVersion="{x:Null}" IsLocked="False" Name="Test_PublishAsync_Authorization_OK" PlatformMonoPreference="{x:Null}" PlatformType="{x:Null}" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+ <TestAncestor>
+ <TestId>xUnit::C6F07921-1052-4945-911E-F328A622F229::.NETCoreApp,Version=v3.0::NucuCar.UnitTests.NucuCar.Telemetry.Tests.TelemetryPublisherFirestoreTest.Test_PublishAsync_Authorization_OK</TestId>
+ </TestAncestor>
+</SessionState>
+ <SessionState ContinuousTestingIsOn="False" ContinuousTestingMode="0" FrameworkVersion="{x:Null}" IsLocked="False" Name="Session" PlatformMonoPreference="{x:Null}" PlatformType="{x:Null}" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+ <Or>
+ <Or>
+ <Or>
+ <Or>
+ <Or>
+ <Or>
+ <TestAncestor>
+ <TestId>xUnit::C6F07921-1052-4945-911E-F328A622F229::.NETCoreApp,Version=v3.0::NucuCar.UnitTests.NucuCar.Telemetry.Tests.TelemetryPublisherFirestoreTest.Test_PublishAsync_OK</TestId>
+ </TestAncestor>
+ <TestAncestor>
+ <TestId>xUnit::C6F07921-1052-4945-911E-F328A622F229::.NETCoreApp,Version=v3.0::NucuCar.UnitTests.NucuCar.Telemetry.Tests.TelemetryPublisherFirestoreTest.Test_PublishAsync_BadProjectId</TestId>
+ </TestAncestor>
+ </Or>
+ <TestAncestor>
+ <TestId>xUnit::C6F07921-1052-4945-911E-F328A622F229::.NETCoreApp,Version=v3.0::NucuCar.UnitTests.NucuCar.Telemetry.Tests.TelemetryPublisherFirestoreTest.Test_PublishAsync_CollectiontName</TestId>
+ </TestAncestor>
+ </Or>
+ <TestAncestor>
+ <TestId>xUnit::C6F07921-1052-4945-911E-F328A622F229::.NETCoreApp,Version=v3.0::NucuCar.UnitTests.NucuCar.Telemetry.Tests.TelemetryPublisherFirestoreTest.Test_PublishAsync_Error_Timeout</TestId>
+ </TestAncestor>
+ </Or>
+ <TestAncestor>
+ <TestId>xUnit::C6F07921-1052-4945-911E-F328A622F229::.NETCoreApp,Version=v3.0::NucuCar.UnitTests.NucuCar.Telemetry.Tests.TelemetryPublisherFirestoreTest.Test_PublishAsync_Cancel</TestId>
+ </TestAncestor>
+ </Or>
+ <TestAncestor>
+ <TestId>xUnit::C6F07921-1052-4945-911E-F328A622F229::.NETCoreApp,Version=v3.0::NucuCar.UnitTests.NucuCar.Telemetry.Tests.TelemetryPublisherFirestoreTest.Test_PublishAsync_UnknownError</TestId>
+ </TestAncestor>
+ </Or>
+ <TestAncestor>
+ <TestId>xUnit::C6F07921-1052-4945-911E-F328A622F229::.NETCoreApp,Version=v3.0::NucuCar.UnitTests.NucuCar.Telemetry.Tests.TelemetryPublisherFirestoreTest.Test_PublishAsync_AuthorizationFail</TestId>
+ </TestAncestor>
+ </Or>
+</SessionState>
\ No newline at end of file