I have a spring application and when i trigger the lambda function from API Gateway , "Endpoint request timed out" error is coming.The code is given below.
public class LambdaHandler implements RequestHandler<AwsProxyRequest, AwsProxyResponse> {
private static final Logger LOG = LoggerFactory.getLogger(LambdaHandler.class);
private SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
#Override
public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context) {
try {
handler = SpringLambdaContainerHandler.getAwsProxyHandler(MvcConfig.class);
} catch (ContainerInitializationException e) {
LOG.warn("Unable to create handler", e);
return null;
}
return handler.proxy(awsProxyRequest, context);
}
}
The MvcConfig class is :-
#SpringBootApplication
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = {"com.joeyvmason.serverless.spring"})
public class MvcConfig {
}
and HelloController class is :-
#RestController
#RequestMapping("/hello")
public class HelloController {
#RequestMapping(method = RequestMethod.GET)
public String hello(#PathVariable String id) {
return "Hello World!";
}
}
Thanks in advance for the help
Related
I am following this article to implement a database read/write separation feature by calling different methods. However, I got the error:
Missing method call for verify(mock) here: verify(spyDatabaseContextHolder, times(1)).set(DatabaseEnvironment.READONLY);
when doing the testing.
My test case is trying to verify DatabaseEnvironment.READONLY has been set once when using TransactionReadonlyAspect AOP annotation:
// TransactionReadonlyAspectTest.java
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {LoadServiceImpl.class, TransactionReadonlyAspect.class})
public class TransactionReadonlyAspectTest {
#Autowired
private TransactionReadonlyAspect transactionReadonlyAspect;
#MockBean
private LoadServiceImpl loadService;
#Test
public void testReadOnlyTransaction() throws Throwable {
ProceedingJoinPoint mockProceedingJoinPoint = mock(ProceedingJoinPoint.class);
Transactional mockTransactional = mock(Transactional.class);
DatabaseContextHolder spyDatabaseContextHolder = mock(DatabaseContextHolder.class);
when(mockTransactional.readOnly()).thenReturn(true);
when(loadService.findById(16)).thenReturn(null);
when(mockProceedingJoinPoint.proceed()).thenAnswer(invocation -> loadService.findById(16));
transactionReadonlyAspect.proceed(mockProceedingJoinPoint, mockTransactional);
verify(spyDatabaseContextHolder, times(1)).set(DatabaseEnvironment.READONLY); // got the error: Missing method call for verify(mock)
verify(loadService, times(1)).findById(16);
assertEquals(DatabaseContextHolder.getEnvironment(), DatabaseEnvironment.UPDATABLE);
}
}
//TransactionReadonlyAspect.java
#Aspect
#Component
#Order(0)
#Slf4j
public class TransactionReadonlyAspect {
#Around("#annotation(transactional)")
public Object proceed(ProceedingJoinPoint proceedingJoinPoint,
org.springframework.transaction.annotation.Transactional transactional) throws Throwable {
try {
if (transactional.readOnly()) {
log.info("Inside method " + proceedingJoinPoint.getSignature());
DatabaseContextHolder.set(DatabaseEnvironment.READONLY);
}
return proceedingJoinPoint.proceed();
} finally {
DatabaseContextHolder.reset();
}
}
}
// DatabaseContextHolder.java
public class DatabaseContextHolder {
private static final ThreadLocal<DatabaseEnvironment> CONTEXT = new ThreadLocal<>();
public static void set(DatabaseEnvironment databaseEnvironment) {
CONTEXT.set(databaseEnvironment);
}
public static DatabaseEnvironment getEnvironment() {
DatabaseEnvironment context = CONTEXT.get();
System.out.println("context: " + context);
return CONTEXT.get();
}
public static void reset() {
CONTEXT.set(DatabaseEnvironment.UPDATABLE);
}
}
//DatabaseEnvironment.java
public enum DatabaseEnvironment {
UPDATABLE,READONLY
}
// LoadServiceImpl.java
#Service
public class LoadServiceImpl implements LoadService {
#Override
#Transactional(readOnly = true)
public LoadEntity findById(Integer Id) {
return this.loadDAO.findById(Id);
}
...
}
I just want to test DatabaseContextHolder.set(DatabaseEnvironment.READONLY) has been used once then in the TransactionReadonlyAspect finally block it will be reset to DatabaseEnvironment.UPDATABLE which make sense.
However, how to test DatabaseContextHolder.set(DatabaseEnvironment.READONLY) gets called once? Why does this error occur? Is there a better way to test TransactionReadonlyAspect?
I am trying to write and test an application that used spring-cloud with azure functions following this tutorial.
https://github.com/markusgulden/aws-tutorials/tree/master/spring-cloud-function/spring-cloud-function-azure/src/main/java/de/margul/awstutorials/springcloudfunction/azure
I am tryign to write a testcase and override the bean.
Here is the application class having function and handler Bean function.
#SpringBootApplication
#ComponentScan(basePackages = { "com.package" })
public class DataFunctions extends AzureSpringBootRequestHandler<GenericMessage<Optional<String>>, Data> {
#FunctionName("addData")
public HttpResponseMessage addDataRun(
#HttpTrigger(name = "add", methods = {
HttpMethod.POST }, authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) throws JsonParseException, JsonMappingException, IOException {
context.getLogger().info("Java HTTP trigger processed a POST request.");
try {
handleRequest(new GenericMessage<Optional<String>>(request.getBody()), context);
} catch (ServiceException ex) {
ErrorMessage em = new ErrorMessage();
return request.createResponseBuilder(handleException(ex, em)).body(em).build();
}
return request.createResponseBuilder(HttpStatus.CREATED).build();
}
#Autowired
MyService mService;
#Bean
public Consumer<GenericMessage<Optional<String>>> addData() {
ObjectMapper mapper = new ObjectMapper();
return req -> {
SomeModel fp = null;
try {
fp = mapper.readValue(req.getPayload().get(), SomeModel.class);
} catch (Exception e) {
throw new ServiceException(e);
}
mService.addData(fp);
};
}
}
I want to test by overriding the above bean.
Cosmosdb spring configuration
#Configuration
#EnableDocumentDbRepositories
public class CosmosDBConfig extends AbstractDocumentDbConfiguration {
#Value("${cosmosdb.collection.endpoint}")
private String uri;
#Value("${cosmosdb.collection.key}")
private String key;
#Value("${cosmosdb.collection.dbname}")
private String dbName;
#Value("${cosmosdb.connect.directly}")
private Boolean connectDirectly;
#Override
public DocumentDBConfig getConfig() {
ConnectionPolicy cp = ConnectionPolicy.GetDefault();
if (connectDirectly) {
cp.setConnectionMode(ConnectionMode.DirectHttps);
} else {
cp.setConnectionMode(ConnectionMode.Gateway);
}
return DocumentDBConfig.builder(uri, key, dbName).connectionPolicy(cp).build();
}
}
Here is the configuration
#TestConfiguration
#PropertySource(value = "classpath:application.properties", encoding = "UTF-8")
#Profile("test")
#Import({DataFunctions.class})
public class TestConfig {
#Bean(name="addData")
#Primary
public Consumer<GenericMessage<Optional<String>>> addData() {
return req -> {
System.out.println("data mock");
};
}
#Bean
#Primary
public DocumentDBConfig getConfig() {
return Mockito.mock(DocumentDBConfig.class);
}
}
Finally the test class
#RunWith(SpringRunner.class)
//#SpringBootTest //Enabling this gives initialization error.
#ActiveProfiles("test")
public class TempTest {
#InjectMocks
DataFunctions func;
#Mock
MyService mService;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
private Optional<String> createRequestString(final String res) throws IOException {
InputStream iStream = TempTest.class.getResourceAsStream(res);
String charset="UTF-8";
try (BufferedReader br = new BufferedReader(new InputStreamReader(iStream, charset))) {
return Optional.of(br.lines().collect(Collectors.joining(System.lineSeparator())));
}
}
#Test
public void testHttpPostTriggerJava() throws Exception {
#SuppressWarnings("unchecked")
final HttpRequestMessage<Optional<String>> req = mock(HttpRequestMessage.class);
final Optional<String> queryBody = createRequestString("/test-data.json");
doNothing().when(mService).addData(Mockito.any(SomeModel.class));
doReturn(queryBody).when(req).getBody();
doAnswer(new Answer<HttpResponseMessage.Builder>() {
#Override
public HttpResponseMessage.Builder answer(InvocationOnMock invocation) {
HttpStatus status = (HttpStatus) invocation.getArguments()[0];
return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status);
}
}).when(req).createResponseBuilder(any(HttpStatus.class));
final ExecutionContext context = mock(ExecutionContext.class);
doReturn(Logger.getGlobal()).when(context).getLogger();
doReturn("addData").when(context).getFunctionName();
// Invoke
final HttpResponseMessage ret = func.addDataRun(req, context);
// Verify
assertEquals(ret.getStatus(), HttpStatus.CREATED);
}
}
For this case instead of test configuration addData the actual bean is called from DataFunctions class. Also the database connection is also created when it should use the mocked bean from my test configuration. Can somebody please point out what is wrong in my test configuration?
I was able to resolve the first part of cosmos db config loading by marking it with
#Configuration
#EnableDocumentDbRepositories
#Profile("!test")
public class CosmosDBConfig extends AbstractDocumentDbConfiguration {
...
}
Also had to mark the repository bean as optional in the service.
public class MyService {
#Autowired(required = false)
private MyRepository myRepo;
}
Didn't use any spring boot configuration other than this.
#ActiveProfiles("test")
public class FunctionTest {
...
}
For the second part of providing mock version of Mock handlers, I simply made the test config file as spring application as below.
#SpringBootApplication
#ComponentScan(basePackages = { "com.boeing.da.helix.utm.traffic" })
#Profile("test")
public class TestConfiguration {
public static void main(final String[] args) {
SpringApplication.run(TestConfiguration.class, args);
}
#Bean(name="addData")
#Primary
public Consumer<GenericMessage<Optional<String>>> addData() {
return req -> {
System.out.println("data mock");
};
}
}
and made use of this constructor from azure functions library in spring cloud in my constructor
public class AppFunctions
extends AzureSpringBootRequestHandler<GenericMessage<Optional<String>>, List<Data>> {
public AppFunctions(Class<?> configurationClass) {
super(configurationClass);
}
}
public AzureSpringBootRequestHandler(Class<?> configurationClass) {
super(configurationClass);
}
Hope it helps someone.
I have the following Spring Boot controller:
#Controller
public class TestController {
#Autowired
private TestService service;
#GetMapping(path="/hello")
public ResponseEntity<String> handleGet() {
return service.getResponse();
}
#GetMapping(path="/hello/hystrix")
public Future<ResponseEntity<String>> handleGetAsync() {
return service.getResponseAsync();
}
#GetMapping(path="/hello/cf")
public Future<ResponseEntity<String>> handleGetCF() {
return service.getResponseCF();
}
}
and service:
#Service
public class TestService {
#HystrixCommand
public ResponseEntity<String> getResponse() {
ResponseEntity<String> response = ResponseEntity.status(HttpStatus.OK).body("Hello");
return response;
}
#HystrixCommand
public Future<ResponseEntity<String>> getResponseAsync() {
return new AsyncResult<ResponseEntity<String>>() {
#Override
public ResponseEntity<String> invoke() {
return getResponse();
}
};
}
public Future<ResponseEntity<String>> getResponseCF() {
return CompletableFuture.supplyAsync(() -> getResponse());
}
}
and application:
#EnableHystrix
#SpringBootApplication
#EnableAsync
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
}
When I hit the /hello/cf endpoint, I get a response "Hello"
When I hit the /hello/hystrix endpoint, I get a 404 error.
Am I able to return an AsyncResult from a controller in this manner? If so, what am I doing wrong?
Thanks.
Your service class needs to return a CompletableFuture.
Also, unless you are using AspectJ, the circuit breaker will not work if the method with #HystrixCommand is called from within the same class.
As I know, feign include ribbon's function, and I prove it in my code.
When I use feign, the default rule is Round Robin Rule.
But how can I change the rule in my feign client code, is ribbon the only way?
Here is my code below, so please help.
ConsumerApplication.java
#SpringBootApplication
#EnableDiscoveryClient
#EnableFeignClients
#EnableCircuitBreaker
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
UserFeignClient .java
#FeignClient(name = "cloud-provider", fallback = UserFeignClient.HystrixClientFallback.class)
public interface UserFeignClient {
#RequestMapping("/{id}")
BaseResponse findByIdFeign(#RequestParam("id") Long id);
#RequestMapping("/add")
BaseResponse addUserFeign(UserVo userVo);
#Component
class HystrixClientFallback implements UserFeignClient {
private static final Logger LOGGER = LoggerFactory.getLogger(HystrixClientFallback.class);
#Override
public BaseResponse findByIdFeign(#RequestParam("id") Long id) {
BaseResponse response = new BaseResponse();
response.setMessage("disable");
return response;
}
#Override
public BaseResponse addUserFeign(UserVo userVo) {
BaseResponse response = new BaseResponse();
response.setMessage("disable");
return response;
}
}
}
FeignController.java
#RestController
public class FeignController {
#Autowired
private UserFeignClient userFeignClient;
#GetMapping("feign/{id}")
public BaseResponse<Date> findByIdFeign(#PathVariable Long id) {
BaseResponse response = this.userFeignClient.findByIdFeign(id);
return response;
}
#GetMapping("feign/user/add")
public BaseResponse<Date> addUser() {
UserVo userVo = new UserVo();
userVo.setAge(19);
userVo.setId(12345L);
userVo.setUsername("nick name");
BaseResponse response = this.userFeignClient.addUserFeign(userVo);
return response;
}
}
From the documentation:
#RibbonClient(name = "cloud-provider", configuration = CloudProviderConfiguration.class)
public class ConsumerApplication {
/* ... */
}
class CloudProviderConfiguration {
#Bean
public IRule ribbonRule(IClientConfig config) {
return new RandomRule();
}
}
By single view application vaadin 7.7.7, spring-boot 1.5 i check uri fragment https:/tld/#!category-name-1 from user and if the category exist show items and if not
VaadinService.getCurrentResponse().sendError(404, "page not found!");
but i got error after update spring-boot 1.5 and vaadin 7.7.7 (with embeded tomcat):
Cannot forward to error page for request [/vaadinServlet/UIDL/] as the response has already been committed. As a result, the response may have the wrong status code. If your application is running on WebSphere Application Server you may be able to resolve this problem by setting com.ibm.ws.webcontainer.invokeFlushAfterService to false
How can i send http error pages from vaadin to user?
ErrorPageCutomizer.java
#Component
public class ErrorPageCutomizer implements EmbeddedServletContainerCustomizer {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"));
container.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"));
}
}
RestController.java
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class ErrorHandlingController implements ErrorController {
private static final String PATH = "/error";
#RequestMapping(value = PATH + "/404")
public String error404() {
return "<div style='font-weight:bold; margin-top:200px; text-align:center; font-size:160%;'>Page not found...<br>to home</div>";
}
#RequestMapping(value = PATH + "/500")
public String error500() {
return "<div style='font-weight:bold; margin-top:200px; text-align:center; font-size:160%;'>500 Internal server error...</div>";
}
#Override
public String getErrorPath() {
return PATH;
}
}
Soliution was:
#Configuration
public class AppInitializer implements WebApplicationInitializer {
#Bean
public ErrorPageFilter errorPageFilter() {
return new ErrorPageFilter();
}
#Bean
public FilterRegistrationBean disableSpringBootErrorFilter(ErrorPageFilter filter) {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(filter);
filterRegistrationBean.setEnabled(false);
return filterRegistrationBean;
}
}
Have you tried the SystemMessagesProvider. In that provider you could define an errorUrl for a variety of errors:
public class YourServlet extends VaadinServlet
{
#Override
protected void servletInitialized() throws ServletException
{
super.servletInitialized();
getService().setSystemMessagesProvider(new SystemMessagesProvider()
{
#Override
public SystemMessages getSystemMessages(SystemMessagesInfo systemMessagesInfo)
{
final CustomizedSystemMessages c = new CustomizedSystemMessages();
final String errorUrl = "<url to errorpage>";
c.setSessionExpiredURL(errorUrl);
c.setSessionExpiredNotificationEnabled(false);
c.setAuthenticationErrorURL(errorUrl);
c.setAuthenticationErrorNotificationEnabled(false);
c.setCommunicationErrorURL(errorUrl);
c.setCommunicationErrorNotificationEnabled(false);
c.setCookiesDisabledURL(errorUrl);
c.setCookiesDisabledNotificationEnabled(false);
c.setInternalErrorURL(errorUrl);
c.setInternalErrorNotificationEnabled(false);
c.setSessionExpiredURL(errorUrl);
c.setSessionExpiredNotificationEnabled(false);
return c;
}
});
}