From c9fd46907d0c4a700796d360226bbc28fa0ea340 Mon Sep 17 00:00:00 2001 From: Mauro Antonio Sanz Date: Wed, 11 Feb 2026 09:49:19 -0300 Subject: [PATCH 1/6] create DTO --- .../Cache/Classes/RedisImpressionsCache.cs | 7 +- src/Splitio/Domain/KeyImpressionDTO.cs | 71 +++++++++++++++++++ .../Classes/ImpressionsSdkApiClient.cs | 11 +-- 3 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 src/Splitio/Domain/KeyImpressionDTO.cs diff --git a/Splitio.Redis/Services/Cache/Classes/RedisImpressionsCache.cs b/Splitio.Redis/Services/Cache/Classes/RedisImpressionsCache.cs index 28339d4a..bce71ca8 100644 --- a/Splitio.Redis/Services/Cache/Classes/RedisImpressionsCache.cs +++ b/Splitio.Redis/Services/Cache/Classes/RedisImpressionsCache.cs @@ -80,11 +80,8 @@ public async Task RecordImpressionsCountAsync(Dictionary impression private RedisValue[] GetImpressions(IList items) { - var impressions = items.Select(item => JsonConvertWrapper.SerializeObject(new - { - m = new { s = SdkVersion, i = MachineIp, n = MachineName }, - i = new { k = item.keyName, b = item.bucketingKey, f = item.feature, t = item.treatment, r = item.label, c = item.changeNumber, m = item.time, pt = item.previousTime } - })); + var impressions = items + .Select(item => JsonConvertWrapper.SerializeObject(new KeyImpressionDTO(item, SdkVersion, MachineIp, MachineName))); return impressions .Select(i => (RedisValue)i) diff --git a/src/Splitio/Domain/KeyImpressionDTO.cs b/src/Splitio/Domain/KeyImpressionDTO.cs new file mode 100644 index 00000000..24df5cf0 --- /dev/null +++ b/src/Splitio/Domain/KeyImpressionDTO.cs @@ -0,0 +1,71 @@ +using Newtonsoft.Json; + +namespace Splitio.Domain +{ + public class KeyImpressionMetadataDTO + { + [JsonProperty("s")] + private readonly string _sdkVersion; + [JsonProperty("i")] + private readonly string _machineIp; + [JsonProperty("n")] + private readonly string _machineName; + + public KeyImpressionMetadataDTO(string sdkVersion, string machineIp, string machineName) + { + _sdkVersion = sdkVersion; + _machineIp = machineIp; + _machineName = machineName; + } + } + + public class KeyImpressionItemDTO + { + [JsonProperty("f")] + private readonly string _feature; + [JsonProperty("k")] + private readonly string _keyName; + [JsonProperty("t")] + private readonly string _treatment; + [JsonProperty("m")] + private readonly long _time; + [JsonProperty("c")] + private readonly long? _changeNumber; + [JsonProperty("r")] + private readonly string _label; + [JsonProperty("b")] + private readonly string _bucketingKey; + [JsonProperty("pt")] + private readonly long? _previousTime; + + [JsonProperty(PropertyName = "properties", NullValueHandling = NullValueHandling.Ignore)] + private readonly string _properties; + + public KeyImpressionItemDTO(KeyImpression impression) + { + _feature = impression.feature; + _keyName = impression.keyName; + _treatment = impression.treatment; + _time = impression.time; + _changeNumber = impression.changeNumber; + _label = impression.label; + _bucketingKey = impression.bucketingKey; + _previousTime = impression.previousTime; + _properties = impression.properties; + } + } + + public class KeyImpressionDTO + { + [JsonProperty("m")] + private readonly KeyImpressionMetadataDTO _metadata; + [JsonProperty("i")] + private readonly KeyImpressionItemDTO _item; + + public KeyImpressionDTO(KeyImpression impression, string sdkVersion, string machineIp, string machineName) + { + _metadata = new KeyImpressionMetadataDTO(sdkVersion, machineIp, machineName); + _item = new KeyImpressionItemDTO(impression); + } + } +} \ No newline at end of file diff --git a/src/Splitio/Services/Impressions/Classes/ImpressionsSdkApiClient.cs b/src/Splitio/Services/Impressions/Classes/ImpressionsSdkApiClient.cs index 9c75c3d2..4d630448 100644 --- a/src/Splitio/Services/Impressions/Classes/ImpressionsSdkApiClient.cs +++ b/src/Splitio/Services/Impressions/Classes/ImpressionsSdkApiClient.cs @@ -81,16 +81,7 @@ public static string ConvertToJson(List impressions) .Select(group => new { f = group.Key, - i = group.Select(x => new - { - k = x.keyName, - t = x.treatment, - m = x.time, - c = x.changeNumber, - r = x.label, - b = x.bucketingKey, - properties = x.properties - }) + i = group.Select(x => new KeyImpressionItemDTO(x)) }); return JsonConvertWrapper.SerializeObjectIgnoreNullValue(impressionsPerFeature); } From 595f11dc6424ae529c4b7232dd0ee073da297457 Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Wed, 11 Feb 2026 06:03:02 -0800 Subject: [PATCH 2/6] undo changes --- .../Impressions/Classes/ImpressionsSdkApiClient.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Splitio/Services/Impressions/Classes/ImpressionsSdkApiClient.cs b/src/Splitio/Services/Impressions/Classes/ImpressionsSdkApiClient.cs index 4d630448..b5bef285 100644 --- a/src/Splitio/Services/Impressions/Classes/ImpressionsSdkApiClient.cs +++ b/src/Splitio/Services/Impressions/Classes/ImpressionsSdkApiClient.cs @@ -81,8 +81,18 @@ public static string ConvertToJson(List impressions) .Select(group => new { f = group.Key, - i = group.Select(x => new KeyImpressionItemDTO(x)) + i = group.Select(x => new + { + k = x.keyName, + t = x.treatment, + m = x.time, + c = x.changeNumber, + r = x.label, + b = x.bucketingKey, + properties = x.properties + }) }); + return JsonConvertWrapper.SerializeObjectIgnoreNullValue(impressionsPerFeature); } From 13f02d9640bae12e1ac3c022923505b506ef2d94 Mon Sep 17 00:00:00 2001 From: Mauro Antonio Sanz Date: Wed, 11 Feb 2026 11:06:59 -0300 Subject: [PATCH 3/6] update version --- Splitio.Redis/Splitio.Redis.csproj | 2 +- src/Splitio/Splitio.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Splitio.Redis/Splitio.Redis.csproj b/Splitio.Redis/Splitio.Redis.csproj index 23a3ee68..b1790d52 100644 --- a/Splitio.Redis/Splitio.Redis.csproj +++ b/Splitio.Redis/Splitio.Redis.csproj @@ -7,7 +7,7 @@ false false false - 7.12.0 + 7.12.1-rc.1 true SplitioRedis.snk Apache-2.0 diff --git a/src/Splitio/Splitio.csproj b/src/Splitio/Splitio.csproj index f7d09149..47f9bcae 100644 --- a/src/Splitio/Splitio.csproj +++ b/src/Splitio/Splitio.csproj @@ -7,7 +7,7 @@ false false false - 7.12.0 + 7.12.1-rc.1 Splitio true Splitio.snk From a2789c8e55d5328d83bcecad9c903a7cdc6e6228 Mon Sep 17 00:00:00 2001 From: Mauro Antonio Sanz Date: Wed, 11 Feb 2026 11:19:43 -0300 Subject: [PATCH 4/6] fixing sonar --- .../Cache/Classes/RedisImpressionsCache.cs | 2 +- src/Splitio/Domain/KeyImpressionDTO.cs | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Splitio.Redis/Services/Cache/Classes/RedisImpressionsCache.cs b/Splitio.Redis/Services/Cache/Classes/RedisImpressionsCache.cs index bce71ca8..da0cf8d7 100644 --- a/Splitio.Redis/Services/Cache/Classes/RedisImpressionsCache.cs +++ b/Splitio.Redis/Services/Cache/Classes/RedisImpressionsCache.cs @@ -81,7 +81,7 @@ public async Task RecordImpressionsCountAsync(Dictionary impression private RedisValue[] GetImpressions(IList items) { var impressions = items - .Select(item => JsonConvertWrapper.SerializeObject(new KeyImpressionDTO(item, SdkVersion, MachineIp, MachineName))); + .Select(item => JsonConvertWrapper.SerializeObject(new KeyImpressionDto(item, SdkVersion, MachineIp, MachineName))); return impressions .Select(i => (RedisValue)i) diff --git a/src/Splitio/Domain/KeyImpressionDTO.cs b/src/Splitio/Domain/KeyImpressionDTO.cs index 24df5cf0..32c6f592 100644 --- a/src/Splitio/Domain/KeyImpressionDTO.cs +++ b/src/Splitio/Domain/KeyImpressionDTO.cs @@ -2,7 +2,7 @@ namespace Splitio.Domain { - public class KeyImpressionMetadataDTO + public class KeyImpressionMetadataDto { [JsonProperty("s")] private readonly string _sdkVersion; @@ -11,7 +11,7 @@ public class KeyImpressionMetadataDTO [JsonProperty("n")] private readonly string _machineName; - public KeyImpressionMetadataDTO(string sdkVersion, string machineIp, string machineName) + public KeyImpressionMetadataDto(string sdkVersion, string machineIp, string machineName) { _sdkVersion = sdkVersion; _machineIp = machineIp; @@ -19,7 +19,7 @@ public KeyImpressionMetadataDTO(string sdkVersion, string machineIp, string mach } } - public class KeyImpressionItemDTO + public class KeyImpressionItemDto { [JsonProperty("f")] private readonly string _feature; @@ -41,7 +41,7 @@ public class KeyImpressionItemDTO [JsonProperty(PropertyName = "properties", NullValueHandling = NullValueHandling.Ignore)] private readonly string _properties; - public KeyImpressionItemDTO(KeyImpression impression) + public KeyImpressionItemDto(KeyImpression impression) { _feature = impression.feature; _keyName = impression.keyName; @@ -55,17 +55,17 @@ public KeyImpressionItemDTO(KeyImpression impression) } } - public class KeyImpressionDTO + public class KeyImpressionDto { [JsonProperty("m")] - private readonly KeyImpressionMetadataDTO _metadata; + private readonly KeyImpressionMetadataDto _metadata; [JsonProperty("i")] - private readonly KeyImpressionItemDTO _item; + private readonly KeyImpressionItemDto _item; - public KeyImpressionDTO(KeyImpression impression, string sdkVersion, string machineIp, string machineName) + public KeyImpressionDto(KeyImpression impression, string sdkVersion, string machineIp, string machineName) { - _metadata = new KeyImpressionMetadataDTO(sdkVersion, machineIp, machineName); - _item = new KeyImpressionItemDTO(impression); + _metadata = new KeyImpressionMetadataDto(sdkVersion, machineIp, machineName); + _item = new KeyImpressionItemDto(impression); } } } \ No newline at end of file From ddfb0fb9b295650ea566f2594875d9e52bae8423 Mon Sep 17 00:00:00 2001 From: Mauro Antonio Sanz Date: Wed, 11 Feb 2026 11:33:48 -0300 Subject: [PATCH 5/6] fix pipe --- .harness/pipeline.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.harness/pipeline.yaml b/.harness/pipeline.yaml index 83dee830..37fe51f9 100644 --- a/.harness/pipeline.yaml +++ b/.harness/pipeline.yaml @@ -75,7 +75,7 @@ pipeline: $env:PATH = "C:\dotnet;C:\dotnet\tools;$env:PATH" dotnet-sonarscanner begin ` /k:"dotnet-client" ` - /d:sonar.host.url="https://sonar.harness.io/" ` + /d:sonar.host.url="https://sonar.harness.io" ` /d:sonar.token="<+secrets.getValue("sonarqube-token")>" ` /d:sonar.cs.opencover.reportsPaths="**/coverage.opencover.xml" ` /d:sonar.coverage.exclusions="**/*Tests*/**,**/bin/**,**/obj/**" ` @@ -268,7 +268,7 @@ pipeline: -CommitSha "<+codebase.commitSha>" ` -SonarProjectKey "dotnet-client" ` -SonarToken "<+secrets.getValue('sonarqube-token')>" ` - -SonarUrl "https://sonar.harness.io/" + -SonarUrl "https://sonar.harness.io" - parallel: - step: type: Run From 9c153ee00c2765a503ca802906269112df503188 Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Wed, 11 Feb 2026 07:47:36 -0800 Subject: [PATCH 6/6] adding tests --- src/Splitio/Domain/KeyImpression.cs | 3 +- .../Impressions/RedisImpressionsCacheTests.cs | 39 ++++++++++++++++--- .../Impressions/RedisImpressionsCacheTests.cs | 22 +++++++++++ 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/Splitio/Domain/KeyImpression.cs b/src/Splitio/Domain/KeyImpression.cs index a64c16dd..23bb2b48 100644 --- a/src/Splitio/Domain/KeyImpression.cs +++ b/src/Splitio/Domain/KeyImpression.cs @@ -6,7 +6,7 @@ public class KeyImpression { public KeyImpression() { } - public KeyImpression(string matchingKey, string feature, string treatment, long time, long? changeNumber, string label, string bucketingKey, bool impressionsDisabled, long? previousTime = null, bool optimized = false) + public KeyImpression(string matchingKey, string feature, string treatment, long time, long? changeNumber, string label, string bucketingKey, bool impressionsDisabled, long? previousTime = null, bool optimized = false, string properties = null) { this.feature = feature; keyName = matchingKey; @@ -18,6 +18,7 @@ public KeyImpression(string matchingKey, string feature, string treatment, long this.previousTime = previousTime; ImpressionsDisabled = impressionsDisabled; this.optimized = optimized; + this.properties = properties; } [JsonIgnore] diff --git a/tests/Splitio-tests/Integration Tests/Impressions/RedisImpressionsCacheTests.cs b/tests/Splitio-tests/Integration Tests/Impressions/RedisImpressionsCacheTests.cs index 522b2a91..7ef3094c 100644 --- a/tests/Splitio-tests/Integration Tests/Impressions/RedisImpressionsCacheTests.cs +++ b/tests/Splitio-tests/Integration Tests/Impressions/RedisImpressionsCacheTests.cs @@ -1,10 +1,12 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Splitio.Domain; using Splitio.Redis.Services.Cache.Classes; using Splitio.Redis.Services.Cache.Interfaces; using Splitio.Redis.Services.Domain; using Splitio.Telemetry.Domain; using Splitio.Tests.Common.Resources; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace Splitio_Tests.Integration_Tests.Impressions @@ -94,36 +96,61 @@ await impressionsCache.RecordUniqueKeysAsync(new List Clean(); } - private static RedisAdapterForTests GetRedisClusterAdapter() + [TestMethod] + public async Task RecordImpressionWithProperties() + { + // Arrange. + var cache = GetRedisClusterImpressionsCache("Prop-Test:"); + var impressions = new List + { + new KeyImpression("matching-key", "feature-1", "treatment", 34534546, 3333444, "label", "bucketing-key", false), + new KeyImpression("matching-key", "feature-1", "treatment", 34534550, 3333444, "label", "bucketing-key", false, 34534546), + new KeyImpression("matching-key", "feature-2", "treatment", 34534546, 3333444, "label", "bucketing-key", false, properties: "{\"prop\":\"val\"}"), + }; + + // Act. + await _impressionsCache.AddAsync(impressions); + var result = await _redisAdapter.ListRangeAsync("test-mtks:.SPLITIO.impressions"); + + // Assert. + Assert.AreEqual(3, result.Count()); + Assert.AreEqual("{\"m\":{\"s\":\"version\",\"i\":\"ip\",\"n\":\"mm\"},\"i\":{\"f\":\"feature-1\",\"k\":\"matching-key\",\"t\":\"treatment\",\"m\":34534546,\"c\":3333444,\"r\":\"label\",\"b\":\"bucketing-key\",\"pt\":null}}", result[0].ToString()); + Assert.AreEqual("{\"m\":{\"s\":\"version\",\"i\":\"ip\",\"n\":\"mm\"},\"i\":{\"f\":\"feature-1\",\"k\":\"matching-key\",\"t\":\"treatment\",\"m\":34534550,\"c\":3333444,\"r\":\"label\",\"b\":\"bucketing-key\",\"pt\":34534546}}", result[1].ToString()); + Assert.AreEqual("{\"m\":{\"s\":\"version\",\"i\":\"ip\",\"n\":\"mm\"},\"i\":{\"f\":\"feature-2\",\"k\":\"matching-key\",\"t\":\"treatment\",\"m\":34534546,\"c\":3333444,\"r\":\"label\",\"b\":\"bucketing-key\",\"pt\":null,\"properties\":\"{\\\"prop\\\":\\\"val\\\"}\"}}", result[2].ToString()); + + Clean(); + } + + private static RedisAdapterForTests GetRedisClusterAdapter(string prefix = null) { var config = new RedisConfig { - ClusterNodes = new Splitio.Domain.ClusterNodes( new List() { "localhost:6379" }, "{SPLITIO}"), + ClusterNodes = new ClusterNodes( new List() { "localhost:6379" }, "{SPLITIO}"), RedisPassword = "", RedisDatabase = 0, RedisConnectTimeout = 1000, RedisConnectRetry = 5, RedisSyncTimeout = 1000, PoolSize = 1, - RedisUserPrefix = RedisPrefix + RedisUserPrefix = prefix ?? RedisPrefix }; var pool = new ConnectionPoolManager(config); return new RedisAdapterForTests(config, pool); } - private static RedisImpressionsCache GetRedisClusterImpressionsCache() + private static RedisImpressionsCache GetRedisClusterImpressionsCache(string prefix = null) { var config = new RedisConfig { - ClusterNodes = new Splitio.Domain.ClusterNodes(new List() { "localhost:6379" }, "{SPLITIO}"), + ClusterNodes = new ClusterNodes(new List() { "localhost:6379" }, "{SPLITIO}"), RedisPassword = "", RedisDatabase = 0, RedisConnectTimeout = 1000, RedisConnectRetry = 5, RedisSyncTimeout = 1000, PoolSize = 1, - RedisUserPrefix = RedisPrefix, + RedisUserPrefix = prefix ?? RedisPrefix, SdkMachineIP = "ip", SdkVersion = "version", SdkMachineName = "mm" diff --git a/tests/Splitio-tests/Unit Tests/Impressions/RedisImpressionsCacheTests.cs b/tests/Splitio-tests/Unit Tests/Impressions/RedisImpressionsCacheTests.cs index de5abd43..96cf6ee1 100644 --- a/tests/Splitio-tests/Unit Tests/Impressions/RedisImpressionsCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Impressions/RedisImpressionsCacheTests.cs @@ -1,9 +1,11 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using Splitio.Domain; using Splitio.Redis.Services.Cache.Classes; using Splitio.Redis.Services.Cache.Interfaces; using Splitio.Redis.Services.Domain; using Splitio.Telemetry.Domain; +using StackExchange.Redis; using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -91,5 +93,25 @@ await _cache.RecordUniqueKeysAsync(new List _redisAdapter.Verify(mock => mock.ListRightPushAsync(key, expected2), Times.Once); _redisAdapter.Verify(mock => mock.KeyExpireAsync(key, new TimeSpan(0, 0, 3600)), Times.Never); } + + [TestMethod] + public async Task CorrectFormatStoreImpressions() + { + // Arrange. + var impressions = new List + { + new KeyImpression("matching-key", "feature-1", "treatment", 34534546, 3333444, "label", "bucketing-key", false), + new KeyImpression("matching-key", "feature-1", "treatment", 34534550, 3333444, "label", "bucketing-key", false, 34534546), + new KeyImpression("matching-key", "feature-2", "treatment", 34534546, 3333444, "label", "bucketing-key", false, properties: "{\"prop\":\"val\"}"), + }; + + // Act. + var result = await _cache.AddAsync(impressions); + + // Assert. + _redisAdapter.Verify(mock => mock.ListRightPushAsync("test-pre:.SPLITIO.impressions", It.IsAny()), Times.Once); + + //IRedisAdapterProducer.ListRightPushAsync("test-pre:.SPLITIO.impressions", [{"m":{"s":"version","i":"ip","n":"mm"},"i":{"f":"feature-1","k":"matching-key","t":"treatment","m":34534546,"c":3333444,"r":"label","b":"bucketing-key","pt":null}}, {"m":{"s":"version","i":"ip","n":"mm"},"i":{"f":"feature-1","k":"matching-key","t":"treatment","m":34534550,"c":3333444,"r":"label","b":"bucketing-key","pt":34534546}}, {"m":{"s":"version","i":"ip","n":"mm"},"i":{"f":"feature-2","k":"matching-key","t":"treatment","m":34534546,"c":3333444,"r":"label","b":"bucketing-key","pt":null,"properties":"{\"prop\":\"val\"}"}}]) + } } }