Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package org.cloudfoundry.multiapps.common.test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import java.text.MessageFormat;
import java.util.List;
import java.util.Objects;
Expand All @@ -15,6 +11,10 @@
import org.cloudfoundry.multiapps.common.util.JsonUtil;
import org.junit.jupiter.api.Assertions;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

public class Tester {

private final Class<?> testedClass;
Expand Down Expand Up @@ -94,12 +94,13 @@ private void validateSuccessForSetExpectation(Set<Object> expectedSet, Set<Objec
private void validateFailure(Expectation expectation, Exception e) {
if (!expectation.expectsFailure()) {
e.printStackTrace();
fail("Test failed: " + e.toString());
fail("Test failed: " + e);
}
String exceptionMessage = e.getMessage();
assertTrue(exceptionMessage.contains(expectation.getExpectationAsString()),
MessageFormat.format("Exception's message doesn't match up! Expected [{0}] to contain [{1}]!", exceptionMessage,
expectation.getExpectationAsString()));
MessageFormat.format("Exception's message doesn't match up! Expected [{0}] to contain [{1}]!",
expectation.getExpectationAsString(), exceptionMessage)
);
}

private Object loadResourceAsJsonObject(String resource) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

public class PropertiesResolver implements SimplePropertyVisitor, Resolver<Map<String, Object>> {

private static final String FULL_PATH_TEMPLATE = "%s%s%s";

private Map<String, Object> properties;
private String prefix;
private ProvidedValuesResolver valuesResolver;
Expand Down Expand Up @@ -150,7 +152,9 @@ private boolean referenceResolutionIsPossible(String referenceKey, Map<String, O
private Object getObjectForLateResolveIfPresent(Reference reference) {
String referenceKey = reference.getKey();
if (isStrict && !dynamicResolvableParameters.contains(referenceKey)) {
throw new ContentException(Messages.UNABLE_TO_RESOLVE, NameUtil.getPrefixedName(prefix, referenceKey));
throw new ContentException(Messages.UNABLE_TO_RESOLVE,
NameUtil.getPrefixedPath(prefix, buildFullQualifiedPath(reference)));

}
if (dynamicResolvableParameters.contains(referenceKey) && prefix != null) {
return MessageFormat.format(DynamicParameterUtil.PATTERN_FOR_DYNAMIC_PARAMETERS, prefix, reference.getKey());
Expand All @@ -174,7 +178,7 @@ protected Object resolveReferenceInDepth(Reference reference, Map<String, Object
keyPart = addOldKeyAsPrefixIfUnresolved(keyPart, referencePartsMatcher.group(1));

if (currentProperty instanceof Collection) {
currentProperty = resolveKeyInIterable(keyPart, (Collection<?>) currentProperty, deepReferenceKey);
currentProperty = resolveKeyInIterable(reference, (Collection<?>) currentProperty, keyPart);
keyPart = "";
} else if (currentProperty instanceof Map) {
@SuppressWarnings("unchecked")
Expand All @@ -184,12 +188,16 @@ protected Object resolveReferenceInDepth(Reference reference, Map<String, Object
keyPart = "";
}
} else {
throw new ContentException(Messages.UNABLE_TO_RESOLVE, NameUtil.getPrefixedName(prefix, deepReferenceKey));
throw new ContentException(Messages.UNABLE_TO_RESOLVE,
NameUtil.getPrefixedPath(prefix, buildFullQualifiedPath(reference)));

}
}

if (!keyPart.isEmpty()) {
throw new ContentException(Messages.UNABLE_TO_RESOLVE, NameUtil.getPrefixedName(prefix, deepReferenceKey));
throw new ContentException(Messages.UNABLE_TO_RESOLVE,
NameUtil.getPrefixedPath(prefix, buildFullQualifiedPath(reference)));

}

return currentProperty;
Expand All @@ -202,15 +210,22 @@ private String addOldKeyAsPrefixIfUnresolved(String oldKey, String newKey) {
return oldKey + "/" + newKey;
}

private Object resolveKeyInIterable(String key, Collection<?> listOfProperties, String longKey) {
if (StringUtils.isNumeric(key)) {
private Object resolveKeyInIterable(Reference reference, Collection<?> listOfProperties, String longKey) {
if (StringUtils.isNumeric(longKey)) {
try {
return IterableUtils.get(listOfProperties, Integer.parseInt(key));
return IterableUtils.get(listOfProperties, Integer.parseInt(longKey));
} catch (IndexOutOfBoundsException e) {
throw new ContentException(e, Messages.UNABLE_TO_RESOLVE, NameUtil.getPrefixedName(prefix, longKey));
throw new ContentException(e, Messages.UNABLE_TO_RESOLVE, buildFullQualifiedPath(reference));
}
}
throw new ContentException(Messages.UNABLE_TO_RESOLVE, NameUtil.getPrefixedName(prefix, longKey));
throw new ContentException(Messages.UNABLE_TO_RESOLVE, buildFullQualifiedPath(reference));
}

private String buildFullQualifiedPath(Reference reference) {
String referenceKey = reference.getDependencyName() != null
? String.format(FULL_PATH_TEMPLATE, reference.getDependencyName(), NameUtil.DEFAULT_PREFIX_SEPARATOR, reference.getKey())
: reference.getKey();
return NameUtil.getPrefixedPath(prefix, referenceKey);
}

private String getReferencedPropertyKeyWithSuffix(Reference reference) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,10 @@ public static String getPrefixedName(String prefix, String name, String separato
return prefix + separator + name;
}

public static String getPrefixedPath(String prefix, String path) {
if (StringUtils.isEmpty(prefix) || path.startsWith(prefix + DEFAULT_PREFIX_SEPARATOR)) {
return path;
}
return prefix + DEFAULT_PREFIX_SEPARATOR + path;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,21 @@ class DescriptorReferenceResolverTest {

static Stream<Arguments> testResolve() {
return Stream.of(
// (0) Resolve references in resources:
Arguments.of("merged-01.yaml", new Expectation(Expectation.Type.JSON, "resolved-01.yaml.json")),
// (1) Resolve references in resources - cyclic dependencies & corner cases:
Arguments.of("merged-02.yaml", new Expectation(Expectation.Type.JSON, "resolved-02.yaml.json")),
// (2) Test error reporting on failure to resolve value:
Arguments.of("merged-03.yaml",
new Expectation(Expectation.Type.EXCEPTION, "Unable to resolve \"baz##non-existing\"")),
// (3) Resolve references in hooks:
Arguments.of("merged-04.yaml", new Expectation(Expectation.Type.JSON, "resolved-03.yaml.json")),
// (4)
Arguments.of("mtad-with-escaped-references.yaml",
new Expectation(Expectation.Type.JSON, "result-from-escaped-references.json")));
// (0) Resolve references in resources:
Arguments.of("merged-01.yaml", new Expectation(Expectation.Type.JSON, "resolved-01.yaml.json")),
// (1) Resolve references in resources - cyclic dependencies & corner cases:
Arguments.of("merged-02.yaml", new Expectation(Expectation.Type.JSON, "resolved-02.yaml.json")),
// (2) Test error reporting on failure to resolve value:
Arguments.of("merged-03.yaml",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add more failing test cases? Add tests where reference fails for arrays like described in backlog item.

new Expectation(Expectation.Type.EXCEPTION, "Unable to resolve \"baz##bar#non-existing\"")),
// (3) Resolve references in hooks:
Arguments.of("merged-04.yaml", new Expectation(Expectation.Type.JSON, "resolved-03.yaml.json")),
// (4)
Arguments.of("mtad-with-escaped-references.yaml",
new Expectation(Expectation.Type.JSON, "result-from-escaped-references.json")),
// (5)
Arguments.of("merged-05.yaml",
new Expectation(Expectation.Type.EXCEPTION, "Unable to resolve \"module-a##module-b#invalid/0/url\"")));
}

@ParameterizedTest
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
ID: com.sap.mta.v2.test.config-02
_schema-version: 3.3.0
version: 1.0.0

modules:
- name: module-a
type: com.sap.application.content
parameters:
content:
subaccount:
existing_destinations_policy: update
destinations:
- Name: destination-a
URL: ~{module-b/invalid/0/url}
forwardAuthToken: true
ServiceInstanceName: "service-a"
requires:
- name: service-destination
parameters:
content-target: true
- name: service-a
- name: module-b

- name: module-b
type: application
path: "appBits.zip"
requires:
- name: service-a
parameters:
buildpack: staticfile_buildpack
memory: 1G
disk-quota: 1G
provides:
- name: module-b
properties:
default-url: ${default-url}

resources:
- name: service-destination
type: org.cloudfoundry.managed-service
parameters:
service: destination
service-name: service-destination
service-plan: lite

- name: service-a
type: org.cloudfoundry.managed-service
parameters:
service: xsuaa
service-plan: application
Loading