Skip to content

Commit

Permalink
Fix to accept correct JSON schema of response from AWS AppConfig (#20)
Browse files Browse the repository at this point in the history
* lint

* Fix to parse to keyNode directly

* Fix test

* tweak

* lnit
  • Loading branch information
lavenderses authored May 11, 2024
1 parent 8b0d8e6 commit 08c51d9
Show file tree
Hide file tree
Showing 16 changed files with 42 additions and 253 deletions.
1 change: 0 additions & 1 deletion .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ protected final boolean enabled(@NotNull final JsonNode keyNode) {
}

/**
* Get feature flag value node ({@code "$.{key_name}.flag_value"} in JSON).<br/>
* Get feature flag value node ({@code "$.flag_value"} in JSON.<br/>
* e.g. When AWS AppConfig is following (feature flag key name is {@code flag_key}, and feature flag value is
* number type {@code 12345})...
* <pre>
Expand All @@ -63,7 +63,8 @@ protected final boolean enabled(@NotNull final JsonNode keyNode) {
* }
* }}
* </pre>
* Parameter keyNode is the {@link JsonNode} of following JSON string.
* Parameter keyNode is the {@link JsonNode} of following JSON string. <b>THIS IS SAME AS JSON RESPONSE FROM AWS
* AppConfig WHEN FEATURE FLAG KEY IS SPECIFIED.</b>
* <pre>
* {@code
* {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.fasterxml.jackson.databind.JsonNode;
import io.github.lavenderses.aws_app_config_openfeature_provider.app_config_model.AppConfigValue;

import java.util.function.BiFunction;
import java.util.function.Function;

/**
* Parser interface for {@link T}-typed feature flag value from AWS AppConfig JSON response.<br/>
Expand All @@ -14,4 +14,4 @@
* @param <T> feature flag type in OpenFeature requirements, such as boolean
* @param <V> {@link T}-typed {@link AppConfigValue}. this will be returned.
*/
interface AttributeParser<T, V extends AppConfigValue<T>> extends BiFunction<JsonNode, JsonNode, V> {}
interface AttributeParser<T, V extends AppConfigValue<T>> extends Function<JsonNode, V> {}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.VisibleForTesting;

import java.util.function.BiFunction;
import java.util.function.Function;

import static java.util.Objects.isNull;
import static java.util.Objects.requireNonNull;

/**
Expand Down Expand Up @@ -46,7 +45,7 @@ public AwsAppConfigParser() {
*
* @param key feature flag key value in {@link AppConfigValueKey} ({@code "feature flag key name in OpenFeature"})
* @param value JSON response from AWS AppConfig
* @param buildAppConfigValue build {@link V} from (request JSON body, key object in response body)
* @param buildAppConfigValue build {@link V} from request JSON body
* @return {@link T}-typed feature flag implementation of {@link AppConfigValue}. Once returned value successfully,
* it is guaranteed that JSON response satisfies ALL spec of this Provider's spec, and success to evaluation feature
* flag.
Expand All @@ -57,33 +56,23 @@ public AwsAppConfigParser() {
public <T, V extends AppConfigValue<T>> V parse(
@NotNull final String key,
@Language("json") @NotNull final String value,
@NotNull final BiFunction<JsonNode, JsonNode, V> buildAppConfigValue
@NotNull final Function<JsonNode, V> buildAppConfigValue
) {
requireNonNull(key, "key");
requireNonNull(value, "value");

final JsonNode responseNode;
final JsonNode keyNode;
try {
responseNode = objectMapper.readTree(value);
keyNode = objectMapper.readTree(value);
} catch (JsonProcessingException e) {
throw new AppConfigValueParseException(
/* response = */ value,
/* evaluationResult = */ EvaluationResult.INVALID_ATTRIBUTE_FORMAT
);
}
requireNonNull(responseNode, "responseNode");

// get key node from response
final JsonNode keyNode = responseNode.get(key);
if (isNull(keyNode)) {
throw new AppConfigValueParseException(
/* response = */ value,
/* evaluationResult = */ EvaluationResult.FLAG_NOT_FOUND
);
}
requireNonNull(keyNode, "responseNode");

return buildAppConfigValue.apply(
/* t = */ responseNode,
/* v = */ keyNode
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public final class BooleanAttributeParser extends AbstractAttributeParser<Boolea
*/
@Override
public AppConfigBooleanValue apply(
@NotNull JsonNode responseNode,
@NotNull JsonNode keyNode
) {
final JsonNode flagValueNode = getValidFlagValueNode(
Expand All @@ -30,7 +29,7 @@ public AppConfigBooleanValue apply(
return new AppConfigBooleanValue(
/* enabled = */ enabled(keyNode),
/* value = */ flagValueNode.asBoolean(),
/* responseNode = */ responseNode.toString()
/* responseNode = */ keyNode.toString()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.fasterxml.jackson.databind.node.JsonNodeType;
import io.github.lavenderses.aws_app_config_openfeature_provider.app_config_model.AppConfigBooleanValue;
import io.github.lavenderses.aws_app_config_openfeature_provider.app_config_model.AppConfigDoubleValue;
import io.github.lavenderses.aws_app_config_openfeature_provider.app_config_model.AppConfigIntegerValue;
import org.jetbrains.annotations.NotNull;

/**
Expand All @@ -22,7 +21,6 @@ public final class DoubleAttributeParser extends AbstractAttributeParser<Double,
*/
@Override
public AppConfigDoubleValue apply(
@NotNull JsonNode responseNode,
@NotNull JsonNode keyNode
) {
final JsonNode flagValueNode = getValidFlagValueNode(
Expand All @@ -33,7 +31,7 @@ public AppConfigDoubleValue apply(
return new AppConfigDoubleValue(
/* enabled = */ enabled(keyNode),
/* value = */ flagValueNode.asDouble(),
/* responseNode = */ responseNode.toString()
/* responseNode = */ keyNode.toString()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public final class IntegerAttributeParser extends AbstractAttributeParser<Intege
*/
@Override
public AppConfigIntegerValue apply(
@NotNull JsonNode responseNode,
@NotNull JsonNode keyNode
) {
final JsonNode flagValueNode = getValidFlagValueNode(
Expand All @@ -32,7 +31,7 @@ public AppConfigIntegerValue apply(
return new AppConfigIntegerValue(
/* enabled = */ enabled(keyNode),
/* value = */ flagValueNode.asInt(),
/* responseNode = */ responseNode.toString()
/* responseNode = */ keyNode.toString()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public final class ObjectAttributeParser extends AbstractAttributeParser<Value,
*/
@Override
public AppConfigObjectValue apply(
@NotNull JsonNode responseNode,
@NotNull JsonNode keyNode
) {
final JsonNode flagValueNode = getValidFlagValueNode(
Expand All @@ -51,7 +50,7 @@ public AppConfigObjectValue apply(
return new AppConfigObjectValue(
/* enabled = */ enabled(keyNode),
/* value = */ value,
/* responseNode = */ responseNode.toString()
/* responseNode = */ keyNode.toString()
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public final class StringAttributeParser extends AbstractAttributeParser<String,
*/
@Override
public AppConfigStringValue apply(
@NotNull JsonNode responseNode,
@NotNull JsonNode keyNode
) {
final JsonNode flagValueNode = getValidFlagValueNode(
Expand All @@ -31,7 +30,7 @@ public AppConfigStringValue apply(
return new AppConfigStringValue(
/* enabled = */ enabled(keyNode),
/* value = */ flagValueNode.asText(),
/* responseNode = */ responseNode.toString()
/* responseNode = */ keyNode.toString()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import org.mockito.kotlin.doReturn
import org.mockito.kotlin.doThrow
import org.mockito.kotlin.verifyNoInteractions
import org.mockito.kotlin.whenever
import software.amazon.awssdk.services.appconfigdata.model.GetLatestConfigurationRequest

@ExtendWith(MockitoExtension::class)
class AwsAppConfigClientServiceTest {
Expand Down Expand Up @@ -486,9 +485,6 @@ class AwsAppConfigClientServiceTest {
// prepare
val key = "key"
val defaultValue = 12345.0
val request = GetLatestConfigurationRequest.builder()
.configurationToken("token")
.build()
val expected = ErrorEvaluationValue<Value>(
/* errorCode = */ ErrorCode.FLAG_NOT_FOUND,
/* errorMessage = */ null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import assertk.assertions.isEqualTo
import io.github.lavenderses.aws_app_config_openfeature_provider.app_config_model.AppConfigBooleanValue
import io.github.lavenderses.aws_app_config_openfeature_provider.evaluation_value.EvaluationResult
import io.github.lavenderses.aws_app_config_openfeature_provider.utils.ObjectMapperBuilder
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
Expand Down Expand Up @@ -38,32 +39,11 @@ class AwsAppConfigParserTest {
// language=JSON
val response = """
{
"key": {
"enabled": true,
"flag_value": true
}
"enabled": true,
"flag_value": true
}
""".trimIndent()
val responseNode = objectMapper.readTree(
// language=JSON
"""
{
"key": {
"enabled": true,
"flag_value": true
}
}
""".trimIndent(),
)
val keyNode = objectMapper.readTree(
// language=JSON
"""
{
"enabled": true,
"flag_value": true
}
""".trimIndent(),
)
val keyNode = objectMapper.readTree(response)
val expected = AppConfigBooleanValue(
/* enabled = */ true,
/* value = */ true,
Expand All @@ -79,7 +59,6 @@ class AwsAppConfigParserTest {
)
.whenever(buildAppConfigValue)
.apply(
/* responseNode = */ responseNode,
/* keyNode = */ keyNode,
)

Expand All @@ -93,16 +72,17 @@ class AwsAppConfigParserTest {
).isEqualTo(expected)
}

@Suppress("ForbiddenComment")
// TODO: Do test
@Disabled
@Test
fun `key not found`() {
// prepare
// language=JSON
val response = """
{
"invalid_key": {
"enabled": true,
"flag_value": true
}
"enabled": true,
"flag_value": true
}
""".trimIndent()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,6 @@ class BooleanAttributeParserTest {
@Test
fun normal() {
// prepare
val responseNode = OBJECT_MAPPER.readTree(
// language=JSON
"""
{
"key": {
"enabled": true,
"flag_value": true
}
}
""".trimIndent(),
)
val keyNode = OBJECT_MAPPER.readTree(
// language=JSON
"""
Expand All @@ -47,13 +36,12 @@ class BooleanAttributeParserTest {
val expected = AppConfigBooleanValue(
/* enabled = */ true,
/* value = */ true,
/* jsonFormat = */ """{"key":{"enable":true,"flag_value":true}}""",
/* jsonFormat = */ """{"enable":true,"flag_value":true}""",
)

// do & verify
assertThat(
booleanAttributeParser.apply(
/* responseNode = */ responseNode,
/* keyNode = */ keyNode,
),
).isEqualTo(expected)
Expand All @@ -62,18 +50,6 @@ class BooleanAttributeParserTest {
@Test
fun `enable is false`() {
// prepare
// language=JSON
val responseNode = OBJECT_MAPPER.readTree(
// language=JSON
"""
{
"key": {
"enabled": false,
"flag_value": true
}
}
""".trimIndent(),
)
val keyNode = OBJECT_MAPPER.readTree(
// language=JSON
"""
Expand All @@ -86,13 +62,12 @@ class BooleanAttributeParserTest {
val expected = AppConfigBooleanValue(
/* enabled = */ false,
/* value = */ true,
/* jsonFormat = */ """{"key":{"enable":true,"flag_value":false}}""",
/* jsonFormat = */ """{"enable":true,"flag_value":true}""",
)

// do & verify
assertThat(
booleanAttributeParser.apply(
/* responseNode = */ responseNode,
/* keyNode = */ keyNode,
),
).isEqualTo(expected)
Expand All @@ -101,16 +76,6 @@ class BooleanAttributeParserTest {
@Test
fun `flag_value is null`() {
// prepare
val responseNode = OBJECT_MAPPER.readTree(
// language=JSON
"""
{
"key": {
"enabled": true
}
}
""".trimIndent(),
)
val keyNode = OBJECT_MAPPER.readTree(
// language=JSON
"""
Expand All @@ -123,7 +88,6 @@ class BooleanAttributeParserTest {
// do
val e = assertThrows<AppConfigValueParseException> {
booleanAttributeParser.apply(
/* responseNode = */ responseNode,
/* keyNode = */ keyNode,
)
}
Expand Down
Loading

0 comments on commit 08c51d9

Please sign in to comment.