Add IsSimulated Tag when devices are created from list (#195)

* Simplify the device models, no methods and twins (#121)

* Remove unused models, scripts, methods, properties
* Upgrade to .NET Core 2.0
* Add some more logging
* Improve simulation runner startup to handle exceptions
* Update CI conf

* move docs, move wiki, new API specs, fix scripts for Windows Bash (#123)

* move docs, move wiki, new API specs, add copyright, fix for Windows Bash

* Disable twin read write by default and add config option to enable (#125)

* add config setting to turn of twin read/write
* add logic to only call twin reads/writes if enabled
* change twin read/write config value to an optional env var

* Allow to schedule a simulation, defining start and end time (#126)

* Support simulation duration and scheduling
* Fix the spelling of “ETag”
* Allow ETag=*
* adjust unit test precision to mitigate flaky test

* Upgrade Docker image to 2.0.3 (#132)

* Fix nullref exception

* Copy agent settings into web service

* Fix status endpoint

* Use S2 limits and increase async thread pool size

* Run a simulation against a hub provisioned by the user (#133)

* Add IoTHub with connstring to Api Model, pass "default" to use the configured hub
* Add private helpers to redact key from IotHubConnString
* Store non redacted entire connection string in a file
* Update API specs documentation

* Reduce the number of threads and improve overall performance (#137)

* Rewrite the simulation engine to use fewer threads
* Start sending telemetry as soon as possible
* Run simulation engine in the same process used for the web service
* Add workaround for registry manager becoming unresponsive
* Add more optional logging by device and by actor
* Use logging level and other logging settings from configuration

* New web service APIs (#138)

New web service APIs

* New API to support multiple scripts 
* New API to support custom sensors
* New API to support custom telemetry frequency
* New API to expose whether a hub is configured, i.e. provisioned and the connection string is in the config file
* Fix exception occurring when there is no connection string

* Simulation input validation (#140)

* Use custom frequency for telemetry and device state (#141)

* Apply the customized telemetry and state frequencies + fix bug for models with multiple messages
* Fix exception on bad request

* Improved Azure IotHub Connection String Validation  (#143)

* additional validation for iothub connection string

* check permissions with calls to registry manager instead of string comparison

* Refactor permissions validation into separate methods. Make sure test device created is deleted, create with a regognizable test name in case of error.

* remove await from Assert.ThrowsAsync

* added retry logic to delete test device

* Logging cleanup

* Internal scripts for increasing/decreasing/random (#146)

* Update travis CI config to use .NET core 2.0.3

* Fix log level parsing from the config, to be case insensitive

* Update simulation model parsing/serialization. Add script Params in the service layer

* Complete the device model override logic

* Add internal scripts

* Allow to override the initial state. Add “online” key where missing.

* Fix null reference exception in DeviceModelsGeneration (#147)

* Use env var to define log level (#150)

* Use env var to define log level
* Add env vars documentation ENVIRONMENT_VARIABLES.md

* bugfix: Etag mismatch now returns 409 Conflict instead of 400 Bad Request (#151)

* When available, return a URL to the metrics of the pre-provisioned hub (#153)

When available and when the simulation is running, return a URL to the metrics of the pre-provisioned hub. Also some changes to the /status endpoint

* Use PCS_LOG_LEVEL env var for log level, instead of LOG_LEVEL

* Create devices using batch operations (#154)

* When a simulation is deleted, delete also the devices
* When a simulation starts, create all the devices in batches

* Throw error on all-whitespace connection string & validate default hub (#155)

* Check for whitespace in custom connection string. Check that default IotHub exists and is valid.
* Update invalid connection string message
* fix log level for GetiotHubConnectionString()

* Map “Custom” device model id used by the UI to the internal ID

* Fix code style

* Fix Decrementing function

* Add system properties to the messages

* Remove old code used to detect simulation stop via cancellation token (#162)

* Remove old code used to detect simulation stop via cancellation token
* Rethrow timeout exceptions

* Fix for override stock device model with null value (#163)

* add null check for PUT payload properties

* add null check test

* update test arrangement

* uncomment UpdateTwinAsync

* add folder for DeviceTwinActor

* Fix exceptions when override stock device model (#164)

* Add null check for MessageSchema

* Add support classes for DeviceTwinActor to update twin -- uses empty methods

* remove Properties from DeviceStateActor class

* Add InternalDeviceState Class and ability to update twin via callback from javascript

* add placeholders for twin update logic for future pr

* remove eslint jsdoc updates and update javascriptinterpreter tests

* Add new thread for device properties updates

* return null for not implemented methods

* Add active device count for status API (#169)

* Register SimulationRunner as a singleton type
* Allow DeviceStatusActor report active status
* Add active device count to status API

* Add Unit Tests for Internal Device State

* Update existing tests with new InternalDeviceState class

* Update scripts with instructions on device property updates

* Fix errors with JS device scripts and readonly dictionary

* revert changes to DeviceTwin class

* Update log messages for readability with timestamp

* Rename logging methods for consistency

* Separate properties and state and remove unused lines

* update comments for twin update branch

* Revert UpdateTwinAsync signature in DeviceClient

* revert UpdateState and JSValueToDictionary to private

* update comment on restoreState in chiller js script

* Update InternalDevicePropertiesTest names

* set sending telemetry retry policy to No Retry (#175)

* Consolidated to SmartDictionary class

* remove DevicePropertiesActor, revert DeviceTwin, change terminology from sensors to state

* revert actors logger

* revert simulation runner

* revert simulation runner test

* revert deletion of UpdateReportedProperties.cs

* fix spacing in SimulationRunner

* fix spacing in device twin

* consolidate restore state javascript methods

* add properties to internal script method call

* variable/method naming, whitespace cleanup, add missing method in elevator state script

* Add Device Properties logic to internal simulation (#173)

* uncomment UpdateTwinAsync

* add folder for DeviceTwinActor

* Add support classes for DeviceTwinActor to update twin -- uses empty methods

* remove Properties from DeviceStateActor class

* Add InternalDeviceState Class and ability to update twin via callback from javascript

* add placeholders for twin update logic for future pr

* remove eslint jsdoc updates and update javascriptinterpreter tests

* Add new thread for device properties updates

* return null for not implemented methods

* Add Unit Tests for Internal Device State

* Update existing tests with new InternalDeviceState class

* Update scripts with instructions on device property updates

* Fix errors with JS device scripts and readonly dictionary

* revert changes to DeviceTwin class

* Update log messages for readability with timestamp

* Rename logging methods for consistency

* Separate properties and state and remove unused lines

* update comments for twin update branch

* Revert UpdateTwinAsync signature in DeviceClient

* revert UpdateState and JSValueToDictionary to private

* update comment on restoreState in chiller js script

* Update InternalDevicePropertiesTest names

* Consolidated to SmartDictionary class

* remove DevicePropertiesActor, revert DeviceTwin, change terminology from sensors to state

* revert actors logger

* revert simulation runner

* revert simulation runner test

* revert deletion of UpdateReportedProperties.cs

* fix spacing in SimulationRunner

* fix spacing in device twin

* consolidate restore state javascript methods

* add properties to internal script method call

* variable/method naming, whitespace cleanup, add missing method in elevator state script

* Revert "Add Device Properties logic to internal simulation (#173)"

This reverts commit 37a720d044.

* [Updated] Add DevicePropertiesActor and push reported properties updates to the IoT Hub (#181)

* Initial commit with placeholders for sending twin updates

* Add skeleton DevicePropertiesActor and integrate with SimulationRunner

* Add mock devicePropertiesActor for SimulationRunnerTest

* added Device Properties Actor Setup

* add device properties actor tests

* Add Device Properties logic to internal simulation (#173)

* uncomment UpdateTwinAsync

* add folder for DeviceTwinActor

* Add support classes for DeviceTwinActor to update twin -- uses empty methods

* remove Properties from DeviceStateActor class

* Add InternalDeviceState Class and ability to update twin via callback from javascript

* add placeholders for twin update logic for future pr

* remove eslint jsdoc updates and update javascriptinterpreter tests

* Add new thread for device properties updates

* return null for not implemented methods

* Add Unit Tests for Internal Device State

* Update existing tests with new InternalDeviceState class

* Update scripts with instructions on device property updates

* Fix errors with JS device scripts and readonly dictionary

* revert changes to DeviceTwin class

* Update log messages for readability with timestamp

* Rename logging methods for consistency

* Separate properties and state and remove unused lines

* update comments for twin update branch

* Revert UpdateTwinAsync signature in DeviceClient

* revert UpdateState and JSValueToDictionary to private

* update comment on restoreState in chiller js script

* Update InternalDevicePropertiesTest names

* Consolidated to SmartDictionary class

* remove DevicePropertiesActor, revert DeviceTwin, change terminology from sensors to state

* revert actors logger

* revert simulation runner

* revert simulation runner test

* revert deletion of UpdateReportedProperties.cs

* fix spacing in SimulationRunner

* fix spacing in device twin

* consolidate restore state javascript methods

* add properties to internal script method call

* variable/method naming, whitespace cleanup, add missing method in elevator state script

* Revert "Add Device Properties logic to internal simulation (#173)"

This reverts commit 37a720d044.

* Add State Machine for device properties updates

* Add Device Property Update Logic and Remove Unused Device Twin Model

* delete old commented out DeviceConnection/UpdateReportedProperties.cs

* Add tests for UpdateReportedProperties

* Add properties to device models & clean up UpdatePropertiesAsync

* remove unused usings

* remove unnecessary lock in JavascriptInterpreter

* Parvezp/add methods (#182)

* Initial commit with placeholders for sending twin updates

* Add skeleton DevicePropertiesActor and integrate with SimulationRunner

* Add mock devicePropertiesActor for SimulationRunnerTest

* added Device Properties Actor Setup

* add device properties actor tests

* Initial check-in for adding methods

* Updating the tabs

* Adding more log parameters

* Fixing build break
Sorting using

* Adding all the simulated devices,state and methods (#183)

* Initial commit with placeholders for sending twin updates

* Add skeleton DevicePropertiesActor and integrate with SimulationRunner

* Add mock devicePropertiesActor for SimulationRunnerTest

* added Device Properties Actor Setup

* add device properties actor tests

* Initial check-in for adding methods

* Updating the tabs

* Adding more log parameters

* Fixing build break
Sorting using

* * Adding all simulated devices
* Adding all of their state javascript files
* Adding all of the javascript  methods for those simulated devices

* Adding unit tests for the new files

* Addressing comments

* Removing extra space that i missed

* Update FirmwareUpdate method to use correct parameters in the callback from js to c# (#186)

* Feature/telemetry metrics (#170)

* Add simulation status reporting messages throughput and errors counters
* Do not retry sending telemetry in case of errors
* Change Azure SDK timeout to 10 seconds (default is 4 minutes)
* Improve SDK exceptions handling
* Fix rare exception due to contention on the `state` variable

* Change stock models to use AMQP (#189)

* Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0 (#187)

Upgrade Azure IoT SDK: Devices Client 1.5.2 to 1.7.0
Upgrade test dependencies

* Register for Desired Property State Changes (#184)

Adds functionality for receiving notifications of Desired Property state changes from the IoT Hub. When the hub detects a state change it will send a notification via the DeviceClient.SetDesiredPropertyUpdateCallbackAsync registration. This change allows the simulation service to subscribe to the change notifications and update the internal simulation state to report the desired property to the hub when executed.

Changes:
* add callback for desired properties updates to Device Client
* add DevicePropertiesRequestTest
* add property for SupportedMethods

* Update DeviceConnectionActorTest with correct constructor for DeviceConnectionActor

* Update DEVICE_MODELS.md

* Add waiting state for properties update

* Update SetAll in SmartDictionar to set a new ConurrentDictionary

* Refactor properties actor

* Rename DeviceProperties.cs & methods, make callback private, update tests

* remove unused property from DevicePropertiesActor

* UpdateReportedPropertiesTest changes to reflect desired functionality

* Update DeviceConnectionActor state machine to tag simulated devices that were created via a list creation in Devices.cs

* Add Device Methods and Properties Functionality (#193)

* Add new state machine to manage changes to devices' "reported properties"
* Add callback to manage changes to devices's "desired properties"
* Add callbacks to manage method calls
* Refactor and improve how simulation scripts access state and properties

* move device tagging to DevicePropertiesActor and update tests

* Fix DevicePropertiesActor reference to twin failure count

* remove whitespace

* Fix merge conflicts between azure-iot-pcs-simulation and master (#196)

* Fix #122 + backport fix for flaky test (#128)

* Upgrade to .NET Core 2.0 and upgrade dependencies (#130)

* Upgrade to .NET Core 2.0 and upgrade dependencies
* Update comments and docs

* Change Docker base image to use .NET Core 2.0.3 (#131)

* Change Docker base image to use .NET Core 2.0.3

* use jessie

* Use absolute instead of relative links to wiki (#161)

Fix for:
https://github.com/Azure/device-simulation-dotnet/issues/39

The relative links don't resolve to the wiki page ending up in a 404. This update changes the URL links to be the full relative link to the documentation page.

* Remove squash (#166)

* Removing the squash flag

* Fixing extra space

* Use env vars in launchSettings.json (#168)

* Docker container excessively privileged running root user (#178)

* Add default non-root user 'pcsuser'
* Run service as 'pcsuser'

PBI[2211778]

* remove whitespace

* revert SimulationAgent.csproj changes

* Adjust whitespace in SimulationAgent.csproj

* remove newline

* Move FailedDeviceTwinUpdatesCount logic to SimulationRunner

* rename Tag to SetDeviceTag

* rename twin to device

* Clean up comments

* Upgrade travis.yml dotnet core version

* revert .Net core upgrade for travis

* Update .travis.yml

* Fix build

* fixing build...

* tag devices with ContinueWith

* fix typos
This commit is contained in:
Jill Bender 2018-04-19 11:16:27 -07:00 коммит произвёл Parvez
Родитель ea79508aea
Коммит 0075b280c7
15 изменённых файлов: 447 добавлений и 194 удалений

Просмотреть файл

@ -0,0 +1,63 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Concurrency;
using Moq;
using Services.Test.helpers;
using Xunit;
using Xunit.Abstractions;
namespace Services.Test.Concurrency
{
public class LoopSettingsTest
{
private readonly ITestOutputHelper log;
private readonly Mock<IRateLimitingConfig> rateLimitingConfig;
private readonly PropertiesLoopSettings propertiesTarget;
private const int TWIN_WRITES_PER_SECOND = 10;
public LoopSettingsTest(ITestOutputHelper logger)
{
this.log = logger;
this.rateLimitingConfig = new Mock<IRateLimitingConfig>();
this.propertiesTarget = new PropertiesLoopSettings(this.rateLimitingConfig.Object);
}
[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
public void Should_SetTaggingLimit_When_NewLoopCreated()
{
// Arrange
this.SetupRateLimitingConfig();
// Act
this.propertiesTarget.NewLoop();
// Assert
// In order for other threads to be able to schedule twin opertations,
// value should be at least 1 but less than the limit per second.
Assert.True(this.propertiesTarget.SchedulableTaggings >= 1);
Assert.True(this.propertiesTarget.SchedulableTaggings < TWIN_WRITES_PER_SECOND);
}
[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
public void Should_UseTwinWrites_When_NewLoopCreated()
{
// Arrange
this.SetupRateLimitingConfig();
// Act
this.propertiesTarget.NewLoop();
// Assert
// ensure twin writes were accessed and no other
// config values to calculate properties limits
this.rateLimitingConfig.VerifyGet(x => x.TwinWritesPerSecond);
this.rateLimitingConfig.VerifyNoOtherCalls();
}
private void SetupRateLimitingConfig()
{
this.rateLimitingConfig.Setup(x => x.TwinWritesPerSecond).Returns(TWIN_WRITES_PER_SECOND);
}
}
}

Просмотреть файл

@ -22,7 +22,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Concurrency
public double SchedulableFetches { get; set; }
public double SchedulableRegistrations { get; set; }
public double SchedulableTaggings { get; set; }
public ConnectionLoopSettings(IRateLimitingConfig ratingConfig)
{
@ -35,7 +34,31 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Concurrency
// Prioritize connections and registrations, so that devices connect as soon as possible
this.SchedulableFetches = Math.Max(1, this.ratingConfig.RegistryOperationsPerMinute / 25);
this.SchedulableRegistrations = Math.Max(1, this.ratingConfig.RegistryOperationsPerMinute / 10);
this.SchedulableTaggings = Math.Max(1, this.ratingConfig.RegistryOperationsPerMinute / 25);
}
}
public class PropertiesLoopSettings
{
private const int SHARED_TWIN_WRITES_ALLOCATION = 2;
public const int MIN_LOOP_DURATION = 500;
private readonly IRateLimitingConfig ratingConfig;
public double SchedulableTaggings { get; set; }
public PropertiesLoopSettings(IRateLimitingConfig ratingConfig)
{
this.ratingConfig = ratingConfig;
this.NewLoop();
}
public void NewLoop()
{
// In order for other threads to be able to schedule twin operations,
// divide by a constant value to prevent the tagging thread from having
// first priority over twin writes all of the time.
this.SchedulableTaggings = Math.Max(1, this.ratingConfig.TwinWritesPerSecond / SHARED_TWIN_WRITES_ALLOCATION);
}
}
}

Просмотреть файл

@ -22,10 +22,10 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics
void DeviceRegistered();
void DeviceRegistrationFailed();
void DeviceTwinTaggingScheduled(long time);
void TaggingDeviceTwin();
void DeviceTwinTagged();
void DeviceTwinTaggingFailed();
void DeviceTaggingScheduled(long time);
void TaggingDevice();
void DeviceTagged();
void DeviceTaggingFailed();
void DeviceConnectionScheduled(long time);
void ConnectingDevice();
@ -184,37 +184,37 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics
this.LogRegistry("Registration FAILED");
}
public void DeviceTwinTaggingScheduled(long time)
public void DeviceTaggingScheduled(long time)
{
if (!this.enabled) return;
var msg = DateTimeOffset.FromUnixTimeMilliseconds(time).ToString(DATE_FORMAT);
this.Log("Twin tagging scheduled at: " + msg);
this.LogProperties("Twin tagging scheduled at: " + msg);
this.Log("Device tagging scheduled at: " + msg);
this.LogProperties("Device tagging scheduled at: " + msg);
}
public void TaggingDeviceTwin()
public void TaggingDevice()
{
if (!this.enabled) return;
this.Log("Tagging twin");
this.Log("Tagging device");
this.LogProperties("Tagging");
}
public void DeviceTwinTagged()
public void DeviceTagged()
{
if (!this.enabled) return;
this.Log("Twin tagged");
this.LogProperties("Twin tagged");
this.Log("Device tagged");
this.LogProperties("Device tagged");
}
public void DeviceTwinTaggingFailed()
public void DeviceTaggingFailed()
{
if (!this.enabled) return;
this.Log("Twin tagging FAILED");
this.LogProperties("Twin tag FAILED");
this.Log("Device tagging FAILED");
this.LogProperties("Device tag FAILED");
}
public void DeviceConnectionScheduled(long time)

Просмотреть файл

@ -20,7 +20,6 @@ namespace SimulationAgent.Test.DeviceConnection
private readonly Mock<IRateLimiting> rateLimiting;
private readonly Mock<Fetch> fetchLogic;
private readonly Mock<Register> registerLogic;
private readonly Mock<DeviceTwinTag> deviceTwinTagLogic;
private readonly Mock<IDevices> devices;
private readonly Mock<Connect> connectLogic;
private readonly Mock<IDeviceStateActor> deviceStateActor;
@ -41,9 +40,6 @@ namespace SimulationAgent.Test.DeviceConnection
this.registerLogic = new Mock<Register>(
this.devices.Object,
this.logger.Object);
this.deviceTwinTagLogic = new Mock<DeviceTwinTag>(
this.devices.Object,
this.logger.Object);
this.connectLogic = new Mock<Connect>(
this.devices.Object,
this.scriptInterpreter.Object,
@ -61,7 +57,6 @@ namespace SimulationAgent.Test.DeviceConnection
this.rateLimiting.Object,
this.fetchLogic.Object,
this.registerLogic.Object,
this.deviceTwinTagLogic.Object,
this.connectLogic.Object);
}
@ -98,39 +93,6 @@ namespace SimulationAgent.Test.DeviceConnection
Assert.Equal(FAILED_DEVICE_CONNECTIONS_COUNT, failedDeviceConnectionCount);
}
[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
public void TheNumberOfFailedTwinUpdatesIsZeroAtStart()
{
// Arrange
this.SetupDeviceConnectionActor();
// Act
long failedTwinUpdateCount = this.target.FailedTwinUpdatesCount;
// Assert
Assert.Equal(0, failedTwinUpdateCount);
}
[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
public void ItReturnsTheNumberOfFailedTwinUpdates()
{
// Arrange
const int FAILED_DEVICE_TWIN_UPDATES_COUNT = 5;
this.SetupDeviceConnectionActor();
DeviceConnectionActor.ActorEvents deviceTwinTaggingFailed = DeviceConnectionActor.ActorEvents.DeviceTwinTaggingFailed;
// Act
for (int i = 0; i < FAILED_DEVICE_TWIN_UPDATES_COUNT; i++)
{
this.target.HandleEvent(deviceTwinTaggingFailed);
}
long failedTwinUpdateCount = this.target.FailedTwinUpdatesCount;
// Assert
Assert.Equal(FAILED_DEVICE_TWIN_UPDATES_COUNT, failedTwinUpdateCount);
}
private void SetupDeviceConnectionActor()
{
string DEVICE_ID = "01";

Просмотреть файл

@ -1,8 +1,10 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Concurrency;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Simulation;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceConnection;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceProperties;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceState;
@ -18,13 +20,18 @@ namespace SimulationAgent.Test.DeviceProperties
public class DevicePropertiesActorTest
{
private readonly Mock<ILogger> logger;
private readonly Mock<IActorsLogger> actorsLogger;
private readonly Mock<IRateLimiting> rateLimiting;
private readonly Mock<IDevicePropertiesLogic> updatePropertiesLogic;
private readonly Mock<IRateLimitingConfig> rateLimitingConfig;
private readonly Mock<IDevices> devices;
private readonly Mock<UpdateReportedProperties> updatePropertiesLogic;
private readonly Mock<SetDeviceTag> deviceTagLogic;
private readonly Mock<IDeviceConnectionActor> deviceConnectionActor;
private readonly Mock<IDeviceStateActor> deviceStateActor;
private readonly Mock<PropertiesLoopSettings> loopSettings;
private const string DEVICE_ID = "01";
private const int TWIN_WRITES_PER_SECOND = 10;
private DevicePropertiesActor target;
@ -32,12 +39,14 @@ namespace SimulationAgent.Test.DeviceProperties
{
this.logger = new Mock<ILogger>();
this.actorsLogger = new Mock<IActorsLogger>();
this.rateLimiting = new Mock<IRateLimiting>();
this.rateLimitingConfig = new Mock<IRateLimitingConfig>();
this.deviceConnectionActor = new Mock<IDeviceConnectionActor>();
this.deviceStateActor = new Mock<IDeviceStateActor>();
this.updatePropertiesLogic = new Mock<IDevicePropertiesLogic>();
this.devices = new Mock<IDevices>();
this.loopSettings = new Mock<PropertiesLoopSettings>(this.rateLimitingConfig.Object);
this.updatePropertiesLogic = new Mock<UpdateReportedProperties>(this.logger.Object);
this.deviceTagLogic = new Mock<SetDeviceTag>(devices.Object, this.logger.Object);
this.CreateNewDevicePropertiesActor();
}
@ -46,7 +55,7 @@ namespace SimulationAgent.Test.DeviceProperties
public void Setup_Called_Twice_Should_Throw_Already_Initialized_Exception()
{
// Arrange
CreateNewDevicePropertiesActor();
this.CreateNewDevicePropertiesActor();
// Act
this.SetupDevicePropertiesActor();
@ -62,7 +71,7 @@ namespace SimulationAgent.Test.DeviceProperties
{
// Arrange
const ActorEvents OUT_OF_RANGE_EVENT = (ActorEvents) 123;
CreateNewDevicePropertiesActor();
this.CreateNewDevicePropertiesActor();
// Act
this.SetupDevicePropertiesActor();
@ -72,22 +81,89 @@ namespace SimulationAgent.Test.DeviceProperties
() => this.target.HandleEvent(OUT_OF_RANGE_EVENT));
}
[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
public void Should_Return_CountOfFailedTwinUpdates_When_TwinUpdateFails()
{
// Arrange
const int FAILED_DEVICE_TWIN_UPDATES_COUNT = 3;
this.CreateNewDevicePropertiesActor();
this.SetupDevicePropertiesActor();
this.SetupRateLimitingConfig();
this.loopSettings.Object.NewLoop(); // resets SchedulableTaggings
// The constructor should initialize count to zero.
Assert.Equal(0, this.target.FailedTwinUpdatesCount);
ActorEvents deviceTwinTaggingFailed = ActorEvents.DeviceTaggingFailed;
// Act
for (int i = 0; i < FAILED_DEVICE_TWIN_UPDATES_COUNT; i++)
{
this.target.HandleEvent(deviceTwinTaggingFailed);
}
long failedTwinUpdateCount = this.target.FailedTwinUpdatesCount;
// Assert
Assert.Equal(FAILED_DEVICE_TWIN_UPDATES_COUNT, failedTwinUpdateCount);
}
[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
public void Should_ReturnZeroForFailedTwinUpdates_When_Started()
{
// Arrange
this.CreateNewDevicePropertiesActor();
// Act
long failedTwinUpdateCount = this.target.FailedTwinUpdatesCount;
// Assert
Assert.Equal(0, failedTwinUpdateCount);
}
private void CreateNewDevicePropertiesActor()
{
this.target = new DevicePropertiesActor(
this.logger.Object,
this.actorsLogger.Object,
this.rateLimiting.Object,
this.updatePropertiesLogic.Object);
this.updatePropertiesLogic.Object,
this.deviceTagLogic.Object);
}
private void SetupDevicePropertiesActor()
{
string DEVICE_ID = "01";
this.target.Setup(DEVICE_ID,
this.deviceStateActor.Object,
this.deviceConnectionActor.Object);
this.deviceConnectionActor.Object,
this.loopSettings.Object);
}
private void SetupRateLimitingConfig()
{
this.rateLimitingConfig.SetupGet(x => x.TwinWritesPerSecond).Returns(TWIN_WRITES_PER_SECOND);
}
private DeviceConnectionActor GetDeviceConnectionActor()
{
Mock<IScriptInterpreter> scriptInterpreter = new Mock<IScriptInterpreter>();
Mock<Fetch> fetchLogic = new Mock<Fetch>(
this.devices.Object,
this.logger.Object);
Mock<Register> registerLogic = new Mock<Register>(
this.devices.Object,
this.logger.Object);
Mock<Connect> connectLogic = new Mock<Connect>(
this.devices.Object,
scriptInterpreter.Object,
this.logger.Object);
return new DeviceConnectionActor(
this.logger.Object,
this.actorsLogger.Object,
this.rateLimiting.Object,
fetchLogic.Object,
registerLogic.Object,
connectLogic.Object);
}
}
}

Просмотреть файл

@ -0,0 +1,66 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Concurrency;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceConnection;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceProperties;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceState;
using Moq;
using SimulationAgent.Test.helpers;
using Xunit;
using Xunit.Abstractions;
namespace SimulationAgent.Test.DeviceProperties
{
public class TagTest
{
private const string DEVICE_ID = "01";
private readonly Mock<ILogger> logger;
private Mock<IDevices> devices;
private readonly Mock<IDevicePropertiesActor> devicePropertiesActor;
private readonly Mock<IDeviceStateActor> deviceStateActor;
private readonly Mock<IDeviceConnectionActor> deviceConnectionActor;
private readonly Mock<IRateLimitingConfig> rateLimitingConfig;
private readonly Mock<PropertiesLoopSettings> loopSettings;
private SetDeviceTag target;
public TagTest(ITestOutputHelper log)
{
this.logger = new Mock<ILogger>();
this.devices = new Mock<IDevices>();
this.rateLimitingConfig = new Mock<IRateLimitingConfig>();
this.devicePropertiesActor = new Mock<IDevicePropertiesActor>();
this.deviceStateActor = new Mock<IDeviceStateActor>();
this.deviceConnectionActor = new Mock<IDeviceConnectionActor>();
this.loopSettings = new Mock<PropertiesLoopSettings>(this.rateLimitingConfig.Object);
this.target = new SetDeviceTag(this.devices.Object, this.logger.Object);
}
[Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)]
public void Should_Call_DeviceTagged_When_Succeeded()
{
// Arrange
this.SetupPropertiesActor();
this.target.Setup(this.devicePropertiesActor.Object, DEVICE_ID);
// Act
this.target.Run();
// Assert
this.devicePropertiesActor.Verify(x => x.HandleEvent(DevicePropertiesActor.ActorEvents.DeviceTagged));
}
private void SetupPropertiesActor()
{
this.devicePropertiesActor.Object.Setup(
DEVICE_ID,
this.deviceStateActor.Object,
this.deviceConnectionActor.Object,
this.loopSettings.Object);
}
}
}

Просмотреть файл

@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Concurrency;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceConnection;
@ -20,22 +21,27 @@ namespace SimulationAgent.Test.DeviceProperties
{
private const string DEVICE_ID = "01";
private readonly Mock<ILogger> logger;
private readonly Mock<IRateLimitingConfig> rateLimitingConfig;
private readonly Mock<IDevicePropertiesActor> devicePropertiesActor;
private readonly Mock<IDeviceStateActor> deviceStateActor;
private readonly Mock<IDeviceConnectionActor> deviceConnectionActor;
private readonly Mock<ISmartDictionary> properties;
private readonly Mock<IDeviceClient> client;
private readonly Mock<PropertiesLoopSettings> loopSettings;
private UpdateReportedProperties target;
public UpdateReportedPropertiesTest(ITestOutputHelper log)
{
this.logger = new Mock<ILogger>();
this.rateLimitingConfig = new Mock<IRateLimitingConfig>();
this.devicePropertiesActor = new Mock<IDevicePropertiesActor>();
this.deviceStateActor = new Mock<IDeviceStateActor>();
this.deviceConnectionActor = new Mock<IDeviceConnectionActor>();
this.properties = new Mock<ISmartDictionary>();
this.client = new Mock<IDeviceClient>();
this.loopSettings = new Mock<PropertiesLoopSettings>(
this.rateLimitingConfig.Object);
this.target = new UpdateReportedProperties(logger.Object);
}
@ -79,7 +85,8 @@ namespace SimulationAgent.Test.DeviceProperties
this.devicePropertiesActor.Object.Setup(
DEVICE_ID,
this.deviceStateActor.Object,
this.deviceConnectionActor.Object);
this.deviceConnectionActor.Object,
this.loopSettings.Object);
}
private void SetupPropertiesActorProperties()

Просмотреть файл

@ -217,7 +217,7 @@ namespace SimulationAgent.Test
this.SetupSimulationReadyToStart();
this.deviceConnectionActor
this.devicePropertiesActor
.Setup(x => x.FailedTwinUpdatesCount)
.Returns(FAILED_DEVICE_TWIN_UPDATES_COUNT);

Просмотреть файл

@ -18,7 +18,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
Device Device { get; set; }
bool Connected { get; }
long FailedDeviceConnectionsCount { get; }
long FailedTwinUpdatesCount { get; }
long SimulationErrorsCount { get; }
void Setup(string deviceId, DeviceModel deviceModel, IDeviceStateActor deviceStateActor, ConnectionLoopSettings loopSettings);
@ -27,9 +26,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
void Stop();
}
/**
* TODO: when the device exists already, check whether it is tagged
*/
public class DeviceConnectionActor : IDeviceConnectionActor
{
private enum ActorStatus
@ -40,8 +36,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
Fetching,
ReadyToRegister,
Registering,
ReadyToTagDeviceTwin,
TaggingDeviceTwin,
ReadyToConnect,
Connecting,
Done,
@ -56,8 +50,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
FetchCompleted,
RegistrationFailed,
DeviceRegistered,
DeviceTwinTaggingFailed,
DeviceTwinTagged,
Connected,
ConnectionFailed
}
@ -67,7 +59,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
private readonly IRateLimiting rateLimiting;
private readonly IDeviceConnectionLogic fetchLogic;
private readonly IDeviceConnectionLogic registerLogic;
private readonly IDeviceConnectionLogic deviceTwinTagLogic;
private readonly IDeviceConnectionLogic connectLogic;
private ActorStatus status;
@ -76,7 +67,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
private long whenToRun;
private ConnectionLoopSettings loopSettings;
private long failedDeviceConnectionsCount;
private long failedTwinUpdatesCount;
private long failedRegistrationsCount;
private long failedFetchCount;
@ -121,17 +111,11 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
/// </summary>
public long FailedDeviceConnectionsCount => this.failedDeviceConnectionsCount;
/// <summary>
/// Failed device twin updates counter
/// </summary>
public long FailedTwinUpdatesCount => this.failedTwinUpdatesCount;
/// <summary>
/// Simulation error counter in DeviceConnectionActor
/// </summary>
public long SimulationErrorsCount => this.failedRegistrationsCount +
this.failedFetchCount +
this.FailedTwinUpdatesCount +
this.FailedDeviceConnectionsCount;
public DeviceConnectionActor(
@ -140,7 +124,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
IRateLimiting rateLimiting,
Fetch fetchLogic,
Register registerLogic,
DeviceTwinTag deviceTwinTagLogic,
Connect connectLogic)
{
this.log = logger;
@ -149,7 +132,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
this.fetchLogic = fetchLogic;
this.registerLogic = registerLogic;
this.deviceTwinTagLogic = deviceTwinTagLogic;
this.connectLogic = connectLogic;
this.Message = null;
@ -162,10 +144,9 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
this.deviceStateActor = null;
this.failedDeviceConnectionsCount = 0;
this.failedTwinUpdatesCount = 0;
this.failedRegistrationsCount = 0;
this.failedFetchCount = 0;
}
}
/// <summary>
/// Invoke this method before calling Execute(), to initialize the actor
@ -188,7 +169,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
this.fetchLogic.Setup(this, this.deviceId, this.deviceModel);
this.registerLogic.Setup(this, this.deviceId, this.deviceModel);
this.deviceTwinTagLogic.Setup(this, this.deviceId, this.deviceModel);
this.connectLogic.Setup(this, this.deviceId, this.deviceModel);
this.actorLogger.Setup(deviceId, "Connection");
@ -239,11 +219,8 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
break;
case ActorEvents.DeviceRegistered:
if (this.loopSettings.SchedulableTaggings <= 0) return;
this.loopSettings.SchedulableTaggings--;
this.actorLogger.DeviceRegistered();
this.ScheduleDeviceTagging();
this.ScheduleConnection();
break;
case ActorEvents.RegistrationFailed:
@ -255,25 +232,11 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
this.ScheduleRegistration();
break;
case ActorEvents.DeviceTwinTaggingFailed:
if (this.loopSettings.SchedulableTaggings <= 0) return;
this.loopSettings.SchedulableTaggings--;
this.failedTwinUpdatesCount++;
this.actorLogger.DeviceTwinTaggingFailed();
this.ScheduleDeviceTagging();
break;
case ActorEvents.FetchCompleted:
this.actorLogger.DeviceFetched();
this.ScheduleConnection();
break;
case ActorEvents.DeviceTwinTagged:
this.actorLogger.DeviceTwinTagged();
this.ScheduleConnection();
break;
case ActorEvents.ConnectionFailed:
this.failedDeviceConnectionsCount++;
this.actorLogger.DeviceConnectionFailed();
@ -321,12 +284,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
this.actorLogger.ConnectingDevice();
this.connectLogic.RunAsync();
return;
case ActorStatus.ReadyToTagDeviceTwin:
this.status = ActorStatus.TaggingDeviceTwin;
this.actorLogger.TaggingDeviceTwin();
this.deviceTwinTagLogic.RunAsync();
return;
}
}
@ -364,24 +321,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceCo
});
}
private void ScheduleDeviceTagging()
{
var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
// note: we overwrite the twin, so no Read operation is needed
var pauseMsec = this.rateLimiting.GetPauseForNextTwinWrite();
this.whenToRun = now + pauseMsec;
this.status = ActorStatus.ReadyToTagDeviceTwin;
this.actorLogger.DeviceTwinTaggingScheduled(this.whenToRun);
this.log.Debug("Device twin tagging scheduled",
() => new
{
this.deviceId,
Status = this.status.ToString(),
When = this.log.FormatDate(this.whenToRun)
});
}
private void ScheduleConnection()
{
var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

Просмотреть файл

@ -1,53 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Threading.Tasks;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models;
namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceConnection
{
/// <summary>
/// Add twin information to the new device twin
/// </summary>
public class DeviceTwinTag : IDeviceConnectionLogic
{
private readonly IDevices devices;
private readonly ILogger log;
private string deviceId;
private IDeviceConnectionActor context;
public DeviceTwinTag(IDevices devices, ILogger logger)
{
this.log = logger;
this.devices = devices;
}
public void Setup(IDeviceConnectionActor context, string deviceId, DeviceModel deviceModel)
{
this.context = context;
this.deviceId = deviceId;
}
public async Task RunAsync()
{
this.log.Debug("Adding tag to device twin...", () => new { this.deviceId });
try
{
var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
await this.devices.AddTagAsync(this.deviceId);
var timeSpent = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - now;
this.log.Debug("Device tag added", () => new { this.deviceId, timeSpent });
this.context.HandleEvent(DeviceConnectionActor.ActorEvents.DeviceTwinTagged);
}
catch (Exception e)
{
this.log.Error("Error while tagging the device twin", () => new { this.deviceId, e });
this.context.HandleEvent(DeviceConnectionActor.ActorEvents.DeviceTwinTaggingFailed);
}
}
}
}

Просмотреть файл

@ -16,23 +16,33 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DevicePr
ISmartDictionary DeviceProperties { get; }
ISmartDictionary DeviceState { get; }
IDeviceClient Client { get; }
long FailedTwinUpdatesCount { get; }
long SimulationErrorsCount { get; }
void Setup(
string deviceId,
IDeviceStateActor deviceStateActor,
IDeviceConnectionActor deviceConnectionActor);
IDeviceConnectionActor deviceConnectionActor,
PropertiesLoopSettings loopSettings);
string Run();
void HandleEvent(DevicePropertiesActor.ActorEvents e);
void Stop();
}
/// <summary>
/// The Device Properties Actor is responsible for sending updates
/// to the IoT Hub Device Twin. This includes adding an initial tag to
/// the device twin, and pushing changes to the device properties.
/// </summary>
public class DevicePropertiesActor : IDevicePropertiesActor
{
private enum ActorStatus
{
None,
ReadyToStart,
ReadyToTagDevice,
TaggingDevice,
WaitingForChanges,
ReadyToUpdate,
Updating,
@ -42,6 +52,8 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DevicePr
public enum ActorEvents
{
Started,
DeviceTaggingFailed,
DeviceTagged,
PropertiesUpdateFailed,
PropertiesUpdated,
}
@ -50,10 +62,13 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DevicePr
private readonly IActorsLogger actorLogger;
private readonly IRateLimiting rateLimiting;
private readonly IDevicePropertiesLogic updatePropertiesLogic;
private readonly IDevicePropertiesLogic deviceSetDeviceTagLogic;
private ActorStatus status;
private string deviceId;
private long whenToRun;
private PropertiesLoopSettings loopSettings;
private long failedTwinUpdatesCount;
/// <summary>
/// Reference to the actor managing the device state, used
@ -81,21 +96,35 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DevicePr
/// </summary>
public IDeviceClient Client => this.deviceConnectionActor.Client;
/// <summary>
/// Failed device twin updates counter
/// </summary>
public long FailedTwinUpdatesCount => this.failedTwinUpdatesCount;
/// <summary>
/// Simulation error counter in DeviceConnectionActor
/// </summary>
public long SimulationErrorsCount => this.FailedTwinUpdatesCount;
public DevicePropertiesActor(
ILogger logger,
IActorsLogger actorLogger,
IRateLimiting rateLimiting,
IDevicePropertiesLogic updatePropertiesLogic)
UpdateReportedProperties updatePropertiesLogic,
SetDeviceTag deviceSetDeviceTagLogic)
{
this.log = logger;
this.actorLogger = actorLogger;
this.rateLimiting = rateLimiting;
this.updatePropertiesLogic = updatePropertiesLogic;
this.deviceSetDeviceTagLogic = deviceSetDeviceTagLogic;
this.status = ActorStatus.None;
this.deviceId = null;
this.deviceStateActor = null;
this.deviceConnectionActor = null;
this.failedTwinUpdatesCount = 0;
}
/// <summary>
@ -105,7 +134,8 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DevicePr
public void Setup(
string deviceId,
IDeviceStateActor deviceStateActor,
IDeviceConnectionActor deviceConnectionActor)
IDeviceConnectionActor deviceConnectionActor,
PropertiesLoopSettings loopSettings)
{
if (this.status != ActorStatus.None)
{
@ -117,6 +147,10 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DevicePr
this.deviceId = deviceId;
this.deviceStateActor = deviceStateActor;
this.deviceConnectionActor = deviceConnectionActor;
this.loopSettings = loopSettings;
this.updatePropertiesLogic.Setup(this, this.deviceId);
this.deviceSetDeviceTagLogic.Setup(this, this.deviceId);
this.updatePropertiesLogic.Setup(this, this.deviceId);
this.actorLogger.Setup(deviceId, "Properties");
@ -130,15 +164,34 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DevicePr
{
case ActorEvents.Started:
this.actorLogger.ActorStarted();
this.status = ActorStatus.ReadyToTagDevice;
break;
case ActorEvents.DeviceTagged:
this.actorLogger.DeviceTagged();
this.status = ActorStatus.WaitingForChanges;
break;
case ActorEvents.DeviceTaggingFailed:
if (this.loopSettings.SchedulableTaggings <= 0) return;
this.loopSettings.SchedulableTaggings--;
this.failedTwinUpdatesCount++;
this.actorLogger.DeviceTaggingFailed();
this.ScheduleDeviceTagging();
break;
case ActorEvents.PropertiesUpdated:
this.actorLogger.DevicePropertiesUpdated();
this.status = ActorStatus.WaitingForChanges;
break;
case ActorEvents.PropertiesUpdateFailed:
this.failedTwinUpdatesCount++;
this.actorLogger.DevicePropertiesUpdateFailed();
this.SchedulePropertiesUpdate(isRetry: true);
break;
default:
throw new ArgumentOutOfRangeException(nameof(e), e, null);
}
@ -160,6 +213,12 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DevicePr
this.HandleEvent(ActorEvents.Started);
return "started";
case ActorStatus.ReadyToTagDevice:
this.status = ActorStatus.TaggingDevice;
this.actorLogger.TaggingDevice();
this.deviceSetDeviceTagLogic.Run();
return "device tag scheduled";
case ActorStatus.WaitingForChanges:
if (!this.DeviceProperties.Changed) return "no properties to update";
this.SchedulePropertiesUpdate();
@ -201,5 +260,23 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DevicePr
isRetry
});
}
private void ScheduleDeviceTagging()
{
var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
// note: we overwrite the twin, so no Read operation is needed
var pauseMsec = this.rateLimiting.GetPauseForNextTwinWrite();
this.whenToRun = now + pauseMsec;
this.status = ActorStatus.ReadyToTagDevice;
this.actorLogger.DeviceTaggingScheduled(this.whenToRun);
this.log.Debug("Device twin tagging scheduled",
() => new
{
this.deviceId,
Status = this.status.ToString(),
When = this.log.FormatDate(this.whenToRun)
});
}
}
}

Просмотреть файл

@ -0,0 +1,84 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics;
namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceProperties
{
/// <summary>
/// Add twin information to the new device twin
/// </summary>
public class SetDeviceTag : IDevicePropertiesLogic
{
private readonly IDevices devices;
private readonly ILogger log;
private string deviceId;
private IDevicePropertiesActor context;
public SetDeviceTag(IDevices devices, ILogger logger)
{
this.log = logger;
this.devices = devices;
}
public void Setup(IDevicePropertiesActor context, string deviceId)
{
this.context = context;
this.deviceId = deviceId;
}
public void Run()
{
this.log.Debug("Adding tag to device twin...", () => new { this.deviceId });
var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
try
{
/*
* ContinueWith allows to easily manage the exceptions here, with the ability to change
* the code to synchronous or asynchronous, via TaskContinuationOptions.
*
* Once the code successfully handle all the scenarios, with good throughput and low CPU usage
* we should see if the async/await syntax performs similarly/better.
*/
this.devices
.AddTagAsync(this.deviceId)
.ContinueWith(t =>
{
var timeSpent = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - now;
if (t.IsCanceled)
{
this.log.Warn("The set device tag task has been cancelled", () => new { this.deviceId, t.Exception });
}
else if (t.IsFaulted)
{
var exception = t.Exception.InnerExceptions.FirstOrDefault();
this.log.Error(GetLogErrorMessage(exception), () => new { this.deviceId, exception });
this.context.HandleEvent(DevicePropertiesActor.ActorEvents.DeviceTaggingFailed);
}
else if (t.IsCompleted)
{
this.log.Debug("Device tag set", () => new { this.deviceId, timeSpent });
this.context.HandleEvent(DevicePropertiesActor.ActorEvents.DeviceTagged);
}
},
TaskContinuationOptions.ExecuteSynchronously);
}
catch (Exception e)
{
this.log.Error("Unexpected error while tagging the device twin", () => new { this.deviceId, e });
this.context.HandleEvent(DevicePropertiesActor.ActorEvents.DeviceTaggingFailed);
}
}
private static string GetLogErrorMessage(Exception e)
{
return e != null ? "Set device tag error: " + e.Message : string.Empty;
}
}
}

Просмотреть файл

@ -8,4 +8,4 @@
<ItemGroup>
<ProjectReference Include="..\Services\Services.csproj" />
</ItemGroup>
</Project>
</Project>

Просмотреть файл

@ -38,9 +38,12 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent
// Application logger
private readonly ILogger log;
// Set of counter to optimize scheduling
// Settings to optimize scheduling
private readonly ConnectionLoopSettings connectionLoopSettings;
// Settings to optimize scheduling
private readonly PropertiesLoopSettings propertiesLoopSettings;
// Service used to load device models details
private readonly IDeviceModels deviceModels;
@ -106,6 +109,7 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent
IFactory factory)
{
this.connectionLoopSettings = new ConnectionLoopSettings(ratingConfig);
this.propertiesLoopSettings = new PropertiesLoopSettings(ratingConfig);
this.log = logger;
this.deviceModels = deviceModels;
@ -277,13 +281,14 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent
public long FailedDeviceConnectionsCount => this.deviceConnectionActors.Sum(a => a.Value.FailedDeviceConnectionsCount);
// Method to return the count of twin update failed devices
public long FailedDeviceTwinUpdatesCount => this.deviceConnectionActors.Sum(a => a.Value.FailedTwinUpdatesCount);
public long FailedDeviceTwinUpdatesCount => this.devicePropertiesActors.Sum(a => a.Value.FailedTwinUpdatesCount);
// Method to return the count of simulation errors
public long SimulationErrorsCount => this.simulationErrors +
this.deviceConnectionActors.Sum(a => a.Value.SimulationErrorsCount) +
this.deviceStateActors.Sum(a => a.Value.SimulationErrorsCount) +
this.deviceTelemetryActors.Sum(a => a.Value.FailedMessagesCount);
this.deviceTelemetryActors.Sum(a => a.Value.FailedMessagesCount) +
this.devicePropertiesActors.Sum(a => a.Value.SimulationErrorsCount);
private DeviceModel GetDeviceModel(string id, Services.Models.Simulation.DeviceModelOverride overrides)
{
@ -339,6 +344,8 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent
{
while (this.running)
{
this.propertiesLoopSettings.NewLoop();
var before = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
foreach (var device in this.devicePropertiesActors)
{
@ -425,7 +432,7 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent
// Create one device properties actor for each device
var devicePropertiesActor = this.factory.Resolve<IDevicePropertiesActor>();
devicePropertiesActor.Setup(deviceId, deviceStateActor, deviceConnectionActor);
devicePropertiesActor.Setup(deviceId, deviceStateActor, deviceConnectionActor, this.propertiesLoopSettings);
this.devicePropertiesActors.Add(key, devicePropertiesActor);
// Create one telemetry actor for each telemetry message to be sent

Просмотреть файл

@ -9,6 +9,7 @@ using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Runtime;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceConnection;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceProperties;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceState;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent.DeviceTelemetry;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.WebService.Runtime;
@ -98,11 +99,12 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.WebService
// Registrations required by Autofac, these classes implement the same interface
builder.RegisterType<Connect>().As<Connect>();
builder.RegisterType<DeviceTwinTag>().As<DeviceTwinTag>();
builder.RegisterType<SetDeviceTag>().As<SetDeviceTag>();
builder.RegisterType<Fetch>().As<Fetch>();
builder.RegisterType<Register>().As<Register>();
builder.RegisterType<UpdateDeviceState>().As<UpdateDeviceState>();
builder.RegisterType<SendTelemetry>().As<SendTelemetry>();
builder.RegisterType<UpdateReportedProperties>().As<UpdateReportedProperties>();
}
private static void RegisterFactory(IContainer container)