In my project, i set session.loggedInUser in login controller. But during integration test , we dont use login controller. So i have set value for session.loggedInUser. But i couldn't use session in that place. How can i use session in integration Test. Give some solution for this. thank you in advance
class MaritalStatusIntegrationTests {
#Test
void testCategoryAudit() {
RequestContextHolder.currentRequestAttributes().session.loggedInUser="Anantha"
def category = new Category(name:"Single")
category.save(flush:true)
assert CategoryAudit.count() == 1
category.name="Married"
category.save(flush:true)
assert CategoryAudit.count() == 2
}
}
Category.groovy:
class Category {
static constraints = {
name blank:false
}
String name
//Auditing
static auditable = false
def onSave = {
new CategoryAudit(this,'Insert').save(failOnError:true)
}
}
CategoryAudit.groovy:
import org.springframework.web.context.request.RequestContextHolder
class CategoryAudit {
String name
String operation
String doneBy
Date txnDate
def CategoryAudit(){}
def CategoryAudit(Category category , String operation) {
this.name = category.name
this.operation = operation
this.doneBy = RequestContextHolder.currentRequestAttributes().session.loggedInUser
this.txnDate = new Date()
}
}
No such property: RequestContextHolder for class:
com.vasco.gs.MaritalStatusIntegrationTest.
Just to clean up, according to the OP, it was missing the import for RequestContextHolder.
Related
I want to use the "dashVer" in StartupTest.groovy in Zip.groovy, but "dashVer" in Zip.groovy return in "null". For detail, please read below, thank you very much!!!!
StartupTest.groovy
class StartupTest extends Specification {
String dashVer
void updateGlobalString(String dashVersion){
dashVer=dashVersion
}
def 'Start_test'() {
setup:
.......
when: 'Test started'
String dashVersion= new GetDashVer().Get_dash_ver().toString()
println(dashVersion) //Eg.the result is 3.3.3 return from GetDashVer class sucessfully
updateGlobalString(dashVersion)
and:
...
then:
...
}
}
Zip.groovy
class ZipUploadSlack {
//Attempt 1
StartupTest test = new StartupTest()
String dashVer111 = test.updateGlobalString()
//Attept 2
//StartupTest test = new StartupTest()
//String dashVer111 = test.dashVer
def 'Zip'(){
println(dashVer111) //This should be return in 3.3.3, but it is "null" for now for both attepts
}
}
#Jacob Aae Mikkelsen, thanks for the advice. Seems static variable working.
Just tried with below:
Startuptest.groovy
class StartupTest extends Specification {
static String dashbVer
static Integer errorCount
String updateGlobalString(String dashVersion){
dashVer=dashVersion
return dashVer
}
Integer updateGlobalInteger(Integer errorC){
errorCount=errorC
return errorCount
}
void updateGlobalString(String dashVersion){
dashVer=dashVersion
}
def 'Start_test'() {
setup:
.......
when: 'Test started'
String dashVersion= new GetDashVer().Get_dash_ver().toString()
println(dashVersion) //Eg.the result is 3.3.3 return from GetDashVer class sucessfully
updateGlobalString(dashVersion)
and:
...
then: 'No error log found'
def error = dash.logFinder.search(/\(ERROR\)/)
error.isEmpty() //Let says it is true, it is empty as no error found
int errorC = error.size() as Integer //.size is using List.java, #return the number of elements in this list
println(errorC) //Here return as 0 as expected
updateGlobalInteger(errorC) // Here return with error, "condition not satisfied groovy"
}
}
Zip.groovy
class ZipUploadSlack {
//Obtain dashVer
StartupTest test = new StartupTest()
String dashVer111 = test.dashVer
def 'Zip'(){
println(dashVer111) //This can return correct dashVer now
}
}
My new question is why there is "condition not satisfied groovy" error when executing updateGlobalInteger(errorC)? errorC is integer and the updateGlobalInteger function is returning a integer, why failed? Thanks!!!!
I have a simple application in Mironaut with three entities, Customer, Contact and Loans.
Customer has a 1 to many relationship with Contact and Loans. I test with Grails / Gorm and it works fine.
I have a DataLoader class that works well and creates all entities with their relationships.
/****** Contact.groovy *******/
package com.gnc.demo.domain
import grails.gorm.annotation.Entity
#Entity
class Contact {
Long id
Long version
Customer customer
static belongsTo = Customer
String email
String phone
String cellPhone
String address
}
/****** Customer.groovy *******/
package com.gnc.demo.domain
import grails.gorm.annotation.Entity
#Entity
class Customer {
Long id
Long version
String driverId
String name
String lastName
static hasMany = [contacts: Contact, loans: Loan]
static constraints = {
contacts nullable: true
loans nullable: true
}
static mapping = {
contacts lazy: false
loans lazy: false
}
}
/****** Loan.groovy *******/
package com.gnc.demo.domain
import grails.gorm.annotation.Entity
#Entity
class Loan {
Long id
Long version
Customer customer
static belongsTo = Customer
BigDecimal amount
long term
BigDecimal rate
}
/******* CustomerController.groovy *******/
package com.gnc.demo.controllers
import com.gnc.demo.domain.Customer
import com.gnc.demo.services.ContactService
import com.gnc.demo.services.CustomerService
import com.gnc.demo.services.LoanService
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import org.slf4j.Logger
import org.slf4j.LoggerFactory
#Controller("/customer")
class CustomerController {
private static final Logger LOG = LoggerFactory.getLogger(CustomerController.class);
final CustomerService customerService
final LoanService loanService
final ContactService contactService
CustomerController(CustomerService customerService, LoanService loanService, ContactService contactService) {
this.customerService = customerService
this.loanService = loanService
this.contactService = contactService
}
#Get("/")
String index() {
return "Hola ! " + new Date()
}
#Get("/all/{offset}/{max}")
List<Customer> getCustomers(String offset, String max) {
List<Customer> customers = customerService.findAll([offset: offset, max: max])
try {
customers.each { customer ->
// LOG.info(">>> Loans :" +customer.loans.size())
customer.contacts = []
customer.loans = []
}
} catch (Exception e) {
LOG.info(">>> Error :" + e)
}
return customers
}
#Get("/{id}")
Customer getCustomers(String id) {
Customer customer = customerService.get(id)
customer?.contacts = []
customer?.loans = []
customer?.contacts = contactService.findAllByCustomer(customer)
customer?.loans = loanService.findAllByCustomer(customer)
return customer
}
}
All the code is available in: https://github.com/gnpitty/com-gnc-demo
But when I test in Micronaut with my browser: http://localhost:9020/customer/10
I receive this error:
{"message":"Internal Server Error: Error encoding object
[com.gnc.demo.domain.Customer : 10] to JSON: could not initialize proxy - no
Session (through reference chain: com.gnc.demo.domain.Customer[\"contacts\"]-
>java.util.LinkedHashSet[0]->com.gnc.demo.domain.Contact[\"customer\"]-
>com.gnc.demo.domain.Customer_$$_jvst110_0[\"driverId\"])"}
As one comment said, you should make sure the #Transactional or withTransaction {} is used when reading the record.
Also, if you want to reference the proxy elements (like the Customer reference), you need to force the proxy element to be read. I know of two ways: 1) do an eager fetch on them or 2) resolve the proxy explicitly.
I chose option 2) since I did not want to force eager fetching when it wasn't needed. I only use this in controllers where I am return a JSON encoded domain object. This is usually just in my REST API methods.
Example:
Loan.withTransaction {
def loan = Loan.findByXYZ()
resolveProxies(loan)
}
This converts the proxies into real objects so you can access them outside of the withTransaction{} closure. This usually is Jackson converting them to JSON.
I use this method to resolve any proxies in lists or as simple references to another domain object:
/**
* Resolves all proxies for the given domain class. This allows the domain to be used outside of an hibernate session
* if needed. This will check all fields and sub-objects for proxies.
* <p>
* <b>Note:</b> This will usually force a read of all referenced objects.
* #param object The object.
*/
def resolveProxies(Object object) {
if (object == null) {
return
}
for (property in object.class.gormPersistentEntity.persistentProperties) {
def value = object[property.name]
if (Collection.isAssignableFrom(property.type) && value) {
for (item in value) {
if (item != null) {
// Resolved any sub-objects too.
resolveProxies(item)
}
}
} else if (value instanceof HibernateProxy) {
// A simple reference, so unproxy it the GORM way.
object[property.name] = value.getClass().get(value.id)
}
}
}
Feel free to use this code anywhere you need it.
finally after extensive stack-overflowing ;-) and debugging I made it work:
My Feign-client can make requests on Spring-Data-Rest's API and I get a Resource<Something> with filled links back.
My code so far...
The FeignClient:
#FeignClient(name = "serviceclient-hateoas",
url = "${service.url}",
decode404 = true,
path = "${service.basepath:/api/v1}",
configuration = MyFeignHateoasClientConfig.class)
public interface MyFeignHateoasClient {
#RequestMapping(method = RequestMethod.GET, path = "/bookings/search/findByBookingUuid?bookingUuid={uuid}")
Resource<Booking> getBookingByUuid(#PathVariable("uuid") String uuid);
}
The client-config:
#Configuration
public class MyFeignHateoasClientConfig{
#Value("${service.user.name:bla}")
private String serviceUser;
#Value("${service.user.password:blub}")
private String servicePassword;
#Bean
public BasicAuthRequestInterceptor basicAuth() {
return new BasicAuthRequestInterceptor(serviceUser, servicePassword);
}
#Bean
public Decoder decoder() {
return new JacksonDecoder(getObjectMapper());
}
#Bean
public Encoder encoder() {
return new JacksonEncoder(getObjectMapper());
}
public ObjectMapper getObjectMapper() {
return new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.registerModule(new Jackson2HalModule());
}
#Bean
public Logger logger() {
return new Slf4jLogger(MyFeignHateoasClient.class);
}
#Bean
public Logger.Level logLevel() {
return Logger.Level.FULL;
}
}
And in the application using the client via an jar-dependency:
#SpringBootApplication
#EnableAutoConfiguration
#EnableFeignClients(basePackageClasses=MyFeignHateoasClient.class)
#EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
#ComponentScan(excludeFilters = #Filter(type = ... ), basePackageClasses= {....class}, basePackages="...")
public class Application {
...
Now this is working:
#Autowired
private MyFeignHateoasClient serviceClient;
...
void test() {
Resource<Booking> booking = serviceClient.getBookingByUuid(id);
Link link = booking.getLink("relation-name");
}
Now my question:
How do I go on from here, i.e. navigate to the resource in the Link?
The Link is containing an URL on the resource I want to request.
Do I really have to parse the ID out of the URL and add a method to the FeignClient like getRelationById(id)
Is there at least a way to pass the complete resource-url to a method of a FeignClient?
I have found no examples which demonstrate how to proceed from here (despite the POST/modify). Any hints appreciated!
Thx
My current solution:
I added an additional request in the Feign client, taking the whole resource path:
...
public interface MyFeignHateoasClient {
...
#RequestMapping(method = RequestMethod.GET, path = "{resource}")
Resource<MyLinkedEntity> getMyEntityByResource(#PathVariable("resource") String resource);
}
Then I implemented some kind of "HAL-Tool":
...
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import org.springframework.hateoas.Link;
import feign.Target;
import lombok.SneakyThrows;
public class HalTool {
private Object feignClient;
public static HalTool forClient( Object feignClient ) {
return new HalTool(feignClient);
}
private HalTool( Object feignClient ) {
this.feignClient = feignClient;
}
#SneakyThrows
private String getUrl() {
InvocationHandler invocationHandler = Proxy.getInvocationHandler(feignClient);
Field target = invocationHandler.getClass().getDeclaredField("target");
target.setAccessible(true);
Target<?> value = (Target<?>) target.get(invocationHandler);
return value.url();
}
public String toPath( Link link ) {
String href = link.getHref();
String url = getUrl();
int idx = href.indexOf(url);
if (idx >= 0 ) {
idx += url.length();
}
return href.substring(idx);
}
}
And then I could do request a linked resource like this:
Link link = booking.getLink("relation-name");
Resource<MyLinkedEntity> entity = serviceClient.getMyEntityByResource(
HalTool.forClient(serviceClient).toPath(link));
I'm using Struts2. I have two web forms that have the same code. I would like to eliminate one form. Here is the structure of my Struts project.
\Web Pages
form.jsp
\WEB-INF
\Content
error.jsp
form.jsp
success.jsp
\Source Packages
\action
MyAction.java
MyAction.java
package action;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.*;
public class MyAction extends ActionSupport {
#Action(value = "foo", results = {
#Result(name = "input", location = "form.jsp"),
#Result(name = "success", location = "success.jsp"),
#Result(name = "error", location = "error.jsp")
})
public String execute() throws Exception {
if (user.length() == 1) {
return "success";
} else {
return "error";
}
}
private String user = "";
public void validate() {
if (user.length() == 0) {
addFieldError("user", getText("user required"));
}
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
}
I tried to eliminate form.jsp under \Web Pages by adding a new action method to MyAction.java.
#Action(value="bar", results = {
#Result(name = "success", location = "form.jsp"),
})
public String another() {
return "success";
}
But I got the following error when I go to http : //localhost .../bar.action
HTTP Status 404 - No result defined for action action.MyAction and result input
Your MyAction has an implementation of validate(), which means it is validation aware.
What's happening is that you're calling another, but validate() is kicking in (as it's in the interceptor stack). Validation is failing, and therefore sending to INPUT result, which is not defined in another.
You should
Add #SkipValidation to the another method if you don't want validation there
Add the INPUT result to another() if you want a default input result
On a more general note, when you get that kind of error (No result defined for action X and result input) it usually means you're either having validation errors, parameter population errors (eg: an exception in preparable).
I am trying to create a test in grails to ensure indeed that the unique:true constraint works, here's my class and test file:
package edu.drexel.goodwin.events.domain
class UpayConfig {
String name
String siteId
String postingCode
static constraints = {
name(blank:false, maxSize:50)
siteId(blank:false, unique:true)
postingCode(blank:false)
}
}
package edu.drexel.goodwin.events.domain
import grails.test.*
class UpayConfigTests extends GrailsUnitTestCase {
protected void setUp() {
super.setUp()
}
protected void tearDown() {
super.tearDown()
}
void testCleanUpayConfigValidates() {
mockForConstraintsTests UpayConfig
def cleanUpayConfig = create()
assertTrue cleanUpayConfig.validate()
}
void testUpayConfigSiteIdMustBeUnique() {
mockForConstraintsTests UpayConfig
def upayConfigOne = create()
def upayConfigTwo = create()
assertFalse upayConfigOne.validate()
assertFalse upayConfigTwo.validate()
upayConfigTwo.siteId = '81'
assertTrue upayConfigOne.validate()
assertTrue upayConfigTwo.validate()
}
UpayConfig create() {
def upayConfig = new UpayConfig(
siteId: '82',
name: 'SMT - Workshops',
postingCode: '6'
)
}
}
But that second test fails, the upayConfig variables both return true for .validate() even though I am telling them both to have the same siteId...
I have a feeling this has something to do with the fact that these aren't being placed in the database, just being stored in memory?
All help is much appreciated, thank you.
-Asaf
The uniqueness will be at the database level. You're never saving the domain, so as far as upayConfigTwo is concerned, it is unique. You'll need to do a regular mock and actually call save() on upayConfigOne.
Thank you. I looked up this website: http://www.ibm.com/developerworks/java/library/j-grails10209/index.html and it had a section called "Testing the unique constraint with mockForConstraintsTests()" so following it I modified my test to be as follows and it passed correctly:
void testUpayConfigSiteIdMustBeUnique() {
def upayConfigOne = create()
mockForConstraintsTests(UpayConfig, [upayConfigOne])
def upayConfigTwo = create()
assertFalse upayConfigTwo.validate()
assertEquals "unique", upayConfigTwo.errors["siteId"]
upayConfigTwo.siteId = '81'
assertTrue upayConfigTwo.validate()
}
Thank you for your help,
-Asaf