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,8 +1,11 @@
package com.sap.cloud.environment.servicebinding;

import java.util.ArrayList;
import java.io.IOException;
import java.util.Collections;
import java.nio.file.Files;
import java.util.List;
import java.nio.file.Path;
import java.util.function.Function;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -39,6 +42,9 @@ public class SapVcapServicesServiceBindingAccessor implements ServiceBindingAcce
@Nonnull
private static final String VCAP_SERVICES = "VCAP_SERVICES";

@Nonnull
private static final String VCAP_SERVICES_FILE_PATH = "VCAP_SERVICES_FILE_PATH";

@Nonnull
private final Function<String, String> environmentVariableReader;

Expand Down Expand Up @@ -68,11 +74,31 @@ public SapVcapServicesServiceBindingAccessor( @Nonnull final Function<String, St
public List<ServiceBinding> getServiceBindings()
throws ServiceBindingAccessException
{
logger.debug("Trying to determine service bindings using the '{}' environment variable.", VCAP_SERVICES);
final String vcapServices = environmentVariableReader.apply(VCAP_SERVICES);
logger
.debug(
"Trying to determine service bindings using the '{}' and '{}' environment variables.",
VCAP_SERVICES,
VCAP_SERVICES_FILE_PATH);
String vcapServices = environmentVariableReader.apply(VCAP_SERVICES);
final String vcapServicesFilePath = environmentVariableReader.apply(VCAP_SERVICES_FILE_PATH);

if( vcapServices == null && vcapServicesFilePath != null ) {
logger
.debug(
"Environment variable '{}' is not defined. Falling back to environment variable '{}'",
VCAP_SERVICES,
VCAP_SERVICES_FILE_PATH);
try {
vcapServices = Files.readString(Path.of(vcapServicesFilePath));
}
catch( final IOException e ) {
logger.error("Failed to read VCAP_SERVICES from file: {}", vcapServicesFilePath, e);
return Collections.emptyList();
}
}

if( vcapServices == null ) {
logger.debug("Environment variable '{}' is not defined.", VCAP_SERVICES);
if( vcapServices == null && vcapServicesFilePath == null ) {
logger.debug("Environment variable '{}' and '{}' are not defined.", VCAP_SERVICES, VCAP_SERVICES_FILE_PATH);
return Collections.emptyList();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
import com.sap.cloud.environment.servicebinding.api.ServiceBinding;

import static org.assertj.core.api.Assertions.assertThat;
import java.util.Map;
import java.util.HashMap;
import java.nio.file.Paths;
import java.nio.file.Path;

class SapVcapServicesServiceBindingAccessorTest
{
Expand All @@ -33,6 +37,25 @@ void parseFullVcapServices()
assertContainsDestinationBinding1(serviceBindings);
}

@Test
void parseFullVcapServicesFileBased()
{
final String vcapServicesFilePath =
TestResource.getPathAsString(SapVcapServicesServiceBindingAccessorTest.class, "FullVcapServices.json");

final SapVcapServicesServiceBindingAccessor sut =
new SapVcapServicesServiceBindingAccessor(
key -> "VCAP_SERVICES_FILE_PATH".equals(key) ? vcapServicesFilePath : null);

final List<ServiceBinding> serviceBindings = sut.getServiceBindings();

assertThat(serviceBindings.size()).isEqualTo(3);

assertContainsXsuaaBinding1(serviceBindings);
assertContainsXsuaaBinding2(serviceBindings);
assertContainsDestinationBinding1(serviceBindings);
}

private void assertContainsXsuaaBinding1( @Nonnull final Collection<ServiceBinding> serviceBindings )
{
final List<ServiceBinding> bindings =
Expand Down Expand Up @@ -128,53 +151,102 @@ void brokenBindingIsIgnored()
assertContainsXsuaaBinding1(serviceBindings);
}

@Test
void brokenBindingIsIgnoredWhenFileBased()
{
final String vcapServicesFilePath =
TestResource
.getPathAsString(SapVcapServicesServiceBindingAccessorTest.class, "VcapServicesWithBrokenBinding.json");

final SapVcapServicesServiceBindingAccessor sut =
new SapVcapServicesServiceBindingAccessor(
key -> "VCAP_SERVICES_FILE_PATH".equals(key) ? vcapServicesFilePath : null);

final List<ServiceBinding> serviceBindings = sut.getServiceBindings();

assertThat(serviceBindings.size()).isEqualTo(1);

assertContainsXsuaaBinding1(serviceBindings);
}

@Test
void resultIsNotCached()
{
final String vcapServices =
TestResource.read(SapVcapServicesServiceBindingAccessorTest.class, "FullVcapServices.json");
final CountingEnvironmentVariableReader environmentVariableReader =
new CountingEnvironmentVariableReader("VCAP_SERVICES", vcapServices);
final CountingEnvironmentVariableReader environmentVariableReader = new CountingEnvironmentVariableReader();
environmentVariableReader.addExpectedKeyAndValue("VCAP_SERVICES", vcapServices);
environmentVariableReader.addExpectedKeyAndValue("VCAP_SERVICES_FILE_PATH", null);

final SapVcapServicesServiceBindingAccessor sut =
new SapVcapServicesServiceBindingAccessor(environmentVariableReader);

// first invocation
assertThat(sut.getServiceBindings().size()).isEqualTo(3);
assertThat(environmentVariableReader.getInvocations("VCAP_SERVICES")).isEqualTo(1);
assertThat(environmentVariableReader.getInvocations("VCAP_SERVICES_FILE_PATH")).isEqualTo(1);

// second invocation
assertThat(sut.getServiceBindings().size()).isEqualTo(3);
assertThat(environmentVariableReader.getInvocations("VCAP_SERVICES")).isEqualTo(2);
assertThat(environmentVariableReader.getInvocations("VCAP_SERVICES_FILE_PATH")).isEqualTo(2);
}

@Test
void resultIsNotCachedWhenFileBased()
{
final String vcapServicesFilePath =
TestResource.getPathAsString(SapVcapServicesServiceBindingAccessorTest.class, "FullVcapServices.json");
final CountingEnvironmentVariableReader environmentVariableReader = new CountingEnvironmentVariableReader();
environmentVariableReader.addExpectedKeyAndValue("VCAP_SERVICES", null);
environmentVariableReader.addExpectedKeyAndValue("VCAP_SERVICES_FILE_PATH", vcapServicesFilePath);

final SapVcapServicesServiceBindingAccessor sut =
new SapVcapServicesServiceBindingAccessor(environmentVariableReader);

// first invocation
assertThat(sut.getServiceBindings().size()).isEqualTo(3);
assertThat(environmentVariableReader.getInvocations()).isEqualTo(1);
assertThat(environmentVariableReader.getInvocations("VCAP_SERVICES")).isEqualTo(1);
assertThat(environmentVariableReader.getInvocations("VCAP_SERVICES_FILE_PATH")).isEqualTo(1);

// second invocation
assertThat(sut.getServiceBindings().size()).isEqualTo(3);
assertThat(environmentVariableReader.getInvocations()).isEqualTo(2);
assertThat(environmentVariableReader.getInvocations("VCAP_SERVICES")).isEqualTo(2);
assertThat(environmentVariableReader.getInvocations("VCAP_SERVICES_FILE_PATH")).isEqualTo(2);
}

private static class CountingEnvironmentVariableReader implements Function<String, String>
{
@Nonnull
private final String expectedKey;
private final Map<String, String> expectedKeyToValueMap;

@Nonnull
private final String value;
private final Map<String, Integer> expectedKeyInvocations;

private int invocations;
public CountingEnvironmentVariableReader()
{
this.expectedKeyToValueMap = new HashMap<>();
this.expectedKeyInvocations = new HashMap<>();
}

public CountingEnvironmentVariableReader( @Nonnull final String expectedKey, @Nonnull final String value )
public void addExpectedKeyAndValue( @Nonnull final String expectedKey, @Nonnull final String value )
{
this.expectedKey = expectedKey;
this.value = value;
expectedKeyToValueMap.put(expectedKey, value);
expectedKeyInvocations.put(expectedKey, 0);
}

@Override
public String apply( final String s )
{
assertThat(s).isEqualTo(expectedKey);
invocations++;
return value;
assertThat(expectedKeyToValueMap.containsKey(s)).isTrue();
int invocations = expectedKeyInvocations.get(s) + 1;
expectedKeyInvocations.put(s, invocations);
return expectedKeyToValueMap.get(s);
}

public int getInvocations()
public int getInvocations( @Nonnull final String expectedKey )
{
return invocations;
return expectedKeyInvocations.get(expectedKey);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,10 @@ public static Path get( @Nonnull final Class<?> testClass, @Nonnull final String
String.format("Unable to load test source from '%s/%s'", testClass.getSimpleName(), fileName));
}
}

@Nonnull
public static String getPathAsString( @Nonnull final Class<?> testClass, @Nonnull final String fileName )
{
return get(testClass, fileName).toAbsolutePath().toString();
}
}