Skip to content

Commit 7505475

Browse files
authored
Add random double template variable (#34)
* Add random double template variable Remove minDouble and maxDouble. Make min max values double and cast to int when necessary * rebase against master * Apply suggestions from comments * Update example in readme
1 parent 5155b73 commit 7505475

File tree

6 files changed

+101
-20
lines changed

6 files changed

+101
-20
lines changed

README.md

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ Customizable variables can be created with the following properties:
9898
|name|Name of the property. Defines what will be replaced in the template telemetry $.Name|
9999
|random|Make the value random, limited by min and max|
100100
|step|If the value is not random, will be incremented each time by the value of step|
101-
|min|For random values defines it's minimum. Otherwise, will be the starting value|
101+
|randomDouble|Make the value random and double, limited by min and max|
102+
|min|For random (integer or double) values defines it's minimum. Otherwise, will be the starting value|
102103
|max|The maximum value generated|
103104
|values|Defines an array of possible values. Example ["on", "off"]|
104105
|customlengthstring|Creates a random string of n bytes. Provide n as parameter|
@@ -110,42 +111,42 @@ Customizable variables can be created with the following properties:
110111
Template:
111112

112113
```json
113-
{ "deviceId": "$.DeviceId", "temp": $.Temp, "Ticks": $.Ticks, "Counter": $.Counter, "time": "$.Time" }
114+
{ "deviceId": "$.DeviceId", "rand_int": $.Temp, "rand_double": $.DoubleValue, "Ticks": $.Ticks, "Counter": $.Counter, "time": "$.Time" }
114115
```
115116

116117
Variables:
117118

118119
```json
119-
[{"name": "Temp", "random": true, "max": 25, "min": 23}, {"name":"Counter", "min":100, "max":102}]
120+
[{"name": "Temp", "random": true, "max": 25, "min": 23}, {"name":"Counter", "min":100, "max":102}, {"name": "DoubleValue", "randomDouble":true, "min":0.22, "max":1.25}]
120121
```
121122

122123
Output:
123124

124125
```json
125-
{ "deviceId": "sim000001", "temp": 23, "Ticks": 637097550115091350, "Counter": 100, "time": "2019-11-19T10:10:11.5091350Z" }
126-
{ "deviceId": "sim000001", "temp": 23, "Ticks": 637097550115952079, "Counter": 101, "time": "2019-11-19T10:10:11.5952079Z" }
127-
{ "deviceId": "sim000001", "temp": 24, "Ticks": 637097550116627320, "Counter": 102, "time": "2019-11-19T10:10:11.6627320Z" }
128-
{ "deviceId": "sim000001", "temp": 24, "Ticks": 637097550117027320, "Counter": 100, "time": "2019-11-19T10:10:11.7027320Z" }
126+
{ "deviceId": "sim000001", "rand_int": 23, "rand_double": 0.207759137669466, "Ticks": 637097550115091350, "Counter": 100, "time": "2019-11-19T10:10:11.5091350Z" }
127+
{ "deviceId": "sim000001", "rand_int": 23, "rand_double": 1.207232427664231, "Ticks": 637097550115952079, "Counter": 101, "time": "2019-11-19T10:10:11.5952079Z" }
128+
{ "deviceId": "sim000001", "rand_int": 24, "rand_double": 0.992871827638167, "Ticks": 637097550116627320, "Counter": 102, "time": "2019-11-19T10:10:11.6627320Z" }
129+
{ "deviceId": "sim000001", "rand_int": 24, "rand_double": 0.779288272162327, "Ticks": 637097550117027320, "Counter": 100, "time": "2019-11-19T10:10:11.7027320Z" }
129130
```
130131

131132
Running with Docker:
132133

133134
```powershell
134-
docker run -it -e "IotHubConnectionString=HostName=your-iothub-name.azure-devices.net;SharedAccessKeyName=device;SharedAccessKey=your-iothub-key" -e Template="{ \"deviceId\": \"$.DeviceId\", \"temp\": $.Temp, \"Ticks\": $.Ticks, \"Counter\": $.Counter, \"time\": \"$.Time\" }" -e Variables="[{name: \"Temp\", \"random\": true, \"max\": 25, \"min\": 23}, {\"name\":\"Counter\", \"min\":100, \"max\":102} ]" mcr.microsoft.com/oss/azure-samples/azureiot-telemetrysimulator
135+
docker run -it -e "IotHubConnectionString=HostName=your-iothub-name.azure-devices.net;SharedAccessKeyName=device;SharedAccessKey=your-iothub-key" -e Template="{ \"deviceId\": \"$.DeviceId\", \"rand_int\": $.Temp, \"rand_double\": $.DoubleValue, \"Ticks\": $.Ticks, \"Counter\": $.Counter, \"time\": \"$.Time\" }" -e Variables="[{name: \"Temp\", \"random\": true, \"max\": 25, \"min\": 23}, {\"name\":\"Counter\", \"min\":100, \"max\":102} ]" mcr.microsoft.com/oss/azure-samples/azureiot-telemetrysimulator
135136
```
136137

137138
calling from PowerShell:
138139

139140
```powershell
140-
docker run -it -e "IotHubConnectionString=HostName=your-iothub-name.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=your-iothub-key" -e Template="{ \"""deviceId\""": \"""$.DeviceId\""", \"""temp\""": $.Temp, \"""Ticks\""": $.Ticks, \"""Counter\""": $.Counter, \"""time\""": \"""$.Time\""", \"""engine\""": \"""$.Engine\""" }" -e Variables="[{name: \"""Temp\""", \"""random\""": true, \"""max\""": 25, \"""min\""": 23}, {\"""name\""":\"""Counter\""", \"""min\""":100, \"""max\""":102}, {name:\"""Engine\""", values: [\"""on\""", \"""off\"""]}]" -e DeviceCount=1 -e MessageCount=3 mcr.microsoft.com/oss/azure-samples/azureiot-telemetrysimulator
141+
docker run -it -e "IotHubConnectionString=HostName=your-iothub-name.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=your-iothub-key" -e Template="{ \"""deviceId\""": \"""$.DeviceId\""", \"""rand_int\""": $.Temp, \"""rand_double\""": $.RandomDouble , \"""Ticks\""": $.Ticks, \"""Counter\""": $.Counter, \"""time\""": \"""$.Time\""", \"""engine\""": \"""$.Engine\""" }" -e Variables="[{name: \"""Temp\""", \"""random\""": true, \"""max\""": 25, \"""min\""": 23}, {\"""name\""":\"""Counter\""", \"""min\""":100, \"""max\""":102}, {name:\"""Engine\""", values: [\"""on\""", \"""off\"""]}]" -e DeviceCount=1 -e MessageCount=3 mcr.microsoft.com/oss/azure-samples/azureiot-telemetrysimulator
141142
```
142143

143144
#### Example 2: Adding the engine status ("on" or "off") to the telemetry
144145

145146
Template:
146147

147148
```json
148-
{ "deviceId": "$.DeviceId", "temp": $.Temp, "Ticks": $.Ticks, "Counter": $.Counter, "time": "$.Time", "engine": "$.Engine" }
149+
{ "deviceId": "$.DeviceId", "rand_int": $.Temp, "Ticks": $.Ticks, "Counter": $.Counter, "time": "$.Time", "engine": "$.Engine" }
149150
```
150151

151152
Variables:
@@ -157,14 +158,14 @@ Variables:
157158
Output:
158159

159160
```json
160-
{ "deviceId": "sim000001", "temp": 23, "Ticks": 637097644549666920, "Counter": 100, "time": "2019-11-19T12:47:34.9666920Z", "engine": "off" }
161-
{ "deviceId": "sim000001", "temp": 24, "Ticks": 637097644550326096, "Counter": 101, "time": "2019-11-19T12:47:35.0326096Z", "engine": "on" }
161+
{ "deviceId": "sim000001", "rand_int": 23, "Ticks": 637097644549666920, "Counter": 100, "time": "2019-11-19T12:47:34.9666920Z", "engine": "off" }
162+
{ "deviceId": "sim000001", "rand_int": 24, "Ticks": 637097644550326096, "Counter": 101, "time": "2019-11-19T12:47:35.0326096Z", "engine": "on" }
162163
```
163164

164165
Running with Docker:
165166

166167
```bash
167-
docker run -it -e "IotHubConnectionString=HostName=your-iothub-name.azure-devices.net;SharedAccessKeyName=device;SharedAccessKey=your-iothub-key" -e Template="{ \"deviceId\": \"$.DeviceId\", \"temp\": $.Temp, \"Ticks\": $.Ticks, \"Counter\": $.Counter, \"time\": \"$.Time\", \"engine\": \"$.Engine\" }" -e Variables="[{name: \"Temp\", \"random\": true, \"max\": 25, \"min\": 23}, {\"name\":\"Counter\", \"min\":100}, {name:\"Engine\", values: [\"on\", \"off\"]}]" mcr.microsoft.com/oss/azure-samples/azureiot-telemetrysimulator
168+
docker run -it -e "IotHubConnectionString=HostName=your-iothub-name.azure-devices.net;SharedAccessKeyName=device;SharedAccessKey=your-iothub-key" -e Template="{ \"deviceId\": \"$.DeviceId\", \"rand_int\": $.Temp, \"Ticks\": $.Ticks, \"Counter\": $.Counter, \"time\": \"$.Time\", \"engine\": \"$.Engine\" }" -e Variables="[{name: \"Temp\", \"random\": true, \"max\": 25, \"min\": 23}, {\"name\":\"Counter\", \"min\":100}, {name:\"Engine\", values: [\"on\", \"off\"]}]" mcr.microsoft.com/oss/azure-samples/azureiot-telemetrysimulator
168169
```
169170

170171
#### Example 3: Using a configuration file to customize simulation

src/IotTelemetrySimulator/DefaultRandomizer.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,15 @@ public int Next(int min, int max)
2222
{
2323
return this.generator.Value.Next(min, max);
2424
}
25+
26+
public double NextDouble()
27+
{
28+
return this.generator.Value.NextDouble();
29+
}
30+
31+
public double NextDouble(double min, double max)
32+
{
33+
return this.generator.Value.NextDouble() * (max - min) + min;
34+
}
2535
}
2636
}

src/IotTelemetrySimulator/IRandomizer.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,9 @@ public interface IRandomizer
77
int Next(int max);
88

99
int Next(int min, int max);
10+
11+
double NextDouble();
12+
13+
double NextDouble(double min, double max);
1014
}
1115
}

src/IotTelemetrySimulator/TelemetryValues.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,24 @@ public Dictionary<string, object> NextValues(Dictionary<string, object> previous
5353
{
5454
if (val.Min.HasValue && val.Max.HasValue && val.Max > val.Min)
5555
{
56-
next[val.Name] = this.random.Next(val.Min.Value, val.Max.Value);
56+
next[val.Name] = this.random.Next((int)val.Min.Value, (int)val.Max.Value);
5757
}
5858
else
5959
{
6060
next[val.Name] = this.random.Next();
6161
}
6262
}
63+
else if (val.RandomDouble)
64+
{
65+
if (val.Min.HasValue && val.Max.HasValue && val.Max > val.Min)
66+
{
67+
next[val.Name] = this.random.NextDouble(val.Min.Value, val.Max.Value);
68+
}
69+
else
70+
{
71+
next[val.Name] = this.random.NextDouble();
72+
}
73+
}
6374
else if (val.CustomLengthString != null)
6475
{
6576
next[val.Name] = this.CreateRandomString(val.CustomLengthString.Value);
@@ -77,8 +88,8 @@ public Dictionary<string, object> NextValues(Dictionary<string, object> previous
7788

7889
switch (prevValue)
7990
{
80-
case int value when value + step > maxThres:
81-
next[val.Name] = val.Min ?? 1;
91+
case int prevIntValue when prevIntValue > maxThres - step:
92+
next[val.Name] = val.Min == null ? 1 : (int)val.Min;
8293
break;
8394

8495
case int prevIntValue:
@@ -88,7 +99,7 @@ public Dictionary<string, object> NextValues(Dictionary<string, object> previous
8899
}
89100
else
90101
{
91-
next[val.Name] = val.Min ?? 1;
102+
next[val.Name] = val.Min == null ? 1 : (int)val.Min;
92103
}
93104
}
94105
}

src/IotTelemetrySimulator/TelemetryVariable.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@ public class TelemetryVariable
1515
[JsonProperty("sequence")]
1616
public bool Sequence { get; set; }
1717

18+
[JsonProperty("randomDouble")]
19+
public bool RandomDouble { get; set; }
20+
1821
[JsonProperty("max")]
19-
public int? Max { get; set; }
22+
public double? Max { get; set; }
2023

2124
[JsonProperty("min")]
22-
public int? Min { get; set; }
25+
public double? Min { get; set; }
2326

2427
[JsonProperty("step")]
2528
public int? Step { get; set; }

test/IotTelemetrySimulator.Test/PayloadGeneratorTest.cs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ public void When_Getting_Payload_Should_Distribute_Correctly()
4747
[InlineData(5, 9, null)]
4848
[InlineData(null, 2, null)]
4949
[InlineData(-3, 2, null)]
50-
public void Counter_With_Threshold_Should_Reset_To_Min(int? min, int? max, int? step)
50+
[InlineData(int.MaxValue - 10, int.MaxValue, 6)]
51+
public void Counter_With_Threshold_Should_Reset_To_Min(double? min, double? max, int? step)
5152
{
5253
var telemetryTemplate = new TelemetryTemplate("{\"val\":\"$.Value\"}", new[] { "Counter" });
5354
var telemetryVariables = new[]
@@ -90,6 +91,57 @@ public void Counter_With_Threshold_Should_Reset_To_Min(int? min, int? max, int?
9091
}
9192
}
9293

94+
[Theory]
95+
[InlineData(null, null)]
96+
[InlineData(null, 15.0)]
97+
[InlineData(10.0, null)]
98+
[InlineData(0.01, 0.02)]
99+
[InlineData(-5, 5)]
100+
public void RandomDouble_Generator(double? min, double? max)
101+
{
102+
var telemetryTemplate = new TelemetryTemplate("{\"val\":\"$.Value\"}", new[] { "Value" });
103+
var telemetryVariables = new[]
104+
{
105+
new TelemetryVariable
106+
{
107+
Name = "Value",
108+
RandomDouble = true,
109+
Min = min,
110+
Max = max
111+
}
112+
};
113+
var telemetryValues = new TelemetryValues(telemetryVariables);
114+
115+
var payload = new TemplatedPayload(100, telemetryTemplate, telemetryValues);
116+
117+
var target = new PayloadGenerator(new[] { payload }, new DefaultRandomizer());
118+
119+
var variables = new Dictionary<string, object>
120+
{
121+
{ Constants.DeviceIdValueName, "mydevice" },
122+
};
123+
124+
if (max == null || min == null)
125+
{
126+
for (int i = 0; i < 10; i++)
127+
{
128+
(_, variables) = target.Generate(null, variables);
129+
variables.TryGetValue("Value", out var o);
130+
Assert.IsType<double>(o);
131+
}
132+
}
133+
else
134+
{
135+
for (int i = 0; i < 10; i++)
136+
{
137+
(_, variables) = target.Generate(null, variables);
138+
variables.TryGetValue("Value", out var o);
139+
var result = Convert.ToDouble(o);
140+
Assert.True(result >= min && result <= max);
141+
}
142+
}
143+
}
144+
93145
[Fact]
94146
public void Sequence_Generator()
95147
{

0 commit comments

Comments
 (0)