jUnit testing KeycloakAuthenticationToken - spring-boot

I'm trying to cover my code coverage with jUnit, but I'm having problems because of KeycloakPrincipal.
The method which I want to test and cover is isRoleAdmin(), which calls another method.
public Boolean isRoleAdmin() {
Map<String, Access> resources = getAccessToken().getResourceAccess();
Access access = resources.get(projectName);
if(access == null) return false;
return access.getRoles().contains(admin) || access.getRoles().contains(superadmin);
}
public AccessToken getAccessToken() {
KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) request.getUserPrincipal();
KeycloakPrincipal principal = (KeycloakPrincipal) token.getPrincipal();
KeycloakSecurityContext session = principal.getKeycloakSecurityContext();
return session.getToken();
}
My test :
#Test
void getContactListTest() {
KeycloakAccount keycloakAccount = new KeycloakAccount() {
#Override
public Set<String> getRoles() {
return null;
}
#Override
public Principal getPrincipal() {
return new Principal() {
#Override
public String getName() {
return "Name";
}
};
}
};
given((KeycloakAuthenticationToken) request.getUserPrincipal()).willReturn(new KeycloakAuthenticationToken(keycloakAccount, false) {
});
assertNotNull(contactService.isRoleAdmin());
I have the problem when getAccessToken() is called, in token.getPrincipal(), where I can't mock it and it gives me an error:
java.lang.ClassCastException: class com.editran.contacts.test.controller.ContactControllerTest$1$1 cannot be cast to class org.keycloak.KeycloakPrincipal (com.editran.contacts.test.controller.ContactControllerTest$1$1 and org.keycloak.KeycloakPrincipal are in unnamed module of loader 'app')
How can I end coverage for this method? Is there any way to avoid this error?

Related

spring resttemplate request object not mapping to rest controller

i have below resttempalte which invokes rest controller of another service..
#Override
public ResponseEntity<String> callRestAPI(APIReqDataMO apiReqDataMO) {
String apiURL = URIGenerator.getAPIURL(apiReqDataMO);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<?> request = new HttpEntity<>(apiReqDataMO.getRequestObject(), headers);
ResponseEntity<String> httpRes = restTemplate.postForEntity(apiURL, request, String.class);
return httpRes;
}
and in my service i have controller, which consumes above request..
#RequestMapping(value = "/targetService/createUser", method = RequestMethod.POST, consumes = "application/json")
public String fuzzerServiceAge(UserMO userMO) {
System.out.println("---------------------age is -------------------------" + userMO.getAge());
if (userMO.getAge() > 0) {
System.out.println("error age greater than 0 ");
return "invalid user age";
} else if (userMO.getAge() == 0) {
return "invalid user age";
}
return "user added successfully";
}
when i try my test.. the age which i am pushing through rest template is not getting mapped..and i am getting age as 0 always in my system.out.. what could be wrong in my code... and is there anything missing from configuration perspective..
EDIT -
public class APIReqDataMO {
private String restAPIURL;
private Object[] pathParam;
private Object[] requestParam;
private String requestType;
private String paramType;
private Object requestObject;
public String getParamType() {
return paramType;
}
public void setParamType(String paramType) {
this.paramType = paramType;
}
public String getRequestType() {
return requestType;
}
public void setRequestType(String requestType) {
this.requestType = requestType;
}
public Object getRequestObject() {
return requestObject;
}
public void setRequestObject(Object requestObject) {
this.requestObject = requestObject;
}
public String getRestAPIURL() {
return restAPIURL;
}
public void setRestAPIURL(String restAPIURL) {
this.restAPIURL = restAPIURL;
}
public Object[] getPathParam() {
return pathParam;
}
public void setPathParam(Object[] pathParam) {
this.pathParam = pathParam;
}
public Object[] getRequestParam() {
return requestParam;
}
public void setRequestParam(Object[] requestParam) {
this.requestParam = requestParam;
}
}
controller
#PostMapping("/targetService/createUser")
public String fuzzerServiceAge(UserMO userMO) {
System.out.println("--------------------- age is -------------------------" + userMO.getAge());
if (userMO.getAge() > 0) {
// return ResponseEntity.ok("Hello World!");
} else if (userMO.getAge() == 0) {
System.out.println(" it is else block");
// return ResponseEntity.badRequest().build();
}
// return ResponseEntity.ok("user added successfully!");
return "user added successfully";
}
usermo
public class UserMO {
#JsonProperty("name")
private String name;
#JsonProperty("age")
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Issue
There is an issue in API implementation. You are creating POST API and when the user will invoke this API by passing UserMO in the request body then mapping won't happen because the #RequestBody annotation is missing.
#PostMapping("/targetService/createUser")
public String fuzzerServiceAge(UserMO userMO) {
System.out.println("--------------------- age is -------------------------" + userMO.getAge());
if (userMO.getAge() > 0) {
// return ResponseEntity.ok("Hello World!");
} else if (userMO.getAge() == 0) {
System.out.println(" it is else block");
// return ResponseEntity.badRequest().build();
}
// return ResponseEntity.ok("user added successfully!");
return "user added successfully";
}
Solution
If you are using #RestController annotation on top of the controller class then add #RequestBody annotation before UserMO userMO and try again.
Like this
#PostMapping("/targetService/createUser")
public String fuzzerServiceAge(#RequestBody UserMO userMO) {
//logic
}
if you are using #Controller annotation on top of the controller class then add #ResponseBody annotation on top of method fuzzerServiceAge() and #RequestBody annotation before UserMO userMO and try again.
Like this
#PostMapping("/targetService/createUser")
#ResponseBody
public String fuzzerServiceAge(#RequestBody UserMO userMO) {
//logic
}

Global Exception Handling in Spring Cloud Function on AWS Lambda Platform

I am using spring cloud function on AWS lambda. I am trying to achieve global exception handling like Spring Boot using #ExceptionHandler annotation. But this method is not getting executed and I am getting 500 for any type of exception.
Sample code is below-
#SpringBootApplication
public class App{
public static void main( String[] args ){
SpringApplication.run(App.class, args);
}
#Bean
public Function<Message<User>, User> getUser(){
return (message)->{
User u = message.getPayload();
if(u==null){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,"No user details provided");
}
return u;
}
}
#ExceptionHandler(ResponseStatusException.class)
public APIGatewayProxyResponseEvent handleException(ResponseStatusException e){
APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent();
response.setStatusCode(e.getRawStatusCode());
response.setBody(e.getMessage());
return response;
}
}
I am getting 500 in response instead Bad Request. Is there any way to achieve this scenario ?
You can provide your custom exceptionHandler while building SpringBootLambdaContainerHandler.
public class StreamLambdaHandler implements RequestStreamHandler {
private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
static {
handler = new SpringBootProxyHandlerBuilder<AwsProxyRequest>()
.defaultProxy()
.exceptionHandler(***your customer handler here***)
// other methods are skipped
.buildAndInitialize();
}
}
If you are using spring cloud functions no need to use SpringBootLambdaContainerHandler, what you need to do is create a custom routing function and handle the exception thrown from your lambda function and return APIGatewayProxyResponseEvent. below shows how I achieved the desired result
public class CustomRoutingFunction implements Function<Message<?>, APIGatewayProxyResponseEvent> {
private final FunctionCatalog functionCatalog;
private final FunctionProperties functionProperties;
private final MessageRoutingCallback routingCallback;
public static final String DEFAULT_ROUTE_HANDLER = "defaultMessageRoutingHandler";
public CustomRoutingFunction(FunctionCatalog functionCatalog,
FunctionProperties functionProperties,
MessageRoutingCallback routingCallback) {
this.functionCatalog = functionCatalog;
this.functionProperties = functionProperties;
this.routingCallback = routingCallback;
}
#Override
public APIGatewayProxyResponseEvent apply(Message<?> input) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
try {
String functionDefinition = this.routingCallback.routingResult(input);
SimpleFunctionRegistry.FunctionInvocationWrapper function = functionCatalog.lookup(functionDefinition);
Object output = function.apply(input);
String payload = mapper.writeValueAsString(output);
return new APIGatewayProxyResponseEvent()
.withIsBase64Encoded(false)
.withBody(payload)
.withHeaders(Map.of(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE,
"statusCode", "200"))
.withStatusCode(200);
} catch (Exception e) {
return new APIGatewayProxyResponseEvent()
.withIsBase64Encoded(false)
.withHeaders(Map.of(HttpHeaders.CONTENT_TYPE,
MediaType.APPLICATION_JSON_VALUE,
"statusCode", String.valueOf(HttpStatus.BAD_REQUEST.value())))
.withBody(e.getMessage())
.withStatusCode(HttpStatus.BAD_REQUEST.value());
}
}
}
now you need to register your router function as a bean and pass it to spring.cloud.function.definition
#Bean
public CustomRoutingFunction customRoutingFunction(FunctionCatalog functionCatalog,
FunctionProperties functionProperties,
#Nullable MessageRoutingCallback routingCallback,
#Nullable DefaultMessageRoutingHandler defaultMessageRoutingHandler) {
if (defaultMessageRoutingHandler != null) {
FunctionRegistration functionRegistration = new FunctionRegistration(defaultMessageRoutingHandler, CustomRoutingFunction.DEFAULT_ROUTE_HANDLER);
functionRegistration.type(FunctionTypeUtils.consumerType(ResolvableType.forClassWithGenerics(Message.class, Object.class).getType()));
((FunctionRegistry) functionCatalog).register(functionRegistration);
}
return new CustomRoutingFunction(functionCatalog, functionProperties, routingCallback);
}
inside your application.yml file
spring:
cloud:
function:
definition: customRoutingFunction

Mock return fails with MockMvc on Junit

Is it possible in a Junit test to make a post request and use BDDMockito.given () to set the return of a Service used by the method that responds to the RestController post? If it is possible, how to do it?
I'm trying to set the return of the Service and in the RestController method the Service returns null and the test fails.
These are the codes:
Test:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {SecurityBeanOverrideConfiguration.class, AccountApp.class})
public class UserSystemResourceIntTest {
#MockBean
private UserSystemService userSystemServiceMock;
private MockMvc restUserSystemMockMvc;
private UserSystem userSystem;
public static UserSystem createEntity(EntityManager em) {
UserSystem userSystem = new UserSystem()
.name(DEFAULT_NAME)
.email(DEFAULT_EMAIL)
.phone(DEFAULT_PHONE)
.documentCode(DEFAULT_DOCUMENT_CODE)
.documentType(DEFAULT_DOCUMENT_TYPE)
.gender(DEFAULT_GENDER)
.createdOn(null)
.updateOn(null)
.active(null)
.userId(null);
return userSystem;
}
#Before
public void initTest() {
userSystem = createEntity(em);
}
#Test
#Transactional
public void createUserSystem() throws Exception {
int databaseSizeBeforeCreate = userSystemRepository.findAll().size();
// Create the UserSystem
UserSystemDTO userSystemDTO = userSystemMapper.toDto(userSystem);
userSystemDTO.setLangKey(DEFAULT_LANG_KEY);
given(userSystemServiceMock.newAccount(userSystemDTO)).willReturn(createNewUserSystemDTO());
restUserSystemMockMvc.perform(post("/api/user-systems")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(userSystemDTO)))
.andExpect(status().isCreated()); // FAIL BECAUSE RETURN STATUS 500
// Validate the UserSystem in the database
List<UserSystem> userSystemList = userSystemRepository.findAll();
assertThat(userSystemList).hasSize(databaseSizeBeforeCreate + 1);
UserSystem testUserSystem = userSystemList.get(userSystemList.size() - 1);
assertThat(testUserSystem.getName()).isEqualTo(DEFAULT_NAME);
assertThat(testUserSystem.getEmail()).isEqualTo(DEFAULT_EMAIL);
assertThat(testUserSystem.getPhone()).isEqualTo(DEFAULT_PHONE);
assertThat(testUserSystem.getDocumentCode()).isEqualTo(DEFAULT_DOCUMENT_CODE);
assertThat(testUserSystem.getDocumentType()).isEqualTo(DEFAULT_DOCUMENT_TYPE);
assertThat(testUserSystem.getGender()).isEqualTo(DEFAULT_GENDER);
assertThat(testUserSystem.getCreatedOn()).isNotNull(); //isEqualTo(DEFAULT_CREATED_ON);
assertThat(testUserSystem.getUpdateOn()).isNull(); // EqualTo(DEFAULT_UPDATE_ON);
assertThat(testUserSystem.isActive()).isEqualTo(DEFAULT_ACTIVE);
assertThat(testUserSystem.getUserId()).isEqualTo(DEFAULT_USER_ID);
// Validate the UserSystem in Elasticsearch
verify(mockUserSystemSearchRepository, times(1)).save(testUserSystem);
}
private static UserSystemDTO createNewUserSystemDTO() {
UserSystemDTO newUserSystemDTO = new UserSystemDTO(
DEFAULT_USER_ID, DEFAULT_NAME, DEFAULT_EMAIL,
DEFAULT_PASSWORD, DEFAULT_PHONE, DEFAULT_PHONE,
DEFAULT_DOCUMENT_TYPE, DEFAULT_GENDER, DEFAULT_LANG_KEY,
null, null, null, null);
return newUserSystemDTO;
}
}
RestController:
#RestController
#RequestMapping("/api")
public class UserSystemResource {
private final UserSystemService userSystemService;
private final UserSystemQueryService userSystemQueryService;
public UserSystemResource(UserSystemService userSystemService, UserSystemQueryService userSystemQueryService) {
this.userSystemService = userSystemService;
this.userSystemQueryService = userSystemQueryService;
}
#PostMapping("/user-systems")
public ResponseEntity<UserSystemDTO> createUserSystem(#Valid #RequestBody UserSystemDTO userSystemDTO) throws URISyntaxException {
log.debug("REST request to save UserSystem : {}", userSystemDTO);
if (userSystemDTO.getId() != null) {
throw new BadRequestAlertException("A new userSystem cannot already have an ID", ENTITY_NAME, "idexists");
}
UserSystemDTO result = userSystemService.newAccount(userSystemDTO);
return ResponseEntity.created(new URI("/api/user-systems/" + result.getId()))
.headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
.body(result);
}
}
Console error:
java.lang.NullPointerException: null
at com.comp.account.web.rest.UserSystemResource.createUserSystem(UserSystemResource.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
Result test error:
createUserSystem(com.comp.account.web.rest.UserSystemResourceIntTest) Time elapsed: 205.661 s <<< FAILURE!
ava.lang.AssertionError: Status expected:<201> but was:<500>

TestNG listener, how to get the singleton use by the tests

We use the TestNG listener feature to report the results of our tests in an external tool. It works fine.
But now, we want to add an information contained by a singleton (a ThreadLocal webdriver). Our test campaign is run in parallel, so we have multiple instance of our singleton.
How can we in the method onSuccess for instance get the correct singleton and so report the correct information?
Edit: code sample
public class QTestWrapper implements ISuiteListener, ITestListener {
...
#Override
public void onTestSuccess(ITestResult result) {
String sessionId = MyDriver.getSessionId();
// do my job with this session id
}
...
}
public final class MyDriver {
private static final ThreadLocal<MyDriver> MY_DRIVER =
ThreadLocal.withInitial(MyDriver::buildDriver);
private WebDriver driver;
private MyDriver(WebDriver driver) {
this.driver = driver;
}
public static MyDriver getDriver() {
return MY_DRIVER.get();
}
private static MyDriver buildDriver() {
URL remoteAddress = getHubAddress();
DesiredCapabilities caps = buildCapabilities();
WebDriver driver = new RemoteWebDriver(remoteAddress, caps);
return new MyDriver(driver);
}
public static String getSessionId() {
String sessionId = null;
MyDriver driver = MY_DRIVER.get();
if (driver != null && driver.getWrappedDriver() != null) {
WebDriver wrappedDriver = driver.getWrappedDriver();
sessionId = ((RemoteWebDriver) wrappedDriver).getSessionId().toString();
}
return sessionId;
}
public WebDriver getWrappedDriver() {
return driver;
}
}
public class TestLogin {
#AfterMethod(alwaysRun = true)
public void die() {
StickyDriver.quit();
}
#Test(description = "Check that a user can login with a Manager profile.")
public void loginAsManager() {
Actor actor = new Actor("foo");
String userName = actor.openBrowserAndLogin().getUserName();
assertThat(userName).isEqualTo("foo");
}
}
public class Actor {
private static final Logger LOGGER = LogManager.getLogger();
private final MyDriver driver;
private User user;
public Actor(String userName) {
user = User.getUser(userName);
driver = MyDriver.getDriver();
}
public Actor(User user) {
this.user = Objects.requireNonNull(user);
driver = MyDriver.getDriver();
}
public HomePage openBrowserAndLogin() {
openBrowser();
return login();
}
public HomePage login() {
LoginPage loginPage = new LoginPage(driver);
loginPage.getUserNameField().setValue(user.getUsername());
loginPage.getPasswordField().setValue(user.getPassword());
return loginPage.login();
}
private void openBrowser() {
String url = EnvironmentHelper.getUrl();
WebDriver webDriver = driver.getWrappedDriver();
webDriver.get(url);
try {
new WebDriverWait(webDriver, 60).until(AjaxExpectedConditions.callsHaveCompleted());
} catch (TimeoutException ex) {
closeBrowser();
throw ex;
}
}
public void closeBrowser() {
MyDriver.quit();
}
}
TestNG does not guarantee that the #Test and onSuccess() will be executed in the same thread.
That assurance is only provided when you work with org.testng.IInvokedMethodListener implementation.
So please change your implementation to do the following :
Have your class QTestWrapper implement org.testng.IInvokedMethodListener
within the afterInvocation() of org.testng.IInvokedMethodListener check if the method that got executed was a #Test method and if its status was a pass, and if it passed you move your logic within onSuccess() into it.

smartgwt listgrid RestDataSource not populating

Im new using this front end framework application...
I recently started to work with smartgwt and i'm bulding a new application with a Spring MVC integration.
I'm using a ListGrid with a RestDataSource (Consume the Rest service with mvc:annotation-driven for plain JSON)
I can see that the servaice gets consuming properly perhaps my grid is never shown with the data in it.
Can someone help me here ?
Here's my ListGrid class
public class ListGrid extends com.smartgwt.client.widgets.grid.ListGrid {
private final SpringJSONDataSource springJSONDataSource;
public ListGrid(List<DataSourceField> fields) {
this(new PatientDataSource(fields));
}
public ListGrid(SpringJSONDataSource springJSONDataSource) {
this.springJSONDataSource = springJSONDataSource;
init();
}
private void init() {
setAutoFetchData(true);
setAlternateRecordStyles(true);
setEmptyCellValue("???");
setDataPageSize(50);
setDataSource(springJSONDataSource);
}
}
Now there's the DataSource implmentation
public abstract class SpringJSONDataSource extends RestDataSource {
protected final HTTPMethod httpMethod;
public SpringJSONDataSource(List<DataSourceField> fields) {
this(fields, HTTPMethod.POST);
}
public SpringJSONDataSource(List<DataSourceField> fields, HTTPMethod httpMethod) {
this.httpMethod = httpMethod;
setDataFormat(DSDataFormat.JSON);
addDataSourceFields(fields);
setOperationBindings(getFetch());
addURLs();
}
private void addURLs() {
if(getUpdateDataURL() != null)
setUpdateDataURL(getUpdateDataURL());
if(getRemoveDataURL() != null)
setRemoveDataURL(getRemoveDataURL());
if(getAddDataURL() != null)
setAddDataURL(getAddDataURL());
if(getFetchDataURL() != null)
setFetchDataURL(getFetchDataURL());
}
private void addDataSourceFields(List<DataSourceField> fields) {
for (DataSourceField dataSourceField : fields) {
addField(dataSourceField);
}
}
protected abstract OperationBinding getFetch();
protected abstract OperationBinding getRemove();
protected abstract OperationBinding getAdd();
protected abstract OperationBinding getUpdate();
public abstract String getUpdateDataURL();
public abstract String getRemoveDataURL();
public abstract String getAddDataURL();
public abstract String getFetchDataURL();
}
The class PatientDataSource that extends SpringJSONDataSource
public class PatientDataSource extends SpringJSONDataSource {
public PatientDataSource(List<DataSourceField> fields) {
super(fields);
setPrettyPrintJSON(true);
}
#Override
protected OperationBinding getFetch() {
OperationBinding fetch = new OperationBinding();
fetch.setOperationType(DSOperationType.FETCH);
fetch.setDataProtocol(DSProtocol.POSTMESSAGE);
DSRequest fetchProps = new DSRequest();
fetchProps.setHttpMethod(httpMethod.toString());
fetch.setRequestProperties(fetchProps);
return fetch;
}
#Override
public String getFetchDataURL() {
return "/spring/fetchPatients";
}
#Override
protected OperationBinding getRemove() {
return null;
}
#Override
public String getRemoveDataURL() {
return null;
}
#Override
protected OperationBinding getAdd() {
return null;
}
#Override
public String getAddDataURL() {
return null;
}
#Override
protected OperationBinding getUpdate() {
return null;
}
#Override
public String getUpdateDataURL() {
return null;
}
}
My spring controller PatientControler
#Controller
public class PatienController {
Logger logger = Logger.getLogger(PatienController.class);
#Autowired
private PatientServices patientServices;
#RequestMapping(value = "/patientTest", method = RequestMethod.GET)
#ResponseBody
public Object getTest()
{
return patientServices.getAllPatients();
}
#RequestMapping(value = "/fetchPatients", method = RequestMethod.POST)
#ResponseBody
public Object getAllPatients()
{
return patientServices.getAllPatients();
}
}
PatientServiceImpl
public class PatientServicesImpl implements PatientServices {
public List<Patient> getAllPatients() {
List<Patient> patients = new ArrayList<Patient>();
Patient patient;
for(int i = 0 ; i < 500 ; i++){
patient = new Patient();
patient.setDateOfBirth(new Date());
patient.setFirstName("Joe");
patient.setMiddleName("Moe");
patient.setLastName("Blow");
patient.setLastConsultation(new Date());
patient.setSex(Sex.M);
patients.add(patient);
}
return patients;
}
}
*Im Really stuck right now i've been looking for all type of answers .... but so far nothing worked when i tried to override the transformResponse from my RestDataSource impentation the parameter "data" as an OBJECT, returns me an array [object Object],[object Object],[object Object],[object Object],[object Object] *
The Data which is transferred from the RestDataSource has a specific format which is described in the JavaDoc of the RestDataSource
Your server must understand the request and send back a valid response.
At the moment your example doesn't seem to honour the contract.
To debug the traffic send to and from your server you can use the SmartClient-Console. You can open it by a browser bookmark like this:
javascript:isc.showConsole()
Of cause you need to deploy this console by adding the following module to your gwt.xml
<inherits name="com.smartclient.tools.SmartClientTools"/>
Now go to the RPC Tab and check Track-RPCs

Resources