How to get nested objects inside entity - spring-boot

I'm new with unit tests. I'm trying test Service Layer in a SPRING APP.
Good, i have any relationships in my Service.
VirtualDatacenterModel vdc = vdcRepository.findById(vmDTO.getVdc()).orElseThrow(() -> new ClientException("Invalid VDC id"));
DataCenterModel dc = vdc.getDatacenter();
String vmName = vdc.getTenant().getName() + "_[" + vmDTO.getName() + "]";
In my test i used MOCKITO, dependencies already is mocked, then i cannot see where is wrong
CreateVmDTO vmDTO = Mockito.mock(CreateVmDTO.class);
VmModel vm = Mockito.mock(VmModel.class);
VirtualDatacenterModel vdc = Mockito.mock(VirtualDatacenterModel.class, Mockito.RETURNS_DEEP_STUBS);
TenantModel tenant = Mockito.mock(TenantModel.class);
Mockito.when(vmRepository.save(vm)).thenReturn(new VmModel());
Mockito.when(vdcRepository.findById(vmDTO.getVdc())).thenReturn(Optional.of(new VirtualDatacenterModel()));
Mockito.doReturn(tenant).when(vdc).getTenant();
Mockito.when(vdc.getTenant().getName()).thenReturn("Olivia");
VmModel vmReturn = vmService.createVM(vmDTO);
And i receive NullPointerException, i probably don't know how to use Mockito correctly

You can only mock one action at the time, the following line will certainly be a problem:
Mockito.when(vdcRepository.findById(vmDTO.getVdc())).thenReturn(Optional.of(new VirtualDatacenterModel()));
cause vmDTO.getVdc() will return a null pointer. (vmDTO is a mocked object itself, and has no instruction set for that call). Assuming vmDTO.getVdc() returns the vdc, you can fix as follows:
CreateVmDTO vmDTO = Mockito.mock(CreateVmDTO.class);
VmModel vm = Mockito.mock(VmModel.class);
VirtualDatacenterModel vdc = Mockito.mock(VirtualDatacenterModel.class, Mockito.RETURNS_DEEP_STUBS);
//example fix:
Mockito.when(vmDTO.getVdc()).thenReturn(vdc);
TenantModel tenant = Mockito.mock(TenantModel.class);
Mockito.when(vmRepository.save(vm)).thenReturn(new VmModel());
//also you can do directly:
Mockito.when(vdcRepository.findById(vdc)).thenReturn(Optional.of(new VirtualDatacenterModel()));
Mockito.doReturn(tenant).when(vdc).getTenant();
Mockito.when(vdc.getTenant().getName()).thenReturn("Olivia");
VmModel vmReturn = vmService.createVM(vmDTO);
Also the naming of your methods throws me off:
You have a method vdcRepository.findById, but your input is a vdc object, and not an id? Either the naming is confusing or your input is wrong. If getVdc returns an Id, then you can fix the code by mocking the return of an Id (rename the method to getVdcId or something).
Note: Personally, I seldom mock a DTO. It is just as easy to make the real DTO object, since they often come with a builder or getter/setter.

Related

Spring Webflux: Extract value from Mono

I am new to spring webflux and am trying to perform some arithmetic on the values of two monos. I have a product service that retrieves account information by calling an account service via webClient. I want to determine if the current balance of the account is greater than or equal to the price of the product.
Mono<Account> account = webClientBuilder.build().get().uri("http://account-service/user/accounts/{userId}/",userId)
.retrieve().bodyToMono(Account.class);
//productId is a path variable on method
Mono<Product> product =this.productService.findById(productId);
When I try to block the stream I get an error
block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-2
//Causes Error
Double accountBalance = account.map(a->a.getBalance()).block():
Double productPrice = product.map(p->p.getPrice()).block();
///Find difference, send response accordingly....
Is this the correct approach of there is another, better way to achieve this? I was also thinking something along the lines of:
Mono<Double> accountBalance = account.map(a->a.getBalance()):
Mono<Double> productPrice = product.map(p->p.getPrice());
Mono<Double> res = accountBalance.zipWith(productPrice,(b,p)-> b-p);
//Something after this.....
You can't use block method on main reactor thread. This is forbidden. block may work when publish mono on some other thread but it's not a case.
Basically your approach with zipping two monos is correct. You can create some helper method to do calculation on them. In your case it may look like:
public boolean isAccountBalanceGreater(Account acc, Product prd) {
return acc.getBalance() >= prd.getPrice();
}
And then in your Mono stream you can pass method reference and make it more readable.
Mono<Boolean> result = account.zipWith(productPrice, this::isAccountBalanceGreater)
The question is what you want to do with that information later. If you want return to your controller just true or false that's fine. Otherwise you may need some other mappings, zippings etc.
Update
return account.zipWith(productPrice, this::createResponse);
...
ResponseEntity createResponse(Account acc, Product prd) {
int responseCode = isAccountBalanceGreater(acc, prd) ? 200 : 500;
return ResponseEntity.status(responseCode).body(prd);
}

Assigning NamedStoredProcedureQuery at runtime

I have stored procedures that need to be called to perform the operation. However, for each operation, I have saved the stored procedure name into the database. So, at runtime, based on the operation name I will call the assign stored procedure.
Question:
1. How can I set the name of the NamedStoredProcedureQuery at runtime?
I am using Spring JPA with Spring boot.
#NamedStoredProcedureQueries({
#NamedStoredProcedureQuery(
name = "sptest",
procedureName = "usp_helper_test",
resultClasses = {Config.class},
parameters = {
#StoredProcedureParameter(
name = "data",
type = String.class,
mode = ParameterMode.IN)
})
})
In this above example, I want to set procedureName at runtime.
If we ignore stuff like byte code generation: You can't.
Named stored procedures get their name from the annotations you showed in the question.
Of course you can still use either the EntityManager or JDBC (possibly via the JdbcTemplate) to call stored procedures by the name they have in the database.
With the EntityManager you'd invoke EntityManager.createStoredProcedureQuery in one of it's variants.
For the JdbcTemplate approach you can consult this SO answer.
The code you need to write would go in a custom method implementation.

Excessive Metadata when getting all states in Test Corda vault

Im testing a Corda 4 Cordapp and set up a spring web server to make api calls to my cordapps. I have one api called named ```get-all-contract1-states`` which does exactly what it says. It gets all of my contract1 states in the vault.
When I call this function, it does return the states, but also returns an excessive amount of repetitive metadata making the output for 1 state more than 600k lines long.
#GetMapping(value = "/get-contract1-states", produces = arrayOf(MediaType.APPLICATION_JSON_VALUE))
fun getContract1s() = rpcOps.vaultQueryBy(criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL), paging = PageSpecification(DEFAULT_PAGE_NUM, 200), sorting = Sort(emptySet()), contractStateType = contract1State::class.java).states
Most of the repetitive metadata (which makes up about 85% of the 600k lines) is at the end of the Json regarding "zero":false,"one":false,"fieldSize":256,"fieldName":"SecP256R1Field". Are there any flags, options, or simply any way to get back a clean version of the contract without so much excess data. I only care about the variables from the contract, nothing more.
What you currently have will return you a collection of:
data class Page<out T : ContractState>(val states: List<StateAndRef<T>>,
val statesMetadata: List<StateMetadata>,
val totalStatesAvailable: Long,
val stateTypes: StateStatus,
val otherResults: List<Any>)
Hence why you're getting all the metadata. What you're after in this data object is states (which actually returns StateAndRef) and then just state within each.
The following code should get you what you're after:
#GetMapping(value = "/get-contract1-states", produces = arrayOf(MediaType.APPLICATION_JSON_VALUE))
fun getContract1s() = proxy.vaultQueryBy(criteria = QueryCriteria.VaultQueryCriteria(status =
Vault.StateStatus.ALL), paging = PageSpecification(DEFAULT_PAGE_NUM, 200),
sorting = Sort(emptySet()), contractStateType = IOUState::class.java).states.map { it.state.data }
Note: the key bit here is the mapping to state.data

Integration Test Asserting Each Element In A Collection

Considering an IT with Spring-Boot and JUnit that would test whether a collection returned from database contains all needed elements. What would be the best way to do that?
To illustrate, consider a JPA class/entity such as the following:
class Person {
Integer id;
String name;
String lastName;
Address address;
Account account;
}
Consider that ids of Person, Address and Account would be auto-generated, so I can't infer them.
Any help will be appreciated.
I identity 3 points :
1) Invoke the method under test that is save and flush the entity instance with the JpaRepository dedicated to your entity
2) Make sure that your integration test is reliable/valuable.
Here it matters to clear the first level cache of JPA (EntityManager.clear()) to test the actual retrieval from the database. The cache may hide some issue in your mapping that will be seen only as the object is actually found from the database.
3) Assert the expected behavior that is retrieve the saved entity from the DB and assert its state according to your expected.
For asserting fields of a object AssertJ could interest you.
It doesn't force you to override equals()/hashCode() and it is very simple and meaningful.
As you want to assert nested objects I advise to use a distinct assertThat() by object.
For example :
Person person = new Person()...;
// action
personRepository.saveAndFlush(person);
// clear the first level cache
em.clear();
// assertions
Optional<Person> optPerson = personRepository.findById(person.getId());
// JUnit
Assert.assertTrue(optPerson.isPresent());
// AssertJ
person = optPerson.get();
Assertions.assertThat(person)
.extracting(Person::getName, Person::getLastName)
.containsExactly("expected name", "expected last name");
Assertions.assertThat(person.getAccount())
.extracting(Account::getFoo, Account::getBar)
.containsExactly("expected foo", "expected bar");
Assertions.assertThat(person.getAddress())
.extracting(Address::getStreet, Address::getZip)
.containsExactly("expected street", "expected zip");

Spring, Hibernate and multiple references to the same row in database

I'm currently facing a problem here and I thought maybe some of you guys could help me out.
I am developing an application using SPRING and HIBERNATE and my issue is the following:
1 - I first create a new AudioFile object (Domain class) in my main object, and insert it in the database using the hibernateTemplate.save(audioFile) method in the DAO.
2 - I then use hibernateTemplate.get(1) method of the DAO to retrieve the row from the database, and store the instance into an audioFile1 object. (Of type AudioFile)
3 - I then repeat step 2 and store the instance into an audioFile2 object.
In summary: my main class goes like this:
ApplicationContext context = new ClassPathXmlApplicationContext(
"application-context.xml");
AudioFileServices audioFileServices = (AudioFileServices) context.getBean("audioFileServices");
AudioFile audioFile = new AudioFile();
audioFile.setAlbum("test");
audioFile.setArtist("test");
audioFile.setLength(1);
audioFile.setPath("test");
audioFile.setTitle("test");
AudioFile a1 = null;
AudioFile a2 = null;
try {
audioFileServices.saveAudioFile(audioFile);
a1 = audioFileServices.getAudioFile(audioFile.getIdAudioFile());
a2 = audioFileServices.getAudioFile(audioFile.getIdAudioFile());
} catch (Exception e) {
e.printStackTrace();
}
ISSUE: Both audioFile1 and audioFile2 are representing the same object, (The same row in the database) however, they are two different instances and not two objects referencing the same instance. (As I wish it would be) Therefore, any modification made to the first object does not affect the second one. (Even though they are both mapped to the same database row)
I have properly configured the application context to inject the AudioFileDAO bean into the AudioFileService bean and am using the Service layer architecture. Everything works perfectly except for this annoying issue. I have also set up transactions and am using the sessionFactory bean that is injected into the AudioFileDAO bean by SPRING as well.
Do any of you know what I am missing here? Maybe it is a HIBERNATE configuration issue?
Any ideas?
Thank you in advance. (I can provide a copy of my application-context, service, and dao code if needed)
How about set a2 = a1, instead of getting from method getAudioFile.
This is likely because Hibernate is not caching retrieved instances of your objects. I would look into Hibernate Configuration

Resources