Accessing AWS Lambda Context from Spring Cloud Function - amazon-web-services

I'm using Spring Cloud Function 1.0.0.RELEASE and the corresponding AWS adapter to run it in AWS lambda. Is there any way to retrieve the lambda function context from the Spring application context?
I know if you implement the RequestHandler interface yourself, then you get the Context object as the second parameter of the handleRequest method (see below), but since the SpringBootRequestHandler is handling this, it's not clear to me how to access the Context object. Any ideas?
Example of implementing RequestHandler directly
public class LambdaRequestHandler implements RequestHandler<String, String> {
public String handleRequest(String input, Context context) {
context.getLogger().log("Input: " + input);
return "Hello World - " + input;
}
}
Deferring the implementation of RequestHandler to SpringBootRequestHandler
public class SomeFunctionHandler
extends SpringBootRequestHandler<SomeRequest, SomeResponse> {
}

SomeFunctionHandler extends the SpringBootRequestHandler, so it can override the handleRequest method to get access to the AWS lambda Context object.
public class SomeFunctionHandler extends SpringBootRequestHandler<SomeRequest, SomeResponse> {
private static final Logger logger = LoggerFactory.getLogger(SomeFunctionHandler.class);
#Override
public Object handleRequest(SomeRequest event, Context context) {
logger.info("ARN=" + context.getInvokedFunctionArn());
return super.handleRequest(event, context);
}
}

If you're using spring-cloud-function-adapter-aws only, #Autowired might not work.
However, you could wrap your input with org.springframework.messaging.Message.
public class FooHandler implements Function<Message<DynamodbEvent>, String> {
#Override
public String apply(Message<DynamodbEvent> message) {
// Get AWS Lambda Context
Context context = message.getHeaders().get("aws-context", Context.class);
assert context != null;
// Get the original input
DynamodbEvent payload = message.getPayload();
return payload.toString();
}
}
Source:
FunctionInvoker#handleRequest
AWSLambdaUtils#generateMessage

In case you are exposing Function as a bean, you can simply Autowire the Context object.
Example:
#Autowired
private Context context;
#Bean
public Function<String, String> uppercase() {
logger.info("ARN=" + context.getInvokedFunctionArn());
return value -> {
if (value.equals("exception")) {
throw new RuntimeException("Intentional exception which should result in HTTP 417");
}
else {
return value.toUpperCase();
}
};
}
Source : this answer.

Related

Apache Camel Beans Unit Testing

I am using Apache Camel with Spring boot in my application. Currently I am working on a Unit test.
Java Code
DataRoute class
from("direct:getData")
.routeId("getData")
.bean(DataService.class, "processData")
.marshal().json(JsonLibrary.Jackson)
.end();
DataService class
public Data processData() {
return new Data("Hello World");
}
Data Class with getters, setters and Jackson toString method
private String value;
Unit test
BaseCamelContextUnitText
public abstract class BaseCamelContextUnitTest extends CamelTestSupport
{
#Autowired
private DataService dataService;
#Produce
private ProducerTemplate producerTemplate;
public CamelContext getCamelContext() {
return camelContext;
}
#Override
protected Context createJndiContext() throws Exception {
JndiContext context = new JndiContext();
context.bind("dataService", dataService);
return context;
}
#Test
public void shouldProcessData() throws Exception {
RouteDefinition routeDef = getCamelContext().getRouteDefinition("getData");
routeDef.adviceWith((ModelCamelContext) getCamelContext(), new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:getData")
.pipeline("bean:dataService?method=processData");
}
});
getCamelContext().start();
String responseData = "{"
+ "\"value\":\"Unit test success\""
+ "}";
Object response = producerTemplate.sendBody("direct:getData", ExchangePattern.InOut, null);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
((InputStreamCache) response).writeTo(byteArrayOutputStream);
assertThat(new String(byteArrayOutputStream.toByteArray()), is(responseData));
}
}
How do I mock
.bean(DataService.class, "processData")
in the unit test to return a mock Data Object with its default String variable as say "Unit test success" and then test to see if the route would give back the mocked Object instead of the Object with "Hello World" String variable?
This may seem's a late response, but I faced the same thing as described in your case, and I come across a simple way to "mock" the bean step, by using the DefaultRegistry to register the mocked bean into Camel registry, for example :
#Test
public void shouldProcessData() throws Exception {
...
...
DataService dataService = new DataService(...);
stubBean("dataService", dataService); // put this before calling context.start();
context.start();
...
...
}
/**
* This method inject a stub bean into the registry
* #param beanName the name of the bean being injected
* #param instance the stub instance
*/
void stubBean(String beanName, Object instance) {
DefaultRegistry registry = context.getRegistry(DefaultRegistry.class);
registry.bind(beanName, instance);
}
You can autowired the DataService in your DataRoute like
#Component
public class DataRoute extends RouteBuilder {
#Autowired
private DataService dataService;
#Override
public void configure() throws Exception {
from("direct:getData")
.routeId("getData")
.bean(dataService, "processData")
.marshal().json(JsonLibrary.Jackson)
.end();
}
}
So you can mock the DataService as usual.
An alternative is using beanRef("beanName", "methodName") in the Route.

Test case for Struts2 2.3.24 using Strut2SpringTestCase (request object is coming as null)

I am trying to write unit test cases for my Struts2 action classes. My Test class extends SpringStrutsTestCase class. I am able to set the request object and able to get the action and action is also getting called but when in action it tries to get the parameters set in request object it throws null pointer exception i.e. request object is going as null. Below is my what my test class looks like. Any help is really appreciated.
import org.apache.struts2.StrutsSpringTestCase;
import org.junit.Test;
import com.opensymphony.xwork2.ActionProxy;
public class testClass extends StrutsSpringTestCase {
#Test
public void test1() throws Exception {
try {
request.setParameter("p1", "v1");
request.setParameter("p2", "v2");
ActionProxy proxy = getActionProxy("/actionName");
MyActionClass loginAction = (MyActionClass) proxy.getAction();
loginAction.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public String[] getContextLocations() {
String[] arr = new String[] { "one.xml", "two.xml", "three.xml" };
return arr;
}
}
Here is my action class.
public class MyAction extends ActionSupport{
private String p1;
private String p2;
/*
Gettere and Setters of p1 and p2
*/
public String execute() throws Exception {
// return "success";
logger.info("Login Action Called");
String pv1= (String) request.getParameter("p1");// If I get value using this.pv1 it works fine but with this code it doesn't.
String pv2= (String) request.getParameter("p2");
return "success";
}
}
In order to test an action call you need to call execute method of ActionProxy. By calling execute of your action you are just invoking that particular method of the action class and not S2 action along with the interceptors, results, etc.
The correct way would be:
ActionProxy proxy = getActionProxy("/actionName");
proxy.execute();
BTW if you're using JUnit 4 there is StrutsSpringJUnit4TestCase which you should use instead of StrutsSpringTestCase.

How to use Moq to Prove that the Method under test Calls another Method

I am working on a unit test of an instance method. The method happens to be an ASP.NET MVC 4 controller action, but I don't think that really matters much. We just found a bug in this method, and I'd like to use TDD to fix the bug and make sure it doesn't come back.
The method under test calls a service which returns an object. It then calls an internal method passing a string property of this object. The bug is that under some circumstances, the service returns null, causing the method under test to throw a NullReferenceException.
The controller uses dependency injection, so I have been able to mock the service client to have it return a null object. The problem is that I want to change the method under test so that when the service returns null, the internal method should be called with a default string value.
The only way I could think to do this is to use a mock for the class under test. I want to be able to assert, or Verify that this internal method has been called with the correct default value. When I try this, I get a MockException stating that the invocation was not performed on the mock. Yet I was able to debug the code and see the internal method being called, with the correct parameters.
What's the right way to prove that the method under test calls another method passing a particular parameter value?
I think there's a code smell here. The first question I'll ask myself in such a situation is, is the "internal" method really internal/ private to the controller under test. Is it the controller's responsibility to do the "internal" task? Should the controller change when the internal method's implementation changes? May be not.
In that case, I would pull out a new targeted class, which has a public method which does the stuff which was until now internal to the controller.
With this refactoring in place, I would use the callback mechanism of MOQ and assert the argument value.
So eventually, you will end up mocking two dependancies:
1. The external service
2. The new targeted class which has the controller's internal implementation
Now your controller is completely isolated and can be unit tested independently. Also, the "internal" implementation becomes unit testable and should have its own set of unit tests too.
So your code and test would look something like this:
public class ControllerUnderTest
{
private IExternalService Service { get; set; }
private NewFocusedClass NewFocusedClass { get; set; }
const string DefaultValue = "DefaultValue";
public ControllerUnderTest(IExternalService service, NewFocusedClass newFocusedClass)
{
Service = service;
NewFocusedClass = newFocusedClass;
}
public void MethodUnderTest()
{
var returnedValue = Service.ExternalMethod();
string valueToBePassed;
if (returnedValue == null)
{
valueToBePassed = DefaultValue;
}
else
{
valueToBePassed = returnedValue.StringProperty;
}
NewFocusedClass.FocusedBehvaior(valueToBePassed);
}
}
public interface IExternalService
{
ReturnClass ExternalMethod();
}
public class NewFocusedClass
{
public virtual void FocusedBehvaior(string param)
{
}
}
public class ReturnClass
{
public string StringProperty { get; set; }
}
[TestClass]
public class ControllerTests
{
[TestMethod]
public void TestMethod()
{
//Given
var mockService = new Mock<IExternalService>();
mockService.Setup(s => s.ExternalMethod()).Returns((ReturnClass)null);
var mockFocusedClass = new Mock<NewFocusedClass>();
var actualParam = string.Empty;
mockFocusedClass.Setup(x => x.FocusedBehvaior(It.IsAny<string>())).Callback<string>(param => actualParam = param);
//when
var controller = new ControllerUnderTest(mockService.Object, mockFocusedClass.Object);
controller.MethodUnderTest();
//then
Assert.AreEqual("DefaultValue", actualParam);
}
}
Edit: Based on the suggestion in the comments to use "verify" instead of callback.
Easier way to verify the parameter value is by using strict MOQ behavior and a verify call on the mock after system under test is executed.
Modified test could look like below:
[TestMethod]
public void TestMethod()
{
//Given
var mockService = new Mock<IExternalService>();
mockService.Setup(s => s.ExternalMethod()).Returns((ReturnClass)null);
var mockFocusedClass = new Mock<NewFocusedClass>(MockBehavior.Strict);
mockFocusedClass.Setup(x => x.FocusedBehvaior(It.Is<string>(s => s == "DefaultValue")));
//When
var controller = new ControllerUnderTest(mockService.Object, mockFocusedClass.Object);
controller.MethodUnderTest();
//Then
mockFocusedClass.Verify();
}
"The only way I could think to do this is to use a mock for the class under test."
I think you should not mock class under test. Mock only external dependencies your class under test has. What you could do is to create a testable-class. It would be a class which derives from your CUT and here you can catch the calls to the another method and verify it's parameter later. HTH
Testable class in the example is named MyTestableController
Another method is named InternalMethod.
Short example:
[TestClass]
public class Tests
{
[TestMethod]
public void MethodUnderTest_WhenServiceReturnsNull_CallsInternalMethodWithDefault()
{
// Arrange
Mock<IService> serviceStub = new Mock<IService>();
serviceStub.Setup(s => s.ServiceCall()).Returns((ReturnedFromService)null);
MyTestableController testedController = new MyTestableController(serviceStub.Object)
{
FakeInternalMethod = true
};
// Act
testedController.MethodUnderTest();
// Assert
Assert.AreEqual(testedController.SomeDefaultValue, testedController.FakeInternalMethodWasCalledWithThisParameter);
}
private class MyTestableController
: MyController
{
public bool FakeInternalMethod { get; set; }
public string FakeInternalMethodWasCalledWithThisParameter { get; set; }
public MyTestableController(IService service)
: base(service)
{ }
internal override void InternalMethod(string someProperty)
{
if (FakeInternalMethod)
FakeInternalMethodWasCalledWithThisParameter = someProperty;
else
base.InternalMethod(someProperty);
}
}
}
The CUT could look something like this:
public class MyController : Controller
{
private readonly IService _service;
public MyController(IService service)
{
_service = service;
}
public virtual string SomeDefaultValue { get { return "SomeDefaultValue"; }}
public EmptyResult MethodUnderTest()
{
// We just found a bug in this method ...
// The method under test calls a service which returns an object.
ReturnedFromService fromService = _service.ServiceCall();
// It then calls an internal method passing a string property of this object
string someStringProperty = fromService == null
? SomeDefaultValue
: fromService.SomeProperty;
InternalMethod(someStringProperty);
return new EmptyResult();
}
internal virtual void InternalMethod(string someProperty)
{
throw new NotImplementedException();
}
}

Mocking addProvider(Class<?> klass)

I am trying to get used Mockito.
I have a class
#Provider
public class SessionProvider implements InjectableProvider<Bind, Type>{
#Override
public ComponentScope getScope() {
return ComponentScope.PerRequest;
}
#Override
public Injectable getInjectable(ComponentContext ic, Bind bind, Type parameter) {
return new SessionInjectable();
}
}
And trying to return null when getInjectable is called.
My use case is like so
public void addProvider(Class<?> klass) {
providers.add(klass);
}
addProvider(SessionProvider.class);
How can I successfully mock SessionProvider.class?
Thanks
Edit:
My class is like so:
#Path("message")
#Produces(MediaType.APPLICATION_JSON)
public class MessageResource {
#POST
#Path("post")
public String testPostMessage(#Bind Session session, Message message) {
return "posted";
}
}
Bind annotation is using my provider. But my current framework does not accept instances of SessionProvider. It is utilizing Class instances.
By the way this is a web service. It is called by my client implementation. I would like to test my message with a mocked session. And for each request it is requested a new one. That is the reason the method is accepting Session Class instead of Session Instance.
I really started to feel that there is something wrong but at where?
Thanks
By default a mock return null :
SessionProvider sessionProvider = mock(SessionProvider.class);
assertNull(sessionProvider.getInjectable(ic, bind, parameter));
For a unit test, you can test MessageResource by invoking testPostMessage with mocks :
messageResource.testPostMessage(mock(SessionMessage.class), mock(Message.class));
or, you could create a mock SessionProvider class returning a mock Session :
#Provider
public class MockSessionProvider implements InjectableProvider<Bind, Type>{
public Injectable getInjectable(ComponentContext ic, Bind bind, Type parameter) {
return mock(Session.class);
}
}
and then register it on the framework :
addProvider(MockSessionProvider.class);

How to make AfterBeanDiscovery get triggered in JUnit

I have the following four classes: DataConsumer, DataProducer, SomeQualifier, a META-INF/beans.xml and a test. The class files are coded as follows:
public class DataConsumer {
private boolean loaded = false;
#Inject
#SomeQualifier
private String someString;
public void afterBeanDiscovery(
#Observes final AfterBeanDiscovery afterBeanDiscovery,
final BeanManager manager) {
loaded = true;
}
public boolean getLoaded() {
return loaded;
}
public String sayHello() {
return someString;
}
}
public class DataProducer {
#Produces
#SomeQualifier
private final String sample = "sample";
}
public #interface SomeQualifier {
}
The unit test looks like this.
public class WeldTest {
#Test
public void testHelloWorld() {
final WeldContainer weld = new Weld().initialize();
final DataConsumer consumer = weld.instance()
.select(DataConsumer.class).get();
Assert.assertEquals("sample", consumer.sayHello());
Assert.assertTrue(consumer.getLoaded());
}
}
However, it is failing on the assertTrue with getLoaded() it appears that the #Observes does not get fired.
Take a look at arquillian: www.arquillian.org. It'll take care of all of this for you.
I found a similar question that had answered my question
CDI - Observing Container Events
Although I am unable to use DataConsumer as both an Extension and a CDI managed bean. So it needs a third class just to be the Extension. However, because Extension have no access to managed beans since they are not created yet, I conclude that is no possible solution to use an #Observes AfterBeanDiscovery to modify the bean data. Even the BeanManager that gets passed in cannot find any of the beans.