Loading AppSettings.json in mock lambda test tool - amazon-web-services

I have an AWS Lambda Web API and I'm trying to use code that I've used before to load the appsettings.json into memory.
In appsettings.json I have this:
{
"AppSettings": {
"TestValue": "Some value"
}
}
In StartUp.cs I have this:
public class Startup
{
public static IConfiguration Configuration { get; private set; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
And in SomeController.cs I have this:
public class SapController : ControllerBase
{
private readonly AppSettings _appSettings;
public SapController(IOptionsMonitor<AppSettings> optionsMonitor)
{
_appSettings = optionsMonitor.CurrentValue;
}
The problem is, under the Mock Lambda Test Tool the _appSettings properties are all null.
I really don't want to load the appsettings using special case code, as seen in this post and described here. I really thought it should load as normal. Am I wrong with this opinion?
Is it really necessary to load appsettings under the mock lambda test tool using this code?:
IConfiguration configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();

So, it turns out that for some reason the appsettings is not being passed in to my constructors. So my controller now has this in the constructor:
public MyController(IConfiguration configuration)
{
_appSettings = configuration.GetSection(nameof(AppSettings)).Get<AppSettings>();
}
The short of it appears to be that I need to acquire the AppSettings instance from the Configuration instance, rather than having it passed in via IoC.
I still don't know why, but at least this works.

Try right-clicking your appsettings.Development.json file and set Copy to Output Directory to Copy always. This will ensure that it will be copied to the same directory as your executable upon build, and your app will find and load it.
You can add the file to your .gitignore if you don't want it to be part of your deployment package. Regardless, it will not be read in Production.

Related

How to set up ServiceBusTrigger with Dependency Injection with .Net Core 6.0 Isolated

I currently have a ServiceBus Trigger in .Net Core 6.0 Isolated. Trying to figure out how to Use Dependency Injection, to set up the Trigger. Trying to figure out how to do this with .Net Core 6.0 Isolated.
I have a strongly typed model that is Bound to the appsettings.json file in the Program.cs code. That part works and has been verified. However when trying to do this with .Net Core 6 Isolated It give error about missing reference.
Here's my Config model that is bound to the appsettings.json file. I have left out the appsettings.json file for simplification
public class MyConfig
{
public string Topic { get; set; }
public string SubscriptionName { get; set; }
}
Here is the Service bus trigger class
public class ServiceBusTriggerClass
{
private readonly MyConfig _myConfig;
public ServiceBusTriggerClass(IOptions<MyConfig> config)
{
_myConfig= config.Value;
}
[Function("MySBFunction")]
public async Task MySBFunction([ServiceBusTrigger(_myConfig.Topic, _myConfig.SubscriptionName)] object myObject)
{
// Do things with the myObject thing.
}}
As of 1-13-2022 it is not possible to do this Using .Net 6 Isolated function. The function does not have access to the Host at this point.

Custom Execution Function in WSO2

I am trying to write a simple custom function extension for WS02 (4.2.0). My function basically takes in a String and returns the upper case. This is meant to be a first step POC for a more advanced custom function.
I implemented a class that extended the org.wso2.siddhi.core.executor.function.FunctionExecutor class, and created a ams.siddhiext file. I then packaged the class and the siddhiext in a JAR file using the maven-bundle plugin.
My function class looks like this
public class AnomalyDetector extends FunctionExecutor {
private final static Logger LOG = LoggerFactory.getLogger(AnomalyDetector
.class);
#Override
protected void init(ExpressionExecutor[] expressionExecutors, ExecutionPlanContext executionPlanContext) {
LOG.info("In AD:init()");
}
#Override
protected Object execute(Object[] objects) {
return null;
}
#Override
protected Object execute(Object o) {
LOG.info("In AD:process(" + o.toString() + ")");
String eventData = (String) o;
LOG.info("Event data : " + eventData);
if (eventData != null) {
return eventData.toUpperCase();
} else {
return "Null event data";
}
}
#Override
public void start() {
LOG.info("In AD:start()");
}
#Override
public void stop() {
}
#Override
public Map<String, Object> currentState() {
return null;
}
#Override
public void restoreState(Map<String, Object> map) {
}
#Override
public Attribute.Type getReturnType() {
return Attribute.Type.STRING;
}
}
I then put the jar in the /repository/components/lib/ since /repository/components/dropins/ did not pick it up.
I have 2 issues that are blocking me currently.
I wanted to write a simple execution plan that takes a value from an input stream (String), invoke my custom function and write the output to an export stream.
#Plan:name('AMSExecutionPlan')
#Import('AMSStream:1.0.0')
define stream amsStream (metrics_json string);
#Export('AnomalyStream:1.0.0')
define stream anomalyStream (anomaly string);
from amsStream
select ams:findAnomaly(metrics_json) as anomaly
insert into anomalyStream
I get the following validation error.
What could be wrong with my execution plan?
Whenever I change my custom function class, rebuild the jar and replace it in the wso2 classpath, and then restart ws02, I dont see the changes reflected in ws02. The log lines that I print out in my custom function class reflect an older version of the code. What should I do to make changes to my Custom function class on a live ws02 instance?
Thanks in advance!
Can you bundle the jar as an OSGI bundle and try? There can be a issue when converting your jar to an OSGI bundle.
Validation error you have pointed suggest that your extension is not returning the return type properly. But I can see you have implemented getReturnType() correctly. So may be your source and actual running code might not be synced up due to issue 2. So let's address that first.
In WSO2 servers lib folder is used to add non-OSGi dependencies and dropins for OSGi dependencies. Fact that it works in lib and not in dropins suggest that your jar is not packed as a bundle. To achieve that please follow below pom file from String extension. There are two things to note.
[1] Usage of bundle packaging
[2] Usage of bundle plugin
Update your pom referencing this and then you will be able to add your bundle to dropins directly. Also this is the reason why your changes are not reflected. When you add your jar to lib server will internally convert it to an OSGi bundle and add to dropins. Now when you update the jar in lib again the one in dropins will not get updated. It will be the old bundle. Hence changes are not reflected. This issue will also go away when you update the pom and build the bundle correctly.
[1] https://github.com/wso2/siddhi/blob/v3.1.0/modules/siddhi-extensions/string/pom.xml#L29
[2] https://github.com/wso2/siddhi/blob/v3.1.0/modules/siddhi-extensions/string/pom.xml#L57
Hope this helps!!

unable to launch spring-data-rest unit test, RepositoryRestResource not available for #Autowire

I'm porting an app across from JDBC / REST to spring-data-rest and my one and only unit test with fails with the error
NoSuchBeanDefinitionException:
No qualifying bean of type 'com.xxx.repository.ForecastRepository' available
The app was retro-fitted with spring-boot just previously, and now I'm trying to put a new layer in place with spring-data-rest on top of spring-data-jpa.
I'm attempting to work out the correct Java-config according to
Custom Test Slice with Spring Boot 1.4
but I had to deviate from the idiomatic approach because
the #WebMvcTest annotation doesn't suppress the security module which causes the test to fail
the #MockMvcAutoConfiguration fails due to missing dependencies unless I specify #SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) (see here)
#WebMvcTest and #SpringBootTest are mutually exclusive since they both specify #BootstrapWith and can't run together
So this is the closest I've got but Spring can't locate my #RepositoryRestResource repository:
Repository
#RepositoryRestResource(collectionResourceRel = "forecasts", path = "forecasts")
public interface ForecastRepository extends CrudRepository<ForecastExEncoded,
Long> {
JUnit Test
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK,
classes = {TestRestConfiguration.class})
public class ForecastRestTests {
#Autowired
private MockMvc mockMvc;
#Autowired
private ForecastRepository forecastRepository;
#Before
public void deleteAllBeforeTests() throws Exception {
forecastRepository.deleteAll();
}
#Test
public void shouldReturnRepositoryIndex() throws Exception {
mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk()).andExpect(
jsonPath("$._links.forecasts").exists());
}
}
Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
RepositoryRestMvcAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
WebMvcAutoConfiguration.class,
MockMvcAutoConfiguration.class,
MockMvcSecurityAutoConfiguration.class
})
#Import({PropertySpringConfig.class})
public class TestRestConfiguration {}
Also tried...
I tried to configure the unit test with just #WebMvcTest and this #ComponentScan below from How to exclude AutoConfiguration from Spring Boot), in an attempt to simplify it all, however the excludeFilters had no effect.
#ComponentScan(
basePackages="com.xxx",
excludeFilters = {
#ComponentScan.Filter(type = ASSIGNABLE_TYPE,
value = {
SpringBootWebApplication.class,
JpaDataConfiguration.class,
SecurityConfig.class
})
})
I've set Spring's logging to trace because all I can do at this point is try to find clues as to what is happening from log output. So far though without any luck.
I can see in the logging that RepositoryRestConfiguration is loading, but obviously it isn't fed with the right info and I am unable to work out how that is done, after googling and pouring over the Spring docs and API. I think I must have read every relevant question here on SO .
Update 2016-11-16 10:00
One thing I see in the logs which concerns me is this:
Performing dependency injection for test context [DefaultTestContext#2b4a2ec7 [snip...]
classes = '{class com.xxx.TestRestConfiguration,
class com.xxx.TestRestConfiguration}',
i.e. the context lists the configuration class twice. I specified the config class (once only) on the #SpringBootTest#classes annotation. But if I leave off the #classes from the annotation, Spring Boot finds and pulls in all the config via the #SpringBootApplication class.
So is that a hint that I am specifying the configuration in the wrong place? How else would I do it?
After way too much time, I settled on this approach.
Custom Test Slice with Spring Boot 1.4 looked promising but I couldn't get anywhere with it.
While going over and over
Accessing JPA Data with REST
I realised I had to include the JPA setup because spring-data-rest is using them directly - no chance to mock them or run unit tests without an embedded database.
At least not as far as I understand it. Maybe it is possible to mock them and have spring-data-rest run on the mocks against test data, but I think spring-data-rest and spring-data are probably too tightly coupled.
So integration testing it must be.
In the Spring source code provided with the articles above
gs-accessing-data-rest/ApplicationTests.java
the logging shows Spring Boot pulling in the whole configuration for the application context.
So that my SpringBootApplication class is avoided and the security module isn't loaded up, I set up my tests like this:
#RunWith(SpringRunner.class)
#SpringBootTest
#ContextConfiguration(classes = {
JpaDataConfiguration.class,
TestJpaConfiguration.class,
TestRestConfiguration.class,
PropertySpringConfig.class})
public class ForecastRestTests {
#SuppressWarnings("SpringJavaAutowiringInspection")
#Autowired
private MockMvc mockMvc;
#Autowired
private ForecastRepository forecastRepository;
#Before
public void deleteAllBeforeTests() throws Exception {
forecastRepository.deleteAll();
}
#Test
public void shouldReturnRepositoryIndex() throws Exception {
mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk()).andExpect(
jsonPath("$._links.forecasts").exists());
}
}
with these configuration classes:
#Configuration
#EnableJpaRepositories(basePackages = {"com.bp.gis.tardis.repository"})
#EntityScan(basePackages = {"com.bp.gis.tardis.type"})
public class JpaDataConfiguration {
and
#Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
CacheAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
TransactionAutoConfiguration.class,
TestDatabaseAutoConfiguration.class,
TestEntityManagerAutoConfiguration.class })
public class TestJpaConfiguration {}
and
#Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
RepositoryRestMvcAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
WebMvcAutoConfiguration.class,
MockMvcAutoConfiguration.class,
MockMvcSecurityAutoConfiguration.class
})
public class TestRestConfiguration {}
so the TL;DR summary is: use #ContextConfiguration to specify the configuration files that specify #OverrideAutoConfiguration and #ImportAutoConfiguration

Mock SomeClass.getClassLoader() when called in method (Mockito / PowerMockito)

I have inherited some code that isn't tested and which loads a resource using a method like :
SomeClass.class.getClassLoader().getResource("somefile");
I've written the following test but there are 0 interactions with the Mock class loader I've created. Can anyone comment on whether this type of test is possible.
public enum SomeClass {
INSTANCE;
public boolean someMethod() {
URL pathToLicense = SomeClass.class.getClassLoader().getResource("somefile");
return false;
}
}
#Test
public void testLicenseWorkflow(){
ClassLoader cl = PowerMockito.mock(ClassLoader.class);
File f = new File("someFile");
assertTrue(f.exists());
logger.info(f.getCanonicalPath() );
when(cl.getResource("somefile")).thenReturn(f.toURL());
verify(cl).getResource("somefile");
assertTrue(SomeClass.INSTANCE.someMethod());
}
Update - Adding a resources via Classloader
I've also tried the following but the someMethod this doens't seem to work either
new URLClassLoader(((URLClassLoader) SomeClass.INSTANCE.getClass().getClassLoader()).getURLs()) {
#Override
public void addURL(URL url) {
super.addURL(url);
logger.info("Calling add URL");
}
}.addURL(f.toURI().toURL());
You are not passing cl to anything. You prepare a mock for a classloader but then proceed to load the resource with another classloader, the one that loaded SomeClass. That is why you have 0 interactions in your mock.
And about your first question, it is possible if somehow you pass your mocked classloader to the method that actually loads the resource. For example, something like
public boolean someMethod(Classloader loader) {
URL pathToLicense = loader.getResource("somefile");
return false;
}
But I have to say that IMO, this test is not very useful, you should be mocking your own components, not java classes. If your goal mocking the classloader is to inject a different file when testing, a better approach is to change your code to receive a Stream and inject a stream connected to the file in production and in testing inject a stream connected to an element in memory.
In other words, resources make for bad testing when they need to be changed at test time

How to unit test this route builder in camel?

I have the following RouteBuilder Class and I am using dependency injection here. How can I test this route builder? I am using JUnit and camel test classes.
public class TestRoute extends RouteBuilder {
private ServiceConfiguration serviceConfiguration;
public TestRoute(ServiceConfiguration serviceConfiguration) {
this.serviceConfiguration = serviceConfiguration;
}
#Override
public void configure() throws Exception {
String incomingURI = serviceConfiguration.getQueueConfiguration().getURI();
String outgoingURI = serviceConfiguration.getHTTPConfiguration().getURI();
from(incomingURI).
setHeader(Exchange.HTTP_METHOD, constant("PUT")).setHeader(Exchange.CONTENT_TYPE, constant("application/json")).
to(outgoingURI);
}
}
My thoughts:
Creating a testConfiguration extending ServiceConfiguration and pass that. But for that I need to set all the configuration and all because the serviceConfiguration contains many other classes. Can I use Mockito here? What is the correct and easy way to test this?
EDIT: I was using the existing route, so that I don't have to write it again. Looks like that is not the correct way of testing in camel. See my test class. Of course, its not working.
public class RabbitMQRouteTest extends CamelTestSupport {
#Mock
ServiceConfiguration serviceConfiguration;
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
System.out.println("testing");
return new TestRoute(serviceConfiguration);
}
#Test
public void testConfigure() throws Exception {
System.out.println("test");
when(serviceConfiguration.getName()).thenReturn("file://target/inbox");
template.sendBodyAndHeader("file://target/inbox", "Hello World",Exchange.FILE_NAME, "hello.txt");
Thread.sleep(1000);
File target = new File("target/outbox/hello.txt");
assertTrue("File not moved", target.exists());
}
}
As you use #Mock, MockitoAnnotations.initMocks has to be invoked. Additionally, when has also be called before passing the reference to TestRoute:
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
// Initialize serviceConfiguration
MockitoAnnotations.initMocks(this);
when(serviceConfiguration.getName()).thenReturn("file://target/inbox");
return new TestRoute(serviceConfiguration);
}
Alternatively to #Mock and MockitoAnnotations.initMocks, just use:
serviceConfiguration = org.mockito.Mockito.mock(ServiceConfiguration.class);
As when is invoked in createRouteBuilder, serviceConfiguration.getName() always returns the same result for all test methods in the JUnit test class. This could be a problem, if different test methods need different URIs.
Alternatively, you may use adviceWith instead as described here.
Camel has two ways to do the route tests, CamelSpringTestSupport and CamelTestSupport.
CamelSpringTestSupport
You can set the route with some camel-whatever-test.xml to setup the route in Spring configuration xml.
CamelTestSupport
You can set the route with RouteBuilder createRoute. And configure the endpoint with mock components.
Here is some reference link, do not forget to add the dependency jars:
http://camel.apache.org/testing.html
Using mockito makes sense in your case as you only need some small parts of the ServiceConfiguration.
On the other hand it is a bad sign that you need it for setting configuration data. You should check if your configuration can be split up into separate parts or not be used in the RouteBuilder at all. If you have one configuration structure that is used in all parts of your code you create a tight coupling between things that should be separate. If you just need the two properties queue uri and http uri in your routebuilder then consider just having two setters for them.