|
| 1 | +using System; |
1 | 2 | using System.Collections.Generic; |
2 | 3 | using System.Threading; |
3 | 4 | using System.Threading.Tasks; |
4 | 5 | using Grpc.Core; |
5 | 6 | using NSubstitute; |
| 7 | +using NSubstitute.ExceptionExtensions; |
| 8 | +using OpenFeature.Constant; |
6 | 9 | using OpenFeature.Contrib.Providers.Flagd.Resolver.Rpc; |
| 10 | +using OpenFeature.Error; |
7 | 11 | using OpenFeature.Flagd.Grpc.Evaluation; |
8 | 12 | using OpenFeature.Model; |
9 | 13 | using Xunit; |
@@ -71,7 +75,7 @@ public async Task HandleEvents_CallsFlagdProviderEventHandler() |
71 | 75 | Assert.True(autoResetEvent.WaitOne(TestTimeoutMilliseconds)); |
72 | 76 |
|
73 | 77 | Assert.NotNull(flagdProviderEvent); |
74 | | - Assert.Equal(Constant.ProviderEventTypes.ProviderReady, flagdProviderEvent.EventType); |
| 78 | + Assert.Equal(ProviderEventTypes.ProviderReady, flagdProviderEvent.EventType); |
75 | 79 | Assert.Contains("key1", flagdProviderEvent.FlagsChanged); |
76 | 80 | Assert.Contains("key1", flagdProviderEvent.FlagsChanged); |
77 | 81 | Assert.Contains("key2", flagdProviderEvent.FlagsChanged); |
@@ -111,7 +115,7 @@ public async Task HandleEvents_WithNoFlags_CallsFlagdProviderEventHandler() |
111 | 115 | Assert.True(autoResetEvent.WaitOne(TestTimeoutMilliseconds)); |
112 | 116 |
|
113 | 117 | Assert.NotNull(flagdProviderEvent); |
114 | | - Assert.Equal(Constant.ProviderEventTypes.ProviderReady, flagdProviderEvent.EventType); |
| 118 | + Assert.Equal(ProviderEventTypes.ProviderReady, flagdProviderEvent.EventType); |
115 | 119 | Assert.Empty(flagdProviderEvent.FlagsChanged); |
116 | 120 | Assert.Equal(Structure.Empty, flagdProviderEvent.SyncMetadata); |
117 | 121 | } |
@@ -152,7 +156,7 @@ public async Task HandleEvents_WhenConfigChanged_CallsFlagdProviderEventHandler( |
152 | 156 | Assert.True(autoResetEvent.WaitOne(TestTimeoutMilliseconds)); |
153 | 157 |
|
154 | 158 | Assert.NotNull(flagdProviderEvent); |
155 | | - Assert.Equal(Constant.ProviderEventTypes.ProviderConfigurationChanged, flagdProviderEvent.EventType); |
| 159 | + Assert.Equal(ProviderEventTypes.ProviderConfigurationChanged, flagdProviderEvent.EventType); |
156 | 160 | Assert.Contains("key1", flagdProviderEvent.FlagsChanged); |
157 | 161 | Assert.Equal(Structure.Empty, flagdProviderEvent.SyncMetadata); |
158 | 162 | } |
@@ -245,6 +249,58 @@ public async Task HandleEvents_WhenConfigChanged_DeletesCacheItem() |
245 | 249 | mockCache.Received().Delete("key1"); |
246 | 250 | } |
247 | 251 |
|
| 252 | + [Theory] |
| 253 | + [MemberData(nameof(ResolveValueDataLossData))] |
| 254 | + internal async Task ResolveValue_WhenDataLossError_ReturnsParseError(Func<RpcResolver, Task> act, Action<Service.ServiceClient> setup) |
| 255 | + { |
| 256 | + // Arrange |
| 257 | + var mockGrpcClient = Substitute.For<Service.ServiceClient>(); |
| 258 | + setup(mockGrpcClient); |
| 259 | + |
| 260 | + var config = new FlagdConfig(); |
| 261 | + var resolver = new RpcResolver(mockGrpcClient, config, null); |
| 262 | + |
| 263 | + // Act |
| 264 | + var ex = await Assert.ThrowsAsync<FeatureProviderException>(() => act(resolver)); |
| 265 | + |
| 266 | + // Assert |
| 267 | + Assert.Equal(ErrorType.ParseError, ex.ErrorType); |
| 268 | + Assert.Equal("Parse error", ex.Message); |
| 269 | + } |
| 270 | + |
| 271 | + public static IEnumerable<object[]> ResolveValueDataLossData() |
| 272 | + { |
| 273 | + const string flagKey = "key"; |
| 274 | + const string errorMessage = "Parse error"; |
| 275 | + var rpcException = new RpcException(new Status(StatusCode.DataLoss, errorMessage)); |
| 276 | + |
| 277 | + yield return new object[] |
| 278 | + { |
| 279 | + new Func<RpcResolver, Task>(r => r.ResolveBooleanValueAsync(flagKey, false)), |
| 280 | + new Action<Service.ServiceClient>(client => client.ResolveBooleanAsync(Arg.Any<ResolveBooleanRequest>()).Throws(rpcException)) |
| 281 | + }; |
| 282 | + yield return new object[] |
| 283 | + { |
| 284 | + new Func<RpcResolver, Task>(r => r.ResolveStringValueAsync(flagKey, "def")), |
| 285 | + new Action<Service.ServiceClient>(client => client.ResolveStringAsync(Arg.Any<ResolveStringRequest>()).Throws(rpcException)) |
| 286 | + }; |
| 287 | + yield return new object[] |
| 288 | + { |
| 289 | + new Func<RpcResolver, Task>(r => r.ResolveIntegerValueAsync(flagKey, 3)), |
| 290 | + new Action<Service.ServiceClient>(client => client.ResolveIntAsync(Arg.Any<ResolveIntRequest>()).Throws(rpcException)) |
| 291 | + }; |
| 292 | + yield return new object[] |
| 293 | + { |
| 294 | + new Func<RpcResolver, Task>(r => r.ResolveDoubleValueAsync(flagKey, 3.5)), |
| 295 | + new Action<Service.ServiceClient>(client => client.ResolveFloatAsync(Arg.Any<ResolveFloatRequest>()).Throws(rpcException)) |
| 296 | + }; |
| 297 | + yield return new object[] |
| 298 | + { |
| 299 | + new Func<RpcResolver, Task>(r => r.ResolveStructureValueAsync(flagKey, new Value(Structure.Builder().Set("value1", true).Build()))), |
| 300 | + new Action<Service.ServiceClient>(client => client.ResolveObjectAsync(Arg.Any<ResolveObjectRequest>()).Throws(rpcException)) |
| 301 | + }; |
| 302 | + } |
| 303 | + |
248 | 304 | private static Service.ServiceClient SetupGrpcStream(List<EventStreamResponse> responses) |
249 | 305 | { |
250 | 306 | var mockGrpcClient = Substitute.For<Service.ServiceClient>(); |
|
0 commit comments