Skip to content

Commit

Permalink
feat: Add test config provider
Browse files Browse the repository at this point in the history
Also adds a few methods for making it easier to create test data
  • Loading branch information
hofmeister committed Apr 25, 2024
1 parent d0672ca commit 4b1cf0a
Show file tree
Hide file tree
Showing 6 changed files with 398 additions and 0 deletions.
8 changes: 8 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,14 @@
<artifactId>schemas</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>

</project>
27 changes: 27 additions & 0 deletions src/main/java/com/kapeta/spring/annotation/KapetaTestContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.kapeta.spring.annotation;

import com.kapeta.spring.config.KapetaTestConfig;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ContextConfiguration;

import java.lang.annotation.*;

/**
* Annotation to enable kapeta test context
* <p>
* This will provide the basics needed by the Kapeta SDK
* when running tests.
* <p>
* To provide adjustments to the configuration, you can
* add beans of type {@link com.kapeta.spring.config.providers.TestConfigProvider.TestConfigurationAdjuster}
* which will be called to adjust the configuration.
*
* This annotation should typically be applied to a @Configuration-annotated class in your test.
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({KapetaTestConfig.class})
public @interface KapetaTestContext {
}
69 changes: 69 additions & 0 deletions src/main/java/com/kapeta/spring/config/KapetaTestConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2023 Kapeta Inc.
* SPDX-License-Identifier: MIT
*/
package com.kapeta.spring.config;


import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.kapeta.spring.config.pageable.PageableDeserializer;
import com.kapeta.spring.config.pageable.PageableSerializer;
import com.kapeta.spring.config.providers.KapetaConfigurationProvider;
import com.kapeta.spring.config.providers.TestConfigProvider;
import com.kapeta.spring.security.AuthorizationForwarderSupplier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.test.context.SpringBootContextLoader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.data.domain.Pageable;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;

import java.util.List;

import static com.kapeta.spring.config.KapetaDefaultConfig.createDefaultObjectMapper;

/**
* Test configuration for kapeta
*
* See {@link com.kapeta.spring.annotation.KapetaTestContext} for how to enable this
*/

public class KapetaTestConfig {

@Bean
public KapetaConfigurationProvider kapetaConfigurationProvider(List<TestConfigProvider.TestConfigurationAdjuster> adjusters, ConfigurableEnvironment environment) throws Exception {
var out = new TestConfigProvider(environment);

adjusters.forEach(a -> a.adjust(out));

var propertiesConfigurationSource = new PropertiesConfigurationSource(out);
out.getEnvironment().getPropertySources().addFirst(propertiesConfigurationSource);

propertiesConfigurationSource.setProperty(PropertiesConfigurationSource.KAPETA_SYSTEM_TYPE, out.getProviderId());
propertiesConfigurationSource.setProperty(PropertiesConfigurationSource.KAPETA_SYSTEM_ID, out.getSystemId());
propertiesConfigurationSource.setProperty(PropertiesConfigurationSource.KAPETA_BLOCK_REF, out.getBlockRef());
propertiesConfigurationSource.setProperty(PropertiesConfigurationSource.KAPETA_INSTANCE_ID, out.getInstanceId());

return out;
}

/**
* Is needed to support @Value("${some.config.property}")
*/
@Bean
@ConditionalOnMissingBean(PropertySourcesPlaceholderConfigurer.class)
public PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
/*
* Copyright 2023 Kapeta Inc.
* SPDX-License-Identifier: MIT
*/

package com.kapeta.spring.config.providers;

import com.kapeta.spring.config.providers.types.BlockInstanceDetails;
import com.kapeta.spring.config.providers.types.InstanceOperator;
import com.kapeta.spring.config.providers.types.ResourceInfo;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;

import java.util.*;


/**
* Configuration for tests
*/
public class TestConfigProvider implements KapetaConfigurationProvider {
private int serverPort = 80;
private String serverHost = "0.0.0.0";
private String instanceId = UUID.randomUUID().toString();
private String blockRef = "test/block:0.0.1";
private String systemId = "test/system:0.0.1";
private ConfigurableEnvironment environment;

private Map<String, Map<String, String>> serviceAddresses = new HashMap<>();
private Map<String, Map<String, ResourceInfo>> resourceInfos = new HashMap<>();
private Map<String, Object> instanceConfig = new HashMap<>();
private Map<String, String> instanceHosts = new HashMap<>();
private Map<String, InstanceOperator> instanceOperators = new HashMap<>();
private Map<String, BlockInstanceDetails> consumerInstances = new HashMap<>();
private Map<String, List<BlockInstanceDetails>> providerInstances = new HashMap<>();

public TestConfigProvider(ConfigurableEnvironment environment) {
this.environment = environment;
}

public TestConfigProvider() {
this(new StandardEnvironment());
}

public TestConfigProvider withEnvironment(ConfigurableEnvironment environment) {
this.environment = environment;
return this;
}


public TestConfigProvider withServerPort(int serverPort) {
this.serverPort = serverPort;
return this;
}

public TestConfigProvider withInstanceId(String instanceId) {
this.instanceId = instanceId;
return this;
}

public TestConfigProvider withBlockRef(String blockRef) {
this.blockRef = blockRef;
return this;
}

public TestConfigProvider withServerHost(String serverHost) {
this.serverHost = serverHost;
return this;
}

public TestConfigProvider withSystemId(String systemId) {
this.systemId = systemId;
return this;
}

public TestConfigProvider withServiceAddress(String serviceName, String portType, String address) {
serviceAddresses.computeIfAbsent(serviceName, k -> new HashMap<>()).put(portType, address);
return this;
}

public TestConfigProvider withResourceInfo(String resourceName, String portType, ResourceInfo resourceInfo) {
resourceInfos.computeIfAbsent(resourceName, k -> new HashMap<>()).put(portType, resourceInfo);
return this;
}

public TestConfigProvider withInstanceConfig(String key, Object value) {
instanceConfig.put(key, value);
return this;
}

public TestConfigProvider withInstanceConfig(Map<String, Object> instanceConfig) {
this.instanceConfig = instanceConfig;
return this;
}

public TestConfigProvider withInstanceHost(String instanceId, String host) {
instanceHosts.put(instanceId, host);
return this;
}

public TestConfigProvider withInstanceOperator(String instanceId, InstanceOperator instanceOperator) {
instanceOperators.put(instanceId, instanceOperator);
return this;
}

public TestConfigProvider withConsumerInstance(String resourceName, BlockInstanceDetails consumerInstance) {
consumerInstances.put(resourceName, consumerInstance);
return this;
}

public TestConfigProvider withProviderInstance(String resourceName, BlockInstanceDetails providerInstance) {
providerInstances.computeIfAbsent(resourceName, k -> new ArrayList<>()).add(providerInstance);
return this;
}

public TestConfigProvider withProviderInstances(String resourceName, List<BlockInstanceDetails> providerInstances) {
this.providerInstances.put(resourceName, providerInstances);
return this;
}

@Override
public int getServerPort(String portType) {
return serverPort;
}

@Override
public String getServerHost() {
return serverHost;
}

@Override
public String getSystemId() {
return systemId;
}

@Override
public ConfigurableEnvironment getEnvironment() {
return environment;
}

@Override
public int getServerPort() {
return serverPort;
}

public String getInstanceId() {
return instanceId;
}

public String getBlockRef() {
return blockRef;
}

@Override
public String getServiceAddress(String serviceName, String portType) {
if (serviceAddresses.containsKey(serviceName) &&
serviceAddresses.get(serviceName).containsKey(portType)) {
return serviceAddresses.get(serviceName).get(portType);
}
throw new IllegalArgumentException("Service not found: " + serviceName + " portType: " + portType);
}

@Override
public ResourceInfo getResourceInfo(String resourceType, String portType, String resourceName) {
if (resourceInfos.containsKey(resourceName) &&
resourceInfos.get(resourceName).containsKey(portType)) {
return resourceInfos.get(resourceName).get(portType);
}
throw new IllegalArgumentException("Resource not found: " + resourceName + " portType: " + portType);
}

@Override
public Map<String, Object> getInstanceConfig() {
return instanceConfig;
}

@Override
public String getInstanceHost(String instanceId) {
if (instanceHosts.containsKey(instanceId)) {
return instanceHosts.get(instanceId);
}

throw new IllegalArgumentException("Instance not found: " + instanceId);
}

@Override
public String getProviderId() {
return "test";
}

@Override
public <Options, Credentials> InstanceOperator<Options, Credentials> getInstanceOperator(String instanceId, Class<Options> optionsClass, Class<Credentials> credentialsClass) {
if (instanceOperators.containsKey(instanceId)) {
return (InstanceOperator<Options, Credentials>) instanceOperators.get(instanceId);
}
throw new IllegalArgumentException("Instance not found: " + instanceId);
}

@Override
public <BlockType> BlockInstanceDetails<BlockType> getInstanceForConsumer(String resourceName, Class<BlockType> clz) {
if (consumerInstances.containsKey(resourceName)) {
return (BlockInstanceDetails<BlockType>) consumerInstances.get(resourceName);
}
throw new IllegalArgumentException("Instance not found for consumer resource: " + resourceName);
}


@Override
public <BlockType> List<BlockInstanceDetails<BlockType>> getInstancesForProvider(String resourceName, Class<BlockType> clz) {
if (providerInstances.containsKey(resourceName)) {
return new ArrayList(providerInstances.get(resourceName));
}
throw new IllegalArgumentException("Instances not found for provider resource: " + resourceName);
}

public interface TestConfigurationAdjuster {
void adjust(TestConfigProvider provider);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public void setInstanceId(String instanceId) {
this.instanceId = instanceId;
}

public BlockInstanceDetails<BlockType> withInstanceId(String instanceId) {
this.instanceId = instanceId;
return this;
}

public BlockType getBlock() {
return block;
}
Expand All @@ -32,11 +37,32 @@ public void setBlock(BlockType block) {
this.block = block;
}

public BlockInstanceDetails<BlockType> withBlock(BlockType block) {
this.block = block;
return this;
}

public List<Connection> getConnections() {
return connections;
}

public void setConnections(List<Connection> connections) {
this.connections = connections;
}

public BlockInstanceDetails<BlockType> withConnections(List<Connection> connections) {
this.connections = connections;
return this;
}

public BlockInstanceDetails<BlockType> withConnection(Connection connection) {
this.connections.add(connection);
return this;
}

public static <BlockType> BlockInstanceDetails<BlockType> fromBlock(BlockType block) {
BlockInstanceDetails<BlockType> out = new BlockInstanceDetails<>();
out.setBlock(block);
return out;
}
}
Loading

0 comments on commit 4b1cf0a

Please sign in to comment.