Skip to content

Commit 670f1ca

Browse files
authored
feat: Implement OFREP default evaluation response (#468)
Signed-off-by: André Silva <[email protected]>
1 parent ec12f2d commit 670f1ca

File tree

2 files changed

+86
-3
lines changed

2 files changed

+86
-3
lines changed

src/OpenFeature.Providers.Ofrep/Client/OfrepClient.cs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,9 @@ private async Task<OfrepResponse<T>> ProcessBadRequestResponse<T>(string flagKey
258258
private async Task<OfrepResponse<T>> ProcessOkResponseAsync<T>(string flagKey, T defaultValue,
259259
HttpResponseMessage response, CancellationToken cancellationToken = default)
260260
{
261-
var evaluationResponse = await response.Content
262-
.ReadFromJsonAsync<OfrepResponse<T>>(JsonOptions, cancellationToken).ConfigureAwait(false);
263-
if (evaluationResponse == null)
261+
var rawResponse = await response.Content
262+
.ReadFromJsonAsync<OfrepResponse<JsonElement>>(JsonOptions, cancellationToken).ConfigureAwait(false);
263+
if (rawResponse == null)
264264
{
265265
this.LogNullResponse(flagKey);
266266
return new OfrepResponse<T>(flagKey, defaultValue)
@@ -270,6 +270,41 @@ private async Task<OfrepResponse<T>> ProcessOkResponseAsync<T>(string flagKey, T
270270
};
271271
}
272272

273+
var hasValue = rawResponse.Value.ValueKind != JsonValueKind.Undefined &&
274+
rawResponse.Value.ValueKind != JsonValueKind.Null;
275+
276+
T resolvedValue;
277+
if (hasValue)
278+
{
279+
try
280+
{
281+
resolvedValue = rawResponse.Value.Deserialize<T>(JsonOptions) ?? defaultValue;
282+
}
283+
catch (JsonException ex)
284+
{
285+
this.LogJsonParseError(flagKey, ex.Message, ex);
286+
return HandleEvaluationError(flagKey, ex, defaultValue);
287+
}
288+
}
289+
else
290+
{
291+
resolvedValue = defaultValue;
292+
}
293+
294+
var evaluationResponse = new OfrepResponse<T>(rawResponse.Key ?? flagKey, resolvedValue)
295+
{
296+
ErrorCode = rawResponse.ErrorCode,
297+
ErrorMessage = rawResponse.ErrorMessage,
298+
Reason = rawResponse.Reason,
299+
Variant = rawResponse.Variant,
300+
Metadata = rawResponse.Metadata
301+
};
302+
303+
if (!hasValue)
304+
{
305+
evaluationResponse.Reason ??= Reason.Default;
306+
}
307+
273308
return evaluationResponse;
274309
}
275310

test/OpenFeature.Providers.Ofrep.Test/Client/OfrepClientTest.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using OpenFeature.Providers.Ofrep.Configuration;
1212
using OpenFeature.Providers.Ofrep.Models;
1313
using OpenFeature.Providers.Ofrep.Test.Helpers;
14+
using OpenFeature.Constant;
1415
using Xunit;
1516

1617
namespace OpenFeature.Providers.Ofrep.Test.Client;
@@ -248,6 +249,53 @@ public async Task EvaluateFlag_WithNullResponse_ShouldReturnParsingError()
248249
Assert.Contains("null or empty response", result.ErrorMessage);
249250
}
250251

252+
[Fact]
253+
public async Task EvaluateFlag_WhenResponseDefersToCodeDefault_ShouldUseDefaultValue()
254+
{
255+
// Arrange
256+
const string flagKey = "code-default";
257+
const bool defaultValue = true;
258+
259+
const string jsonResponse = "{\"key\":\"code-default\",\"variant\":\"control\",\"metadata\":{\"traceId\":\"abc-123\"}}";
260+
this._mockHandler.SetupResponse(HttpStatusCode.OK, jsonResponse);
261+
262+
using var client = new OfrepClient(this._configuration, this._mockHandler, this._mockLogger);
263+
264+
// Act
265+
var result = await client.EvaluateFlag(flagKey, defaultValue, EvaluationContext.Empty);
266+
267+
// Assert
268+
Assert.Equal(defaultValue, result.Value);
269+
Assert.Equal(Reason.Default, result.Reason);
270+
Assert.Equal("control", result.Variant);
271+
272+
Assert.NotNull(result.Metadata);
273+
Assert.True(result.Metadata!.TryGetValue("traceId", out var traceId));
274+
var traceIdElement = Assert.IsType<JsonElement>(traceId);
275+
Assert.Equal("abc-123", traceIdElement.GetString());
276+
}
277+
278+
[Fact]
279+
public async Task EvaluateFlag_WhenCodeDefaultResponseIncludesReason_ShouldPreserveServerReason()
280+
{
281+
// Arrange
282+
const string flagKey = "code-default-reason";
283+
const int defaultValue = 7;
284+
285+
const string jsonResponse = "{\"key\":\"code-default-reason\",\"reason\":\"STATIC\"}";
286+
this._mockHandler.SetupResponse(HttpStatusCode.OK, jsonResponse);
287+
288+
using var client = new OfrepClient(this._configuration, this._mockHandler, this._mockLogger);
289+
290+
// Act
291+
var result = await client.EvaluateFlag(flagKey, defaultValue, EvaluationContext.Empty);
292+
293+
// Assert
294+
Assert.Equal(defaultValue, result.Value);
295+
Assert.Equal("STATIC", result.Reason);
296+
Assert.Null(result.Metadata);
297+
}
298+
251299
[Fact]
252300
public async Task EvaluateFlag_WithEvaluationContext_ShouldIncludeContextInRequest()
253301
{

0 commit comments

Comments
 (0)