How to write while-loop in spring - spring

I have a test here, where I try a loop at the last assert. My point is, that I need to do while loop till .hasNoRoles(); is true
Can you please help me with how to write this while loop. Thank you :)
#Test
public void deleteAssignedRoleTest() {
/* Create new unique role */
String idRole = roleExtApi.postRoles(DefaultModelFactory.createRole()).getBody().getIdRole();
/* Create unique identity with assigned role */
IdentityAssignment identityAssignment = roleExtApi.postIdentityAssignments(DefaultModelFactory.createIdentityAssignment(idRole)).getBody();
assertThat(identityAssignment)
.isNotNull()
.hasRoles(idRole);
/* Delete assigned role */
ResponseEntity<Void> response = roleExtApi.deleteRoles(idRole);
Assertions.assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
/* Identity does not have assigned role anymore */
for (int i = 0; i < 5; i++)
assertThat(roleExtApi.getIdentityAssignments(identityAssignment.getIdIdentity()))
.hasNoRoles();
}

Related

How can I check email validation in cypress

I want to check validation for input element. Can I check if typing wrong or valid Email format in my input.
Like this.
cy.get('#email_signup').type(validateEmail())
var email = "";
var possible = "abcd#.gh";
for (var i = 0; i < 10; i++)
email += possible.charAt(Math.floor(Math.random() * possible.length));
return email;
}
cy.get('.nextBtn').click();
cy.get('.error-message').should('be.visible');
According to what you expect to do, you need two external functions to create emails and to get a valid state of emails. Then you need to loop the it hook throughout all the emails.
//Create Emails
//Did a small modification so that you can decied the email length you need
const emails = (val) => {
var email = "";
var possible = "abcd#.gh";
for (var i = 0; i < val; i++){
email += possible.charAt(Math.floor(Math.random() * possible.length));}
return email;
}
//validate emails
//I have used a general Regex here, use the regex you have used in your website insted
const validateEmail = (email) => {
var re = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/;
return re.test(email);
}
//Test Cases (I have added 10 loops so it will create 10 test cases)
//Change the test case count as much as you need
for (let index = 0; index < 10; index++) {
const TestEmail = emails(10)
const EmailState = validateEmail(TestEmail)
it("EmailTest -"+ TestEmail +" - " + EmailState,() => {
cy.get('#email_signup').type(TestEmail)
cy.get('.nextBtn').click();
if(!EmailState){
cy.get('.error-message').should('be.visible');
}else{
cy.get('.error-message').should('not.be.visible');
}
})
}
Your method of creating emails is awesome. But make sure you add a separate test to check specific and valid scenarios as random emails might not cover them all
This is how the tests are going to look like.
Note: As I have mentioned earlier. It's always better to know your test data. So Without a random generation. Try to have a list of valid, invalid email scenarios with true false conditions And loop through them.
First of all it's good to generate random emails, but the best way to do is have a set of emails in a array. (may be in a JSON) and loop through them and check for the email validity.
Eg:
{
"Email_1":"['robot#mail.com','valid']",
"Email_2":"['robotmail.com','InValid']",
}
Because then you know the email conditions you are testing. But if you want to go with a random email generation method. I totally agree with the Muditha Perera's answer. It works perfectly.

How to repeat Job with Partitioner when data is dynamic with Spring Batch?

I am trying to develop a batch process using Spring Batch + Spring Boot (Java config), but I have a problem doing so. I have a software that has a database and a Java API, and I read records from there. The batch process should retrieve all the documents which expiration date is less than a certain date, update the date, and save them again in the same database.
My first approach was reading the records 100 by 100; so the ItemReader retrieve 100 records, I process them 1 by 1, and finally I write them again. In the reader, I put this code:
public class DocumentItemReader implements ItemReader<Document> {
public List<Document> documents = new ArrayList<>();
#Override
public Document read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
if(documents.isEmpty()) {
getDocuments(); // This method retrieve 100 documents and store them in "documents" list.
if(documents.isEmpty()) return null;
}
Document doc = documents.get(0);
documents.remove(0);
return doc;
}
}
So, with this code, the reader reads from the database until no records are found. When the "getDocuments()" method doesn't retrieve any documents, the List is empty and the reader returns null (so the Job finish). Everything worked fine here.
However, the problem appears if I want to use several threads. In this case, I started using the Partitioner approach instead of Multi-threading. The reason of doing that is because I read from the same database, so if I repeat the full step with several threads, all of them will find the same records, and I cannot use pagination (see below).
Another problem is that database records are updated dynamically, so I cannot use pagination. For example, let's suppose I have 200 records, and all of them are going to expire soon, so the process is going to retrieve them. Now imagine I retrieve 10 with one thread, and before anything else, that thread process one and update it in the same database. The next thread cannot retrieve from 11 to 20 records, as the first record is not going to appear in the search (as it has been processed, its date has been updated, and then it doesn't match the query).
It is a little difficult to understand, and some things may sound strange, but in my project:
I am forced to use the same database to read and write.
I can have millions of documents, so I cannot read all the records at the same time. I need to read them 100 by 100, or 500 by 500.
I need to use several threads.
I cannot use pagination, as the query to the databse will retrieve different documents each time it is executed.
So, after hours thinking, I think the unique possible solution is to repeat the job until the query retrives no documents. Is this possible? I want to do something like the step does: Do something until null is returned - repeat the job until the query return zero records.
If this is not a good approach, I will appreciate other possible solutions.
Thank you.
Maybe you can add a partitioner to your step that will :
Select all the ids of the datas that needs to be updated (and other columns if needed)
Split them in x (x = gridSize parameter) partitions and write them in temporary file (1 by partition).
Register the filename to read in the executionContext
Then your reader is not reading from the database anymore but from the partitioned file.
Seem complicated but it's not that much, here is an example which handle millions of record using JDBC query but it can be easily transposed for your use case :
public class JdbcToFilePartitioner implements Partitioner {
/** number of records by database fetch */
private int fetchSize = 100;
/** working directory */
private File tmpDir;
/** limit the number of item to select */
private Long nbItemMax;
#Override
public Map<String, ExecutionContext> partition(final int gridSize) {
// Create contexts for each parttion
Map<String, ExecutionContext> executionsContexte = createExecutionsContext(gridSize);
// Fill partition with ids to handle
getIdsAndFillPartitionFiles(executionsContexte);
return executionsContexte;
}
/**
* #param gridSize number of partitions
* #return map of execution context, one for each partition
*/
private Map<String, ExecutionContext> createExecutionsContext(final int gridSize) {
final Map<String, ExecutionContext> map = new HashMap<>();
for (int partitionId = 0; partitionId < gridSize; partitionId++) {
map.put(String.valueOf(partitionId), createContext(partitionId));
}
return map;
}
/**
* #param partitionId id of the partition to create context
* #return created executionContext
*/
private ExecutionContext createContext(final int partitionId) {
final ExecutionContext context = new ExecutionContext();
String fileName = tmpDir + File.separator + "partition_" + partitionId + ".txt";
context.put(PartitionerConstantes.ID_GRID.getCode(), partitionId);
context.put(PartitionerConstantes.FILE_NAME.getCode(), fileName);
if (contextParameters != null) {
for (Entry<String, Object> entry : contextParameters.entrySet()) {
context.put(entry.getKey(), entry.getValue());
}
}
return context;
}
private void getIdsAndFillPartitionFiles(final Map<String, ExecutionContext> executionsContexte) {
List<BufferedWriter> fileWriters = new ArrayList<>();
try {
// BufferedWriter for each partition
for (int i = 0; i < executionsContexte.size(); i++) {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(executionsContexte.get(String.valueOf(i)).getString(
PartitionerConstantes.FILE_NAME.getCode())));
fileWriters.add(bufferedWriter);
}
// Fetching the datas
ScrollableResults results = runQuery();
// Get the result and fill the files
int currentPartition = 0;
int nbWriting = 0;
while (results.next()) {
fileWriters.get(currentPartition).write(results.get(0).toString());
fileWriters.get(currentPartition).newLine();
currentPartition++;
nbWriting++;
// If we already write on all partitions, we start again
if (currentPartition >= executionsContexte.size()) {
currentPartition = 0;
}
// If we reach the max item to read we stop
if (nbItemMax != null && nbItemMax != 0 && nbWriting >= nbItemMax) {
break;
}
}
// closing
results.close();
session.close();
for (BufferedWriter bufferedWriter : fileWriters) {
bufferedWriter.close();
}
} catch (IOException | SQLException e) {
throw new UnexpectedJobExecutionException("Error writing partition file", e);
}
}
private ScrollableResults runQuery() {
...
}
}

Laravel generate password and insert user in database by hand

I have few users with no email and password, and I would like to update users by adding email from freemail column, and setup password from random string.
This is my sample code:
public function updateUserProfil()
{
//find list user to be update(juste one to test)
$users = User::where('isfree', '1')->first();
//Random string generate
$motdepasse = str_random(6);
//find user
$updateUser= User::find($users->id);
//setup fields
$updateUser->email = $users->freemail;
$updateUser->remember_token = str_random(10);
$updateUser->motdepasse = $motdepasse;
$updateUser->password = bcrypt($motdepasse);
$updateUser->isfree = 0;
$updateUser->save();
}
The problem is that when I try to connect with email($users->freemail) and password($motdepasse), which is not encrypted random string, I get error that:
my credential is not valid
what did I miss ?
You can use update() to update rows. So your code must be
public function updateUserProfil()
{
//find list user to be update(juste one to test)
$users = User::where('isfree', '1')->first();
//Random string generate
$motdepasse = str_random(6);
//find user
$updateUser= User::find($users->id);
//setup fields
$updateUser->update([
'email'=>$users->freemail,
'remember_token'=>str_random(10),
'motdepasse'=>$motdepasse,
'password'=>bcrypt($motdepasse),
'isfree'=>0,
]);
}

Deleting List<Object> using HibernateTemplate() is giving Exception

I am trying to fetch List from table FlexiBooking and then add this to another list i.e. to move to another table and delete those entries fetched from this table. I have used HibernateTemplate() object, since the project is being done using Spring Framework. But I am getting exception that trying to delete Detatched object. What is the problem?
Below is my code:
#Override
public void moveToNormalBooking(User user,
int no_of_seats) {
String queryString = "FROM FlexiBooking";
HibernateTemplate hibernateTemplate = getHibernateTemplate();
hibernateTemplate.setMaxResults(no_of_seats);
List<FlexiBooking> flexiBookingsTobeMoved = hibernateTemplate.find(queryString);
List<FlightBooking> flightBookings = new ArrayList<FlightBooking>();
int i =0;
while(i < flexiBookingsTobeMoved.size()) {
FlightBooking flightbooking = new FlightBooking();
flightbooking.setCostPerTicket(flexiBookingsTobeMoved.get(i).getTotalCost());
flightbooking.setDateOfJourney(flexiBookingsTobeMoved.get(i).getScheduledFlight().getScheduledFlightDate());
Booking booking = new Booking();
booking.setBooker(flexiBookingsTobeMoved.get(i).getUser());
booking.setBookingDate(flexiBookingsTobeMoved.get(i).getBookingDate());
booking.setBookingReferenceNo(flexiBookingsTobeMoved.get(i).getBookingReferenceNumber());
booking.setCancelled(false);
flightbooking.setBooking(booking);
flightbooking.setFlightRoute(flexiBookingsTobeMoved.get(i).getScheduledFlight());
flightbooking.setCouponCode(flexiBookingsTobeMoved.get(i).getCouponCode());
flightBookings.add(flightbooking);
i++;
}
hibernateTemplate.saveOrUpdateAll(flightBookings);
// hibernateTemplate.update(flexiBookingsTobeMoved);
hibernateTemplate.deleteAll(flexiBookingsTobeMoved);
}

Converting string to int, array of strings

I am having an issue with converting a string of id to an int when there are multiple strings passed in, the code shows the following:
for(int i = 0; i < Request.Params["service"].Length; i++)
{
int serviceID = int.Parse(Request.Params["service"]);
db.ServiceAssignments.Add(serviceAssignment);
serviceAssignment.locationID = locationID;
serviceAssignment.ServiceID = serviceID;
db.SaveChanges();
}
If you pass in one param, you get: int.Parse(Request.Params["Service"]); = 1, which then works and the database saves. however if you have the following you get:
'1,2' which three. What I want is 1 and then 2, not 1,2.
What is 1 and 2?
When you create anew location you get to select services for that location. The service id, in the case of this problem is 1 and 2. if I select one service then it saves and all is well. When I select two or more it doesnt work.
I though I could do:
Request.Params["Service"][i] because "Service" is an array after all. How ever this causes database problems and a whole other mess.
So what would you suggest I can do to make it save id 1 and id 2 when you select them for a location?
MVC 3 is quite powerful to figure out the binding, I don't know exactly what are you doing in the view that get the service Ids from user but I assume there is form there and if all Ids are int you can do like this and you don't need any conversion, or maybe you can use FormCollection. I don't think using Request in MVC 3 is a good idea, it does not really belong the whole MVC idea.
public void Add(int[] service)
{
foreach (var item in service)
{
int serviceID = item;
}
}
OR
public void Add(FormCollection frm)
{
foreach (var item in frm.AllKeys)
{
if (item.StartsWith("service"))
{
int serviceID = Int32.Parse(frm[item]);
}
}
}
anyway none of these are also MVC, these are should work but I recommend you to use Models in views and controllers
This will work. Just tested it:
string[] items = Request.Params["service"].Split(',');
for (int i = 0; i < items.Length; i++)
{
int serviceID = int.Parse(items[i]);
db.ServiceAssignments.Add(serviceAssignment);
serviceAssignment.locationID = locationID;
serviceAssignment.ServiceID = serviceID;
db.SaveChanges();
}
As a side note, I'd probably make two changes:
I'd use a foreach statement. No real difference; just less typing.
I'd put the SaveChanges() AFTER the for loop. This will make fewer calls to the database, but still accomplish the same thing.

Resources