My service would throw an InvalidOperationException if the result of the query
PaymentDetails.findByIdAndAmountDateCreatedGreaterThanEquals is NOT NULL
The function aims to check if there are duplicate details from the last 5 minutes.
I'm trying to create a unit test for this but the function always returns NULL instead
given:
DateUtils.getCurrentDate() >> new Date()
Date currentDate = new Date()
Date twoMinutesBeforeCurrentDate = new Date()
use (TimeCategory) {
twoMinutesBeforeCurrentDate = currentDate - 2.minutes
}
long methodId = 3L
BigDecimal amount = new BigDecimal("5")
PaymentDetails details = new PaymentDetails(amount: amount, id:methodId).save(flush: true)
details.dateCreated = twoMinutesBeforeCurrentDate
details.save(flush: true)
when:
service.validateTransactionDetails(methodId, amount)
then:
InvalidOperationException exception = thrown()
ApiError.SAME_PAYMENT_DETAILS_WITH_PREVIOUS_TRANSACTION == exception.apiError
Here is my service method:
Date currentDate = DateUtils.getCurrentDate()
Date fiveMinutesBeforeCurrentDate = null
use (TimeCategory) {
fiveMinutesBeforeCurrentDate = currentDate-5.minutes
}
PaymentDetails details = PaymentDetails.findByIdAndAmountDateCreatedGreaterThanEquals(methodId, amount, fiveMinutesBeforeCurrentDate)
if (details) {
throw new InvalidOperationException(ApiError.SAME_PAYMENT_DETAILS_WITH_PREVIOUS_TRANSACTION)
}
Thank you in advance! It's my first time debugging something from Grails and I'm having a hard time on this. Please be gentle. Lol.
The problem is that new PaymentDetails(amount: amount, id:methodId) isn't really valid because ids are by default excluded from mass property binding so your PaymentDetails instance does not have the id you think it does (you can verify that by inspecting the object in the debugger if you like). A better idea is to let the entity be assigned an id by the save method and then retrieve that value later to initiate the query. This works:
import grails.testing.gorm.DataTest
import grails.testing.services.ServiceUnitTest
import groovy.time.TimeCategory
import spock.lang.Specification
class PaymentServiceSpec extends Specification implements ServiceUnitTest<PaymentService>, DataTest{
#Override
Class[] getDomainClassesToMock() {
[PaymentDetails]
}
void "test payment details validation"() {
given:
Date currentDate = new Date()
GroovySpy(DateUtils, global: true)
1 * DateUtils.getCurrentDate() >> currentDate
Date twoMinutesBeforeCurrentDate
use (TimeCategory) {
twoMinutesBeforeCurrentDate = currentDate - 2.minutes
}
BigDecimal amount = new BigDecimal("5")
PaymentDetails details = new PaymentDetails(amount: amount).save(flush: true)
when:
service.validateTransactionDetails(details.id, amount)
then:
InvalidOperationException exception = thrown()
ApiError.SAME_PAYMENT_DETAILS_WITH_PREVIOUS_TRANSACTION == exception.apiError
}
}
I hope that helps.
Related
I have API that post and get dates:
this is the data class:
data class PlannerGet(
val date: String,
val endTime: String,
val id: Int,
val location: String,
val note: String,
val startTime: String,
val title: String
)
and i am using this library for the calendar:
https://github.com/VarunBarad/Highlightable-Calendar-View
now in the fragment i was able to highlight certain days like this:
HighlightableCalendarView.dayDecorators = listOf(
DayDecorator(
Calendar.getInstance().apply {
set(Calendar.DAY_OF_MONTH, 4)
},
Color.parseColor("#ffffff"),
Color.parseColor("#ff0000")
),
)
but i want to highlight the days from API
i tried to make it like this:
HighlightableCalendarView.dayDecorators = listOf(
DayDecorator(
Calendar.getInstance().apply {
set(PlannerGet.date)
},
Color.parseColor("#ffffff"),
Color.parseColor("#ff0000")
),
)
but i am having a problem with "set" it show "None of the following functions can be called with the arguments supplied."
i tried to add "toInt()" and still the same problem.
what is the correct way to achieve this?
This is because the params which you are passing do not match the required params.
Calendar.getInstance().apply {
set(Calendar.DAY_OF_MONTH, 4)
}
The set functions accept the int field, int value but you are passing the params as the string
PlannerGet.date
The function set
public void set(int field, int value) {
throw new RuntimeException("Stub!");
}
If you want the date to be passed from the API dates please convert the string dates to java Date object.
SOLUTION:
if (response?.body().toString() == "[]") {
}
else if (response.isSuccessful) {
response.body()?.forEach {
getplanner.add(it)
Log.e("gggg gggg",getplanner.toString())
Log.e("gggg ddddd",getplanner[0].date)
}
val list = arrayListOf<DayDecorator>()
for (dsds in getplanner) {
list.add( DayDecorator(
Calendar.getInstance().apply {
// getplanner[0].date
val input_date = dsds.date
val format1 = SimpleDateFormat("yyyy-MM-dd")
var dt1: Date? = null
dt1 = format1.parse(input_date)
val format2: DateFormat = SimpleDateFormat("dd")
val strMonth: String = format2.format(dt1)
val month = strMonth.toInt()
Log.e("dateinplanner", "" + month)
set(Calendar.DAY_OF_MONTH, month)
},
Color.parseColor("#ffffff"),
Color.parseColor("#1AB7B8")
))
}
HighlightableCalendarView.dayDecorators = list
I'm trying to fetch lower/upper endpoint from range and when it comes to fetch these lower/upper Endpoints it throws exception which goes like this:
java.lang.IllegalArgumentException: No instant converter found for type: java.time.ZonedDateTime
at org.joda.time.convert.ConverterManager.getInstantConverter(ConverterManager.java:166)
at org.joda.time.base.BaseDateTime.<init>(BaseDateTime.java:171)
at org.joda.time.DateTime.<init>(DateTime.java:257)
The code:
#Override
public WeatherStatus getForecastForFlightOverall(String icao, ... flight) {
...
if ( flightmapIntegration.isMetIntegrationEnabled() ) {
List<ViewFlightAirportDTO> airports = getRoutes(icao, flight);
Range<ZonedDateTime> range = getRange(airports);
DateTime from = range.lowerEndpoint() == null ? null : new DateTime(range.lowerEndpoint());
...
try {
....
}
}
return status != null ? status : WeatherStatus.UNKNOWN;
}
getRange method:
private Range<ZonedDateTime> getRange(List<...> ...) {
if ( ....isEmpty() ) {
return Range.singleton(ZonedDateTime.now());
}
Range<ZonedDateTime> result = validityRangeOf(....get(0));
for (int i = 1; i < flightAirports.size(); i++) {
result = ...
}
return result;
}
validtyRangeOf method:
private Range<ZonedDateTime> validityRangeOf(ViewFlightAirportDTO firstAirport) {
return Range.closed(firstAirport.getValidFrom(), firstAirport.getValidTill());
}
EDIT
I can make like this, but do not know how to finish it. I mean from/to can be also type of ZonedDateTime but I do not know how to create object of it with lower/upper Endpoint
ZonedDateTime from = range.lowerEndpoint() == null ? null : new ZonedDateTime(...);
ZonedDateTime to = ...
You are currently trying to convert from ZonedDateTime to DateTime by calling the constructor directly.
ZonedDateTime zonedDateTime = ZonedDateTime.now();
DateTime dateTime = new DateTime(zonedDateTime); // will cause IllegalArgumentException
You need to call a different constructor to make this conversion:
DateTimeZone dateTimeZone = DateTimeZone.forID(zonedDateTime.getZone().getId()); // extract DateTimeZone separately
new DateTime(zonedDateTime.toInstant().toEpochMilli(), dateTimeZone); // convert using epoch milliseconds
This will allow you to do this conversion.
I am trying to integrate a database with a web application that extracts event data from Google Calendar API which inputs the data into the database. The following code is identical to the Quickstart class provided by Google.
I basically want 'DateTime start' to be converted to 'long start'. I need the long value for SQL.
import com.google.api.client.util.DateTime;
// ...
DateTime now = new DateTime(System.currentTimeMillis());
Events events = service.events().list(calendarId)
.setTimeMin(now)
.setOrderBy("startTime")
.setSingleEvents(true)
.execute();
List<Event> items = events.getItems();
if (items.isEmpty()) {
System.out.println("No upcoming events found.");
} else {
System.out.println("Upcoming events");
for (Event event : items) {
DateTime start = event.getStart().getDateTime();
DateTime end = event.getEnd().getDateTime();
if (start == null) {
start = event.getStart().getDate();
}
System.out.printf("%s\n", start.toString());
Google has implemented the Rfc3339 parser in Google HTTP Client Library. You can try parsing it first and the use the DateTime.getValue() function to convert it into long.
You may also try using the DatetimeFormatter to format it to the way you want the value.
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.withZone(ZoneId.of("UTC"));
public void convertDatetime() {
String timeStamp = "2019-05-24T11:32:26.553955473Z";
DateTime dateTime = DateTime.parseRfc3339(timeStamp);
long millis = dateTime.getValue();
String result = formatter.format(new Date(millis).toInstant());
I have tested three variation of the same code and I got it to work just fine. I want to know why the different behavior.
So I have this working code, which converts a long time stamp to a string of the ECMA date standard format :
lazy val dateFormat = new java.text.SimpleDateFormat("yyyy-MM-DD'T'HH:mm:ss.sssZ")
implicit def dateToECMAFormat(time: Long) = new {
def asECMADateString: String = {
dateFormat.format(new java.util.Date(time))
}
}
Other variation that works :
implicit def dateToECMAFormat(time: Long) = new {
val dateFormat = new java.text.SimpleDateFormat("yyyy-MM-DD'T'HH:mm:ss.sssZ")
def asECMADateString: String = {
dateFormat.format(new java.util.Date(time))
}
}
But I do not want the SimpleDateFormat to be re instanciated all the time . So I prefere the first one. But now the real mystery :
val dateFormat = new java.text.SimpleDateFormat("yyyy-MM-DD'T'HH:mm:ss.sssZ")
implicit def dateToECMAFormat(time: Long) = new {
def asECMADateString: String = {
dateFormat.format(new java.util.Date(time))
}
}
This last piece of code compiles but throws an exception at run-time; I did not manage to get the stack trace from play framework. I just know my controller in play framework 2.1 return with a 500 (Internal Server Error) without any more information (the other controllers work though and the main services are still up).
In each case the call looks like this: 100000L.asECMADateString
Can someone explain to me the different behaviors and why does the last one does not work? I though I had a good grasp of the difference between val, lazy val and def, but now I feel like I am missing something.
UPDATE
The code is called in object like this :
object MyController extends Controller{
implicit val myExecutionContext = getMyExecutionContext
lazy val dateFormat = new java.text.SimpleDateFormat("yyyy-MM-DD'T'HH:mm:ss.sssZ")
implicit def dateToECMAFormat(time: Long) = new {
def asECMADateString: String = {
dateFormat.format(new java.util.Date(time))
}
}
def myAction = Action {
Async {
future {
blocking{
//here get some result from a db
val result = getStuffFromDb
result.someLong.asECMADateString
}
} map { result => Ok(result) } recover { /* return some error code */ }
}
}
}
It is your basic playframework Async action call.
Since the difference between the 1st and 3rd examples are the lazy val, I'd be looking at exactly where your call (100000L.asECMADateString) is being made. lazy val helps correct some "order of initialization" issues with mix-ins, for example: see this recent issue to see if it's similar to yours.
I have an ArrayList including several number of time-stamps and the aim is finding the difference of the first and the last elements of the ArrayList.
String a = ArrayList.get(0);
String b = ArrayList.get(ArrayList.size()-1);
long diff = b.getTime() - a.getTime();
I also converted the types to int but still it gives me an error The method getTime is undefined for the type String.
Additional info :
I have a class A which includes
String timeStamp = new SimpleDateFormat("ss S").format(new Date());
and there is a class B which has a method private void dialogDuration(String timeStamp)
and dialogueDuration method includes:
String a = timeSt.get(0); // timeSt is an ArrayList which includes all the timeStamps
String b = timeSt.get(timeSt.size()-1); // This method aims finding the difference of the first and the last elements(timestamps) of the ArrayList (in seconds)
long i = Long.parseLong(a);
long j = Long.parseLong(b);
long diff = j.getTime()- i.getTime();
System.out.println("a: " +i);
System.out.println("b: " +j);
And one condition is that the statement(String timeStamp = new SimpleDateFormat("ss S").format(new Date());) wont be changed in class A. And an object of class B is created in class A so that it invokes the dialogueDuration(timeStamp) method and passes the values of time-stamps to class B.
My problem is this subtraction does not work, it gives an error cannot invoke getTime() method on the primitive type long. It gives the same kind of error also for int and String types?
Thanks a lot in advance!
Maybe like this:
SimpleDateFormat dateFormat = new SimpleDateFormat("ss S");
Date firstParsedDate = dateFormat.parse(a);
Date secondParsedDate = dateFormat.parse(b);
long diff = secondParsedDate.getTime() - firstParsedDate.getTime();
Assuming you have Timestamp objects or Date Objects in your ArrayList you could do:
Timestamp a = timeSt.get(0);
Timestamp b = timeSt.get(timeSt.size()-1);
long diff = b.getTime() - a.getTime();
You can calculate the difference with the both following methods(also you can modify the mentioned methods to return difference as 'millisecond', 'day', 'month', etc by adding additional if statement or using switch case):
private Long calculateDifference(String date1, String date2, String value) {
Timestamp date_1 = stringToTimestamp(date1);
Timestamp date_2 = stringToTimestamp(date2);
long milliseconds = date_1.getTime() - date_2.getTime();
if (value.equals("second"))
return milliseconds / 1000;
if (value.equals("minute"))
return milliseconds / 1000 / 60;
if (value.equals("hours"))
return milliseconds / 1000 / 3600;
else
return new Long(999999999);
}
private Timestamp stringToTimestamp(String date) {
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date parsedDate = dateFormat.parse(date);
return new Timestamp(parsedDate.getTime());
} catch (Exception e) {
return null;
}
}
For example:
calculateDifference("2021-10-20 10:00:01", "2021-10-20 10:15:01", "minute");
will return '-15'
or
calculateDifference("2021-10-20 12:00:01", "2021-10-20 10:15:01", "minute");
will return '105'
You should make your ArrayList x to an ArrayList<TimeStamp> x. Subsequently, your method get(int) will return an object of type TimeStamp (instead of a type String). On a TimeStamp you are allowed to invoke getTime().
By the way, do you really need java.sql.TimeStamp? Maybe a simple Date or Calendar is easier and more appropriate.