diff --git a/sdk-dotnet/LittleHorse.Sdk.Tests/LHLoggerFactoryProviderTest.cs b/sdk-dotnet/LittleHorse.Sdk.Tests/LHLoggerFactoryProviderTest.cs deleted file mode 100644 index e3d79ed78..000000000 --- a/sdk-dotnet/LittleHorse.Sdk.Tests/LHLoggerFactoryProviderTest.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using Microsoft.Extensions.Logging; -using Moq; -using Xunit; - -namespace LittleHorse.Sdk.Tests.Internal -{ - public class LHLoggerFactoryProviderTest - { - [Fact] - public void Initialize_WithCustomLoggerFactory_ShouldCreateLogger() - { - var mockLoggerFactory = new Mock(); - - LHLoggerFactoryProvider.Initialize(mockLoggerFactory.Object); - var logger = LHLoggerFactoryProvider.GetLogger(); - - Assert.NotNull(logger); - Assert.IsAssignableFrom>(logger); - } - - [Fact] - public void Initialize_WithoutLoggerFactory_ShouldAVoidWritingLogs() - { - LHLoggerFactoryProvider.Initialize(); - var logger = LHLoggerFactoryProvider.GetLogger(); - logger.LogInformation("This log should not be printed."); - - Assert.NotNull(logger); - } - - [Fact] - public void GetLogger_WithoutInitialize_ShouldThrowInvalidOperationException() - { - var exception = Assert.Throws(() => LHLoggerFactoryProvider.GetLogger()); - - Assert.Equal("_loggerFactory does not have a valid value and it is trying to create a logger instance.", exception.Message); - } - } -} diff --git a/sdk-dotnet/LittleHorse.Sdk.Tests/LHTaskSignatureTest.cs b/sdk-dotnet/LittleHorse.Sdk.Tests/LHTaskSignatureTest.cs index ad7137284..2fc89b565 100644 --- a/sdk-dotnet/LittleHorse.Sdk.Tests/LHTaskSignatureTest.cs +++ b/sdk-dotnet/LittleHorse.Sdk.Tests/LHTaskSignatureTest.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using LittleHorse.Common.Proto; +using LittleHorse.Sdk; using LittleHorse.Sdk.Exceptions; using LittleHorse.Sdk.Worker; using LittleHorse.Sdk.Worker.Internal; @@ -20,6 +21,11 @@ public class LHTaskSignatureTest const string DETAIL_ATTR_NAME = "detail"; const string TELEPHONE_ATTR_NAME = "telephone"; + public LHTaskSignatureTest() + { + LHLoggerFactoryProvider.Initialize(null); + } + [Fact] public void TaskSignature_WithLHTaskMethodAndLHTypeAttributes_ShouldBuildLHSignatureWithInputAndOutput() { diff --git a/sdk-dotnet/LittleHorse.Sdk.Tests/TestClasses.cs b/sdk-dotnet/LittleHorse.Sdk.Tests/TestClasses.cs index 6ec3afe4e..c5510365f 100644 --- a/sdk-dotnet/LittleHorse.Sdk.Tests/TestClasses.cs +++ b/sdk-dotnet/LittleHorse.Sdk.Tests/TestClasses.cs @@ -10,7 +10,7 @@ public class Car public class Person { - public string FirstName { get; set; } + public string? FirstName { get; set; } public int Age { get; set; } - public List Cars { get; set; } + public List? Cars { get; set; } } \ No newline at end of file diff --git a/sdk-dotnet/LittleHorse.Sdk.Tests/Utils/JsonHandlerTest.cs b/sdk-dotnet/LittleHorse.Sdk.Tests/Utils/JsonHandlerTest.cs index 436a71f0a..a9370eb26 100644 --- a/sdk-dotnet/LittleHorse.Sdk.Tests/Utils/JsonHandlerTest.cs +++ b/sdk-dotnet/LittleHorse.Sdk.Tests/Utils/JsonHandlerTest.cs @@ -26,11 +26,11 @@ public void JsonHandler_WithJsonString_ShouldReturnCustomObject() var result = JsonHandler.DeserializeFromJson(jsonString, typeof(Person)); - var actual = (Person) result; + var actual = (Person) result!; Assert.Equal("Test", actual.FirstName); Assert.Equal(35, actual.Age); - Assert.Equal(1, actual.Cars[0].Id); + Assert.Equal(1, actual.Cars![0].Id); Assert.Equal(134.45E-2f, actual.Cars[0].Cost); } } diff --git a/sdk-dotnet/LittleHorse.Sdk.Tests/Worker/VariableMappingTest.cs b/sdk-dotnet/LittleHorse.Sdk.Tests/Worker/VariableMappingTest.cs new file mode 100644 index 000000000..0e664e5f4 --- /dev/null +++ b/sdk-dotnet/LittleHorse.Sdk.Tests/Worker/VariableMappingTest.cs @@ -0,0 +1,336 @@ +using System; +using System.Collections.Generic; +using Google.Protobuf; +using Type = System.Type; +using LittleHorse.Common.Proto; +using LittleHorse.Sdk.Exceptions; +using LittleHorse.Sdk.Helper; +using LittleHorse.Sdk.Worker; +using Moq; +using Newtonsoft.Json; +using Xunit; + +namespace LittleHorse.Sdk.Tests.Worker; + +public class VariableMappingTest +{ + public VariableMappingTest() + { + LHLoggerFactoryProvider.Initialize(null); + } + + [Fact] + public void VariableMapping_WithValidLHTypes_ShouldBeBuiltSuccessfully() + { + int position = 0; + string paramName = "param_test"; + + var testAllowedTypes = new List() + { + typeof(Int64), typeof(Int32), typeof(Int16) + , typeof(UInt16), typeof(UInt32), typeof(UInt64) + , typeof(sbyte), typeof(byte), typeof(short), typeof(ushort) + , typeof(int), typeof(uint), typeof(long) + , typeof(ulong), typeof(nint), typeof(nuint), typeof(float), typeof(double) + , typeof(String), typeof(bool), typeof(byte[]), typeof(List) + , typeof(List), typeof(List), typeof(List) + }; + + foreach (var type in testAllowedTypes) + { + var variableType = LHMappingHelper.MapDotNetTypeToLHVariableType(type); + TaskDef taskDef = getTaskDefForTest(variableType); + + var result = new VariableMapping(taskDef, position, type, paramName); + + Assert.True(result is not null); + } + } + + [Fact] + public void VariableMapping_WithMismatchTypesInt_ShouldThrowException() + { + Type type1 = typeof(Int64); + Type type2 = typeof(string); + var variableType = LHMappingHelper.MapDotNetTypeToLHVariableType(type1); + TaskDef taskDef = getTaskDefForTest(variableType); + + var exception = Assert.Throws( + () => new VariableMapping(taskDef, 0, type2, "any param name")); + + Assert.Contains($"TaskDef provides INT, func accepts", exception.Message); + } + + [Fact] + public void VariableMapping_WithMismatchTypeDouble_ShouldThrowException() + { + Type type1 = typeof(double); + Type type2 = typeof(Int64); + var variableType = LHMappingHelper.MapDotNetTypeToLHVariableType(type1); + TaskDef taskDef = getTaskDefForTest(variableType); + + var exception = Assert.Throws( + () => new VariableMapping(taskDef, 0, type2, "any param name")); + + Assert.Contains($"TaskDef provides DOUBLE, func accepts", exception.Message); + } + + [Fact] + public void VariableMapping_WithMismatchTypeString_ShouldThrowException() + { + Type type1 = typeof(string); + Type type2 = typeof(double); + var variableType = LHMappingHelper.MapDotNetTypeToLHVariableType(type1); + TaskDef taskDef = getTaskDefForTest(variableType); + + var exception = Assert.Throws( + () => new VariableMapping(taskDef, 0, type2, "any param name")); + + Assert.Contains($"TaskDef provides STRING, func accepts", exception.Message); + } + + [Fact] + public void VariableMapping_WithMismatchTypeBool_ShouldThrowException() + { + Type type1 = typeof(bool); + Type type2 = typeof(string); + var variableType = LHMappingHelper.MapDotNetTypeToLHVariableType(type1); + TaskDef taskDef = getTaskDefForTest(variableType); + + var exception = Assert.Throws( + () => new VariableMapping(taskDef, 0, type2, "any param name")); + + Assert.Contains($"TaskDef provides BOOL, func accepts", exception.Message); + } + + [Fact] + public void VariableMapping_WithMismatchTypeBytes_ShouldThrowException() + { + Type type1 = typeof(byte[]); + Type type2 = typeof(string); + var variableType = LHMappingHelper.MapDotNetTypeToLHVariableType(type1); + TaskDef taskDef = getTaskDefForTest(variableType); + + var exception = Assert.Throws( + () => new VariableMapping(taskDef, 0, type2, "any param name")); + + Assert.Contains($"TaskDef provides BYTES, func accepts", exception.Message); + } + + [Fact] + public void VariableMapping_WithAssignIntValue_ShouldReturnInt32Object() + { + int expectedValue = 29; + var testAllowedTypes = new List() { typeof(Int32), typeof(Int16) + , typeof(UInt16), typeof(UInt32) + , typeof(sbyte), typeof(byte), typeof(short), typeof(ushort) + , typeof(int), typeof(uint) + , typeof(nint), typeof(nuint)}; + + int position = 0; + string paramName = "param_test"; + + foreach (var type in testAllowedTypes) + { + var variableMapping = getVariableMappingForTest(type, paramName, position); + VariableValue variableValue = new VariableValue {Int = expectedValue}; + ScheduledTask taskInstance = getScheduledTaskForTest(variableValue, paramName); + var mockWorkerContext = new Mock(taskInstance, new DateTime()); + + var result = variableMapping.Assign(taskInstance, mockWorkerContext.Object); + + Assert.Equal((int) taskInstance.Variables[0].Value.Int, result); + } + } + + [Fact] + public void VariableMapping_WithAssignLongValue_ShouldReturnInt64Object() + { + int expectedValue = 29; + var testAllowedTypes = new List() { typeof(Int64), typeof(UInt64), typeof(long), typeof(ulong)}; + + int position = 0; + string paramName = "param_test"; + + foreach (var type in testAllowedTypes) + { + var variableMapping = getVariableMappingForTest(type, paramName, position); + VariableValue variableValue = new VariableValue {Int = expectedValue}; + ScheduledTask taskInstance = getScheduledTaskForTest(variableValue, paramName); + var mockWorkerContext = new Mock(taskInstance, new DateTime()); + + var result = variableMapping.Assign(taskInstance, mockWorkerContext.Object); + + Assert.Equal(taskInstance.Variables[0].Value.Int, result); + } + } + + [Fact] + public void VariableMapping_WithAssignDoubleValue_ShouldReturnDoubleObject() + { + float expectedValue = 3_000.5F; + var testAllowedTypes = new List() { typeof(double), typeof(Double)}; + + int position = 0; + string paramName = "param_test"; + + foreach (var type in testAllowedTypes) + { + var variableMapping = getVariableMappingForTest(type, paramName, position); + VariableValue variableValue = new VariableValue {Double = expectedValue}; + ScheduledTask taskInstance = getScheduledTaskForTest(variableValue, paramName); + var mockWorkerContext = new Mock(taskInstance, new DateTime()); + + var result = variableMapping.Assign(taskInstance, mockWorkerContext.Object); + + Assert.Equal(taskInstance.Variables[0].Value.Double, result); + } + } + + [Fact] + public void VariableMapping_WithAssignDoubleValue_ShouldReturnFloatObject() + { + float expectedValue = 3_000.5F; + var type = typeof(float); + + int position = 0; + string paramName = "param_test"; + + var variableMapping = getVariableMappingForTest(type, paramName, position); + VariableValue variableValue = new VariableValue {Double = expectedValue}; + ScheduledTask taskInstance = getScheduledTaskForTest(variableValue, paramName); + var mockWorkerContext = new Mock(taskInstance, new DateTime()); + + var result = variableMapping.Assign(taskInstance, mockWorkerContext.Object); + + Assert.Equal((float) taskInstance.Variables[0].Value.Double, result); + } + + [Fact] + public void VariableMapping_WithAssignStringValue_ShouldReturnStrObject() + { + Type type = typeof(string); + int position = 0; + string paramName = "param_test"; + var variableMapping = getVariableMappingForTest(type, paramName, position); + VariableValue variableValue = new VariableValue { Str = "param_value_test"}; + ScheduledTask taskInstance = getScheduledTaskForTest(variableValue, paramName); + var mockWorkerContext = new Mock(taskInstance, new DateTime()); + + var result = variableMapping.Assign(taskInstance, mockWorkerContext.Object); + + Assert.Equal(taskInstance.Variables[0].Value.Str, result); + } + + [Fact] + public void VariableMapping_WithAssignBytesValue_ShouldReturnBytesObject() + { + byte[] expectedValue = new byte[] { 0x20, 0x20, 0x20 }; + ByteString byteString = ByteString.CopyFrom(expectedValue); + Type type = typeof(byte[]); + int position = 0; + string paramName = "param_test"; + var variableMapping = getVariableMappingForTest(type, paramName, position); + VariableValue variableValue = new VariableValue { Bytes = byteString}; + ScheduledTask taskInstance = getScheduledTaskForTest(variableValue, paramName); + var mockWorkerContext = new Mock(taskInstance, new DateTime()); + + var result = variableMapping.Assign(taskInstance, mockWorkerContext.Object); + + Assert.Equal(taskInstance.Variables[0].Value.Bytes, result); + } + + [Fact] + public void VariableMapping_WithAssignBoolValue_ShouldReturnBoolObject() + { + bool expectedValue = false; + Type type = typeof(bool); + int position = 0; + string paramName = "param_test"; + var variableMapping = getVariableMappingForTest(type, paramName, position); + VariableValue variableValue = new VariableValue { Bool = expectedValue}; + ScheduledTask taskInstance = getScheduledTaskForTest(variableValue, paramName); + var mockWorkerContext = new Mock(taskInstance, new DateTime()); + + var result = variableMapping.Assign(taskInstance, mockWorkerContext.Object); + + Assert.Equal(taskInstance.Variables[0].Value.Bool, result); + } + + [Fact] + public void VariableMapping_WithAssignArrayObjectValue_ShouldReturnArrayObject() + { + string value = "[{\"FirstName\":\"Test\",\"Age\":35,\"Cars\":[{\"Id\":1,\"Cost\":1.3445}]}]"; + Type type = typeof(List); + int position = 0; + string paramName = "param_test"; + var variableMapping = getVariableMappingForTest(type, paramName, position); + VariableValue variableValue = new VariableValue { JsonArr = value}; + ScheduledTask taskInstance = getScheduledTaskForTest(variableValue, paramName); + var mockWorkerContext = new Mock(taskInstance, new DateTime()); + + var result = variableMapping.Assign(taskInstance, mockWorkerContext.Object); + + var expectedList = (List)JsonConvert.DeserializeObject(value, type)!; + var actualList = (List)result!; + + Assert.Equal(expectedList.Count, actualList.Count); + Assert.Equal(expectedList[0].FirstName, actualList[0].FirstName); + Assert.Equal(expectedList[0].Age, actualList[0].Age); + Assert.Equal(expectedList[0].Cars!.Count, actualList[0].Cars!.Count); + } + + [Fact] + public void VariableMapping_WithAssignJsonStringValue_ShouldReturnCustomObject() + { + string value = "{\"FirstName\":\"Test\",\"Age\":35,\"Cars\":[{\"Id\":1,\"Cost\":1.3445}]}"; + Type type = typeof(Person); + int position = 0; + string paramName = "param_test"; + var variableMapping = getVariableMappingForTest(type, paramName, position); + VariableValue variableValue = new VariableValue { JsonObj = value}; + ScheduledTask taskInstance = getScheduledTaskForTest(variableValue, paramName); + var mockWorkerContext = new Mock(taskInstance, new DateTime()); + + var result = variableMapping.Assign(taskInstance, mockWorkerContext.Object); + + var expectedObject = (Person)JsonConvert.DeserializeObject(value, type)!; + var actualObject = (Person)result!; + + Assert.Equal(expectedObject.FirstName, actualObject.FirstName); + Assert.Equal(expectedObject.Age, actualObject.Age); + Assert.Equal(expectedObject.Cars!.Count, actualObject.Cars!.Count); + } + + private TaskDef getTaskDefForTest(VariableType type) + { + var inputVar = new VariableDef(); + inputVar.Type = type; + TaskDef taskDef = new TaskDef(); + TaskDefId taskDefId = new TaskDefId(); + taskDef.Id = taskDefId; + taskDef.InputVars.Add(inputVar); + + return taskDef; + } + + private VariableMapping getVariableMappingForTest(Type type, string paramName, int position) + { + var variableType = LHMappingHelper.MapDotNetTypeToLHVariableType(type); + TaskDef taskDef = getTaskDefForTest(variableType); + + var variableMapping = new VariableMapping(taskDef, position, type, paramName); + + return variableMapping; + } + + private ScheduledTask getScheduledTaskForTest(VariableValue variableValue, string variableName) + { + ScheduledTask scheduledTask = new ScheduledTask(); + List variables = new List(); + variables.Add(new VarNameAndVal {VarName = variableName, Value = variableValue, Masked = true}); + scheduledTask.Variables.Add(variables); + + return scheduledTask; + } +} \ No newline at end of file diff --git a/sdk-dotnet/LittleHorse.Sdk/Helper/LHMappingHelper.cs b/sdk-dotnet/LittleHorse.Sdk/Helper/LHMappingHelper.cs index 192709545..118be46cf 100644 --- a/sdk-dotnet/LittleHorse.Sdk/Helper/LHMappingHelper.cs +++ b/sdk-dotnet/LittleHorse.Sdk/Helper/LHMappingHelper.cs @@ -203,5 +203,13 @@ private static Double GetFloatingValue(object obj) _ => throw new LHInputVarSubstitutionException("Object value can not be converted to a Double.") }; } + + public static bool isInt64Type(Type type) + { + return type.IsAssignableFrom(typeof(Int64)) + || type.IsAssignableFrom(typeof(UInt64)) + || type.IsAssignableFrom(typeof(long)) + || type.IsAssignableFrom(typeof(ulong)); + } } } diff --git a/sdk-dotnet/LittleHorse.Sdk/Worker/LHTaskSignature.cs b/sdk-dotnet/LittleHorse.Sdk/Worker/LHTaskSignature.cs index 8807042ac..ba3ead229 100644 --- a/sdk-dotnet/LittleHorse.Sdk/Worker/LHTaskSignature.cs +++ b/sdk-dotnet/LittleHorse.Sdk/Worker/LHTaskSignature.cs @@ -24,7 +24,7 @@ public class LHTaskSignature public LHTaskSignature(string taskDefName, T executable) { - _logger = new LoggerFactory().CreateLogger>(); + _logger = LHLoggerFactoryProvider.GetLogger>(); _lhMethodParams = new List(); TaskDefName = taskDefName; Executable = executable; diff --git a/sdk-dotnet/LittleHorse.Sdk/Worker/VariableMapping.cs b/sdk-dotnet/LittleHorse.Sdk/Worker/VariableMapping.cs index a557fe683..36514461b 100644 --- a/sdk-dotnet/LittleHorse.Sdk/Worker/VariableMapping.cs +++ b/sdk-dotnet/LittleHorse.Sdk/Worker/VariableMapping.cs @@ -8,7 +8,7 @@ namespace LittleHorse.Sdk.Worker { public class VariableMapping { - private ILogger? _logger; + private ILogger? _logger; private string? _name; private Type _type; private int _position; @@ -45,19 +45,19 @@ public VariableMapping(TaskDef taskDef, int position, Type type, string? paramNa switch (val.ValueCase) { case VariableValue.ValueOneofCase.Int: - if (_type == typeof(long) || _type == typeof(long?)) + if (LHMappingHelper.isInt64Type(_type)) { return val.Int; } - return (int)val.Int; + return (int) val.Int; case VariableValue.ValueOneofCase.Double: - if (_type == typeof(double) || _type == typeof(double?)) + if (_type == typeof(double) || _type == typeof(Double)) { return val.Double; } - return (float)val.Double; + return (float) val.Double; case VariableValue.ValueOneofCase.Str: return val.Str; case VariableValue.ValueOneofCase.Bytes: