Skip to content
This repository has been archived by the owner on Oct 11, 2023. It is now read-only.

Commit

Permalink
Performance improvements (#223)
Browse files Browse the repository at this point in the history
* Refactor code writing twin tags for better performance
* Refactor device properties code for better performance
* Refactor simulation runner for better performance
* Improve connections performance
* Reduce time to start simulation, by creating devices using the same conn string and fetching device from registry only if the authentication fails.
* Limit the number of pending threads attempting to deliver telemetry
* Change all stock device models to use AMQP
* Move SDK timeout setting and other hard coded magic numbers to config file
* Use default timeout value from SDK instead of hardcoding it
* Improve documentation in the configuration file
* Upgrade IoT SDK
* Improve logging in device client
* Reduce noise in the "Info" log level
* When building, remove "deleted files" left over from previous builds
* Improve error detection when creating devices with batch operations
* Recreate device client when the internal AMQP client is disposed (lib bug workaround)
* VS code config update
* Remove simulation version, not used anywhere
* Catch and log when a device model doesn't exist
* Log missing config settings
* Make sure the simulation object is not lost in case of errors while checking for simulation changes
* Limit async tests duration
* Remove IoT hub registry workaround
* Fix boolean conf values parsing
* Remove "en-us" from links in the comments
* Fix invalid parsing of environment variables
  • Loading branch information
dluc authored Jul 17, 2018
1 parent 876cb34 commit 6f0d073
Show file tree
Hide file tree
Showing 94 changed files with 1,957 additions and 846 deletions.
9 changes: 8 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@
"PCS_STORAGEADAPTER_WEBSERVICE_URL": "http://localhost:9022/v1",
// Optional Settings. For additonal optional settings, refer to appsettings.ini directly.
"PCS_LOG_LEVEL": "Debug",
"PCS_AUTH_REQUIRED": "false"
"PCS_AUTH_REQUIRED": "false",
"PCS_AUTH_ISSUER": "",
"PCS_AUTH_AUDIENCE": "",
"PCS_CORS_WHITELIST": "",
"PCS_SUBSCRIPTION_DOMAIN": "",
"PCS_SUBSCRIPTION_ID": "",
"PCS_RESOURCE_GROUP": "",
"PCS_IOHUB_NAME": ""
},
"stopAtEntry": false,
"justMyCode":false,
Expand Down
4 changes: 4 additions & 0 deletions Services.Test/Concurrency/PerSecondCounterTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ public void FourThreadsTenPerSecondAreThrottledTogether()
{
// wait until the next second
}

var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
thread1.Start();
thread2.Start();
Expand Down Expand Up @@ -323,6 +324,7 @@ public void FourThreadsTwentyPerSecondAreThrottledTogether()
{
// wait until the next second
}

var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
thread1.Start();
thread2.Start();
Expand Down Expand Up @@ -368,6 +370,7 @@ public void ItSupportLongPeriodsWithoutEvents()
{
target.IncreaseAsync(CancellationToken.None).Wait(Constants.TEST_TIMEOUT);
}

var t2 = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

Thread.Sleep(5001);
Expand All @@ -377,6 +380,7 @@ public void ItSupportLongPeriodsWithoutEvents()
{
target.IncreaseAsync(CancellationToken.None).Wait(Constants.TEST_TIMEOUT);
}

var t4 = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

// Assert
Expand Down
1 change: 0 additions & 1 deletion Services.Test/CustomDeviceModelsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using Newtonsoft.Json;
using Services.Test.helpers;
using Xunit;
using Xunit.Abstractions;

namespace Services.Test
{
Expand Down
58 changes: 58 additions & 0 deletions Services.Test/DeviceClientTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) Microsoft. All rights reserved.

using Microsoft.Azure.Devices.Client.Exceptions;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Exceptions;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.IotHub;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models;
using Moq;
using Services.Test.helpers;
using Xunit;

namespace Services.Test
{
public class DeviceClientTest
{
private readonly DeviceClient target;
private readonly Mock<IDeviceClientWrapper> client;
private readonly Mock<IDeviceMethods> deviceMethods;
private readonly Mock<ILogger> log;

public DeviceClientTest()
{
this.client = new Mock<IDeviceClientWrapper>();
this.deviceMethods = new Mock<IDeviceMethods>();
this.log = new Mock<ILogger>();

this.target = new DeviceClient(
"x",
IoTHubProtocol.AMQP,
this.client.Object,
this.deviceMethods.Object,
this.log.Object);
}

[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
public void ConnectsToIoTHub()
{
// Act (connect twice, the second call should be ignored)
this.target.ConnectAsync().Wait(Constants.TEST_TIMEOUT);
this.target.ConnectAsync().Wait(Constants.TEST_TIMEOUT);

// Assert
this.client.Verify(x=>x.OpenAsync(), Times.Once);
}

[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
public void AuthFailureOnConnectRaiseException()
{
// Arrange
this.client.Setup(x => x.OpenAsync()).Throws(new UnauthorizedException(""));

// Act + Assert
Assert.ThrowsAsync<DeviceAuthFailedException>(
async () => await this.target.ConnectAsync()).Wait(Constants.TEST_TIMEOUT);
}
}
}
34 changes: 9 additions & 25 deletions Services.Test/DevicePropertiesRequestTest.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
// Copyright (c) Microsoft. All rights reserved.

using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.Azure.Devices.Client;
using Microsoft.Azure.Devices.Shared;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.IotHub;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models;
using Moq;
using Services.Test.helpers;
Expand All @@ -24,20 +22,16 @@ public class DevicePropertiesRequestTest
private const string VALUE1 = "Value1";
private const string VALUE2 = "Value2";

private Mock<IDeviceClient> client;
private SdkClient sdkClient;
private readonly IDevicePropertiesRequest target;
private Mock<IDeviceClientWrapper> sdkClient;
private Mock<ILogger> logger;

private IDevicePropertiesRequest target;

public DevicePropertiesRequestTest(ITestOutputHelper log)
{
this.sdkClient = GetSdkClient();

this.client = new Mock<IDeviceClient>();
this.sdkClient = new Mock<IDeviceClientWrapper>();
this.logger = new Mock<ILogger>();

this.target = new DeviceProperties(sdkClient, this.logger.Object);
this.target = new DeviceProperties(this.sdkClient.Object, this.logger.Object);
}

[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
Expand All @@ -46,7 +40,7 @@ public void SmartDictionary_Should_UpdateValue_When_DesiredPropertiesChange()
// Arrange
const string NEW_VALUE = "new value";

ISmartDictionary reportedProps = GetTestProperties();
ISmartDictionary reportedProps = this.GetTestProperties();
this.target.RegisterChangeUpdateAsync(DEVICE_ID, reportedProps);

TwinCollection desiredProps = new TwinCollection();
Expand All @@ -70,7 +64,7 @@ public void SmartDictionary_Should_HaveNewItem_When_NewDesiredPropertyAdded()
const string NEW_KEY = "new key";
const string NEW_VALUE = "new value";

ISmartDictionary reportedProps = GetTestProperties();
ISmartDictionary reportedProps = this.GetTestProperties();
this.target.RegisterChangeUpdateAsync(DEVICE_ID, reportedProps);

TwinCollection desiredProps = new TwinCollection();
Expand All @@ -91,12 +85,12 @@ public void SmartDictionary_Should_HaveNewItem_When_NewDesiredPropertyAdded()
public void SmartDictionary_Should_Not_Update_When_DesiredPropertiesValueIsTheSame()
{
// Arrange
ISmartDictionary reportedProps = GetTestProperties();
ISmartDictionary reportedProps = this.GetTestProperties();
reportedProps.ResetChanged();
Assert.False(reportedProps.Changed);

this.target.RegisterChangeUpdateAsync(DEVICE_ID, reportedProps);

TwinCollection desiredProps = new TwinCollection
{
[KEY1] = VALUE1 // This should be the same value in props
Expand All @@ -111,16 +105,6 @@ public void SmartDictionary_Should_Not_Update_When_DesiredPropertiesValueIsTheSa
Assert.False(reportedProps.Changed);
}

private SdkClient GetSdkClient()
{
var connectionString = $"HostName=somehost.azure-devices.net;DeviceId=" + DEVICE_ID + ";SharedAccessKeyName=iothubowner;SharedAccessKey=Test123+Test123456789+TestTestTestTestTest1=";

SdkClient sdkClient = SdkClient.CreateFromConnectionString(connectionString, TransportType.Mqtt_Tcp_Only);
sdkClient.SetRetryPolicy(new NoRetry());

return sdkClient;
}

private ISmartDictionary GetTestProperties()
{
SmartDictionary properties = new SmartDictionary();
Expand Down
23 changes: 14 additions & 9 deletions Services.Test/DevicesTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ public class DevicesTest
/// <summary>The test logger</summary>
private readonly ITestOutputHelper log;

private Mock<IServicesConfig> config;
private Mock<IIotHubConnectionStringManager> connectionStringManager;
private Mock<ILogger> logger;
private readonly Mock<IRegistryManager> registry;
private readonly Devices target;
private readonly Mock<IServicesConfig> config;
private readonly Mock<IIotHubConnectionStringManager> connectionStringManager;
private readonly Mock<IRegistryManager> registry;
private readonly Mock<IDeviceClientWrapper> deviceClient;
private readonly Mock<ILogger> logger;

public DevicesTest(ITestOutputHelper log)
{
Expand All @@ -33,17 +34,21 @@ public DevicesTest(ITestOutputHelper log)
this.config = new Mock<IServicesConfig>();
this.connectionStringManager = new Mock<IIotHubConnectionStringManager>();
this.registry = new Mock<IRegistryManager>();
this.deviceClient = new Mock<IDeviceClientWrapper>();
this.logger = new Mock<ILogger>();

this.target = new Devices(
this.config.Object,
this.connectionStringManager.Object,
this.registry.Object,
this.deviceClient.Object,
this.logger.Object);

this.connectionStringManager
.Setup(x => x.GetIotHubConnectionString())
.Returns("HostName=iothub-AAAA.azure-devices.net;SharedAccessKeyName=AAAA;SharedAccessKey=AAAA");

this.target.SetCurrentIotHub();
}

/**
Expand All @@ -56,24 +61,24 @@ public DevicesTest(ITestOutputHelper log)
public void ItThrowsWhenCreationTimesOut()
{
// Case 1: the code uses async, and the exception surfaces explicitly

// Arrange
this.registry.Setup(x => x.AddDeviceAsync(It.IsAny<Device>())).Throws<TaskCanceledException>();

// Act+Assert
Assert.ThrowsAsync<ExternalDependencyException>(
async () => await this.target.CreateAsync("a-device-id"))
async () => await this.target.CreateAsync("a-device-id"))
.Wait(Constants.TEST_TIMEOUT);

// Case 2: the code uses Wait(), and the exception is wrapped in AggregateException

// Arrange
var e = new AggregateException(new TaskCanceledException());
this.registry.Setup(x => x.AddDeviceAsync(It.IsAny<Device>())).Throws(e);

// Act+Assert
Assert.ThrowsAsync<ExternalDependencyException>(
async () => await this.target.CreateAsync("a-device-id"))
async () => await this.target.CreateAsync("a-device-id"))
.Wait(Constants.TEST_TIMEOUT);
}
}
Expand Down
Loading

0 comments on commit 6f0d073

Please sign in to comment.