/*
* Copyright(c) 2005 Center for E-Commerce Infrastructure Development, The
* University of Hong Kong (HKU). All Rights Reserved.
*
* This software is licensed under the GNU GENERAL PUBLIC LICENSE Version 2.0 [1]
*
* [1] http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
package hk.hku.cecid.ebms.spa;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.Calendar;
import java.util.TimeZone;
import org.junit.Ignore;
import junit.framework.TestCase;
import hk.hku.cecid.ebms.spa.EbmsUtility;
import hk.hku.cecid.piazza.commons.util.UtilitiesException;
/**
* The <code>EbmsUtilityTest</code> is the testcase for <code>EbmsUtility</code>.
*
* @author Twinsen Tsang
* @since 1.0.0
* @version 1.0.0
*/
public class EbmsUtilityTest extends TestCase{
// Invoked for setup.
public void setUp() throws Exception {
System.out.println();
System.out.println("---------" + this.getName() + " Start -------");
}
// Invoked for finalized.
public void tearDown() throws Exception {
System.out.println("---------" + this.getName() + " End -------");
}
/**
* Get the local timezone represenetation from the UTC. The returned
* format is "GMT+hh:mm".
* <br/><br/>
* For example, if you are located in Asia/Hong Kong, the returned
* string should be "GMT+08:00".
*/
public String getLocalTimezone(){
// Get the default timezone.
TimeZone tz = TimeZone.getDefault();
// Get the offset from UTC.
int tzOffset = tz.getOffset(new Date().getTime());
// Formatter.
DecimalFormat twoDigits = new DecimalFormat("00");
String sign = "+";
if (tzOffset < 0){ sign = "-"; tzOffset = -tzOffset; }
// calculate the timezone offset.
int hours = (tzOffset / 3600000);
int minutes = (tzOffset % 3600000) / 60000;
// Return the local timezone.
return new StringBuffer("GMT")
.append(sign)
.append(twoDigits.format(hours))
.append(":")
.append(twoDigits.format(minutes)).toString();
}
/**
* A common method to validate cirtical field for specified <code>cal</code>
*
* @param cal The calendar to test against.
* @param expectedYear
* The expected year.
* @param expectedMonth
* The expected month.
* @param expectedDay
* The expected day.
* @param expectedHour
* The expected hour.
* @param expectedMins
* The expected mins.
* @param expectedSecond
* The expected second.
* @param expectedMillisecond
* The expected millisecond.
* @param expectedTz
* The expected timezone.
*/
public void validateCalendar(Calendar cal,
int expectedYear, int expectedMonth, int expectedDay, int expectedHour,
int expectedMins, int expectedSecond, int expectedMillisecond, String expectedTz)
{
// Null test
TestCase.assertNotNull(cal);
// Value test
TestCase.assertEquals(expectedYear , cal.get(Calendar.YEAR));
TestCase.assertEquals(expectedMonth , cal.get(Calendar.MONTH)); // Month is starting from zero.
TestCase.assertEquals(expectedDay , cal.get(Calendar.DAY_OF_MONTH));
TestCase.assertEquals(expectedHour , cal.get(Calendar.HOUR_OF_DAY));
TestCase.assertEquals(expectedMins , cal.get(Calendar.MINUTE));
TestCase.assertEquals(expectedSecond , cal.get(Calendar.SECOND));
TestCase.assertEquals(expectedMillisecond , cal.get(Calendar.MILLISECOND));
TestCase.assertEquals(expectedTz , cal.getTimeZone().getID());
// Now transform it to the local machine time.
Calendar transformedCal = Calendar.getInstance();
transformedCal.setTime(cal.getTime());
// Get the timezone offset from the testing calendar from UTC.
int clOffset = cal.getTimeZone().getOffset(new Date().getTime());
// Get the timezone offset of this local machine from UTC.
int tzOffset = TimeZone.getDefault().getOffset(cal.getTimeInMillis());
// Calculate the actual offset
tzOffset = tzOffset - clOffset;
System.out.println("TimeZone Offset: " + tzOffset);
int hours = expectedHour + tzOffset / 3600000;
int mins = expectedMins + (tzOffset % 3600000) / 60000;
int days = expectedDay;
// If the offset is greater than 24.
if (hours > 24){ hours -= 24; days += 1; }
else if (hours < 0) { hours += 24; days -= 1; }
TestCase.assertEquals(hours, transformedCal.get(Calendar.HOUR_OF_DAY));
TestCase.assertEquals(mins , transformedCal.get(Calendar.MINUTE));
TestCase.assertEquals(days , transformedCal.get(Calendar.DAY_OF_MONTH));
System.out.println(transformedCal.getTime());
// Done.
}
/**
* A common method to validate cirtical field for specified <code>target</code>
* by the value in the calendar <code>control</code>.
*
* @param target
* The target calendar to test for.
* @param control
* The reference calendar to test for.
*/
public void validateCalendar(Calendar target, Calendar control)
{
// Not Null test
TestCase.assertNotNull(target);
TestCase.assertNotNull(control);
// Assert whether they are representing same time.
System.out.println("Target Calendar (de): " + target.getTime());
System.out.println("Control Calendar (de): " + control.getTime());
System.out.println("Target Calendar (ms): " + target.getTimeInMillis());
System.out.println("Control Calendar (ms): " + control.getTimeInMillis());
TestCase.assertEquals (target.getTimeInMillis(), control.getTimeInMillis());
}
/**
* Test the conversation from UTC to java calendar object.<br/><br/>
*
* Testing for the scenario the dateTime is represented as UTC and
* under the timezone in UTC (GMT+00:00) using 'Z' designator.
*/
public void testUTC2Calendar_Pos0() throws Exception {
String dateTime = "2007-07-16T13:24:56.789Z";
Calendar cal = EbmsUtility.UTC2Calendar(dateTime);
// Validate all field.
this.validateCalendar(cal, 2007, 06, 16, 13, 24, 56, 789, "UTC");
}
/**
* Test the conversation from UTC to java calendar object.<br/><br/>
*
* Testing for the scenario the dateTime is represented as UTC and
* under the timezone in UTC (GMT+00:00) using +00:00
*/
public void testUTC2Calendar_Pos1() throws Exception {
String dateTime = "2007-07-16T13:24:56.789+00:00";
Calendar cal = EbmsUtility.UTC2Calendar(dateTime);
// Validate all field.
this.validateCalendar(cal, 2007, 06, 16, 13, 24, 56, 789, "GMT+00:00");
}
/**
* Test the conversation from UTC to java calendar object.<br/><br/>
*
* Testing for the scenario the dateTime is represented as UTC and
* under the timezone GMT+08:00 (non zero timezone)
*/
public void testUTC2Calendar_Pos2() throws Exception {
String dateTime = "2007-07-16T13:24:56.789+08:00";
Calendar cal = EbmsUtility.UTC2Calendar(dateTime);
// Validate all field.
this.validateCalendar(cal, 2007, 06, 16, 13, 24, 56, 789, "GMT+08:00");
}
/**
* Test the conversation from UTC to java calendar object.<br/><br/>
*
* Testing for the scenario the dateTime is represented as UTC and
* under the timezone GMT+13:00 (boundary case)
*/
public void testUTC2Calendar_Pos3() throws Exception {
String dateTime = "2007-07-16T04:24:56.789+13:00";
Calendar cal = EbmsUtility.UTC2Calendar(dateTime);
// * We have used the hour 04 instead of 13 for testing the offset from previous day.
// Validate all field.
this.validateCalendar(cal, 2007, 06, 16, 04, 24, 56, 789, "GMT+13:00");
}
/**
* Test the conversation from UTC to java calendar object.<br/><br/>
*
* Testing for the scenario the dateTime is represented as UTC and
* under the timezone GMT-12:00 (boundary case)
*/
public void testUTC2Calendar_Pos4() throws Exception {
String dateTime = "2007-07-16T13:24:56.789-12:00";
Calendar cal = EbmsUtility.UTC2Calendar(dateTime);
// Validate all field.
this.validateCalendar(cal, 2007, 06, 16, 13, 24, 56, 789, "GMT-12:00");
}
/**
* Test the conversation from UTC to java calendar object.<br/><br/>
*
* Testing for the scenario the dateTime is represented as UTC without millisecond
* and under the timezone UTC.
*/
public void testUTC2Calendar_Pos5() throws Exception {
String dateTime = "2007-07-16T13:24:56Z";
Calendar cal = EbmsUtility.UTC2Calendar(dateTime);
// Validate all field.
this.validateCalendar(cal, 2007, 06, 16, 13, 24, 56, 0, "UTC");
}
/**
* Test the conversation from UTC to java calendar object.<br/><br/>
*
* Testing for the scenario the dateTime is represented as UTC without millisecond
* and under any timezone other than UTC.
*/
public void testUTC2Calendar_Pos6() throws Exception {
String dateTime = "2007-07-16T13:24:56-08:00";
Calendar cal = EbmsUtility.UTC2Calendar(dateTime);
// Validate all field.
this.validateCalendar(cal, 2007, 06, 16, 13, 24, 56, 0, "GMT-08:00");
}
/**
* Test the conversation from UTC to java calendar object.<br/><br/>
*
* Testing for the scenario the dateTime is represented as UTC without millisecond and 'Z'
* and under any timezone other than UTC.
*/
public void testUTC2Calendar_Pos7() throws Exception {
String dateTime = "2007-07-16T13:24:56";
Calendar cal = EbmsUtility.UTC2Calendar(dateTime);
// Validate all field.
this.validateCalendar(cal, 2007, 06, 16, 13, 24, 56, 0, "UTC");
}
/**
* Test the conversation from UTC to java calendar object.<br/><br/>
*
* Testing for the scenario the dateTime is represented as UTC with 'Z'
* and under any timezone other than UTC.
*/
public void testUTC2Calendar_Pos8() throws Exception {
String dateTime = "2007-07-16T13:24:56.789";
Calendar cal = EbmsUtility.UTC2Calendar(dateTime);
// Validate all field.
this.validateCalendar(cal, 2007, 06, 16, 13, 24, 56, 789, "UTC");
}
/**
* Test the conversation from UTC to java calendar object negatively.<br/><br/>
*
* Testing for the scenario all invalid UTC format representation.
*/
public void testUTC2Calendar_Neg0() throws Exception {
// Invalid regex format between year and month
String dateTime0 = "2007**07-16T13:24:56.789-12:00";
try{
EbmsUtility.UTC2Calendar(dateTime0);
TestCase.fail("Invalid Format of UTC datetime has not throw parsing exception.");
} catch (Exception ex) {
System.out.println("Invalid regex format between year and month passed.");
}
// Invalid regex format between month and days
String dateTime1 = "2007-07!!16T13:24:56.789-12:00";
try{
EbmsUtility.UTC2Calendar(dateTime1);
TestCase.fail("Invalid Format of UTC datetime has not throw parsing exception.");
} catch (Exception ex) {
System.out.println("Invalid regex format between month and days passed.");
}
// Invalid regex format between days and hour
String dateTime2 = "2007-07-16@@@13:24:56.789-12:00";
try{
EbmsUtility.UTC2Calendar(dateTime2);
TestCase.fail("Invalid Format of UTC datetime has not throw parsing exception.");
} catch (Exception ex) {
System.out.println("Invalid regex format between days and hour passed.");
}
// Invalid regex format between hours and minutes
String dateTime3 = "2007-07-16@T13##24:56.789-12:00";
try{
EbmsUtility.UTC2Calendar(dateTime3);
TestCase.fail("Invalid Format of UTC datetime has not throw parsing exception.");
} catch (Exception ex) {
System.out.println("Invalid regex format between hours and minutes passed.");
}
// Invalid regex format between minutes and second
String dateTime4 = "2007-07-16@T13:24~~56.789-12:00";
try{
EbmsUtility.UTC2Calendar(dateTime4);
TestCase.fail("Invalid Format of UTC datetime has not throw parsing exception.");
} catch (Exception ex) {
System.out.println("Invalid regex format between minutes and second passed.");
}
// Invalid regex format between second and millisecond
String dateTime5 = "2007-07-16@T13:24:56~_~789-12:00";
try{
EbmsUtility.UTC2Calendar(dateTime5);
TestCase.fail("Invalid Format of UTC datetime has not throw parsing exception.");
} catch (Exception ex) {
System.out.println("Invalid regex format between second and millisecond passed.");
}
// Invalid regex format between millisecond and timezone
String dateTime6 = "2007-07-16@T13:24:56.78931212:00";
try{
EbmsUtility.UTC2Calendar(dateTime6);
TestCase.fail("Invalid Format of UTC datetime has not throw parsing exception.");
} catch (Exception ex) {
System.out.println("Invalid regex format between millisecond and timezone passed.");
}
// Invalid regex format for millisecond
String dateTime7 = "2007-07-16@T13:24:56.ddd-12:00";
try{
EbmsUtility.UTC2Calendar(dateTime7);
TestCase.fail("Invalid Format of UTC datetime has not throw parsing exception.");
} catch (Exception ex) {
System.out.println("Invalid regex format for millisecond");
}
}
/**
* Test for getting the current UTC data time.<br/><br/>
*/
/**
* @throws Exception
*/
public void testGetCurrentUTCDateTime_Pos0() throws Exception {
String utc = EbmsUtility.getCurrentUTCDateTime();
Calendar sysCal = Calendar.getInstance();
Calendar utcCal = EbmsUtility.UTC2Calendar(utc);
System.out.println("UTC converted: " + utc);
// For this testcase, we should tolerate the millisecond and second due to
// there is sightly time different between creating the sysCal and utcCal.
// So we set the millisecond part to 0 for this two cal.
sysCal.set(Calendar.SECOND, 0);
sysCal.set(Calendar.MILLISECOND, 0);
utcCal.set(Calendar.SECOND, 0);
utcCal.set(Calendar.MILLISECOND, 0);
// validate the calendar field
this.validateCalendar(utcCal,
sysCal.get(Calendar.YEAR),
sysCal.get(Calendar.MONTH),
sysCal.get(Calendar.DAY_OF_MONTH),
sysCal.get(Calendar.HOUR_OF_DAY),
sysCal.get(Calendar.MINUTE),
sysCal.get(Calendar.SECOND),
sysCal.get(Calendar.MILLISECOND),
this.getLocalTimezone());
}
/**
* Test for converting from a java date object to UTC conformed representation string.
*
* Testing for the scenario the dateTime is represented as java calendar and
* under the timezone same as the machine running.
*/
@Ignore
public void testDate2UTC_Pos0() throws Exception {
Calendar cal = Calendar.getInstance();
// 2007-07-16@T13:24:56.78931212:00
cal.set(2007, 06, 16, 13, 24, 56);
cal.set(Calendar.MILLISECOND, 0);
// Convert to UTC representation
String utc = EbmsUtility.date2UTC(cal.getTime(), cal.getTimeZone());
System.out.println("UTC converted: " + utc);
// Convert back to java calendar and validate the field.
Calendar utcCal = EbmsUtility.UTC2Calendar(utc);
// validate the calendar field
//this.validateCalendar(utcCal, 2007, 6, 16, 13, 24, 56, 0, this.getLocalTimezone());
}
/**
* Test for converting from a java date object to UTC conformed representation string.
*
* Testing for the scenario the dateTime is represented as java calendar and
* under the timezone under UTC.
*/
public void testDate2UTC_Pos1() throws Exception {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
// 2007-07-16@T13:24:56.000Z
cal.set(2007, 06, 16, 13, 24, 56);
cal.set(Calendar.MILLISECOND, 789);
// Convert to UTC representation
String utc = EbmsUtility.date2UTC(cal.getTime(), cal.getTimeZone());
System.out.println("UTC converted : " + utc);
// Convert back to java calendar and validate the field.
Calendar utcCal = EbmsUtility.UTC2Calendar(utc);
// validate whether the timezone is correctly converted.
String utcTz = utcCal.getTimeZone().getID();
TestCase.assertTrue(utcTz.equals("UTC") || utcTz.equals("GMT+00:00"));
// validate the calendar field based on cal.
this.validateCalendar(utcCal, cal);
}
/**
* Test for converting from a java date object to UTC conformed representation string.
*
* Testing for the scenario the dateTime is represented as java calendar and
* under the timezone under GMT-12:00 (boundary case)
*/
public void testDate2UTC_Pos2() throws Exception {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT-12:00"));
// 2007-07-16@T13:24:56.000-12:00
cal.set(2007, 06, 16, 13, 24, 56);
cal.set(Calendar.MILLISECOND, 789);
// Convert to UTC representation
String utc = EbmsUtility.date2UTC(cal.getTime(), cal.getTimeZone());
System.out.println("UTC converted: " + utc);
// Convert back to java calendar and validate the field.
Calendar utcCal = EbmsUtility.UTC2Calendar(utc);
// validate whether the timezone is correctly converted.
TestCase.assertTrue(utcCal.getTimeZone().getID().equals("GMT-12:00"));
// validate the calendar field based on cal.
this.validateCalendar(utcCal, cal);
}
/**
* Test for converting from a java date object to UTC conformed representation string.
*
* Testing for the scenario the dateTime is represented as java calendar and
* under the timezone under GMT+13:00 (boundary case)
*/
public void testDate2UTC_Pos3() throws Exception {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+13:00"));
// 2007-07-16@T13:24:56.000-12:00
cal.set(2007, 06, 16, 13, 24, 56);
cal.set(Calendar.MILLISECOND, 789);
// Convert to UTC representation
String utc = EbmsUtility.date2UTC(cal.getTime(), cal.getTimeZone());
System.out.println("UTC converted: " + utc);
// Convert back to java calendar and validate the field.
Calendar utcCal = EbmsUtility.UTC2Calendar(utc);
// validate whether the timezone is correctly converted.
TestCase.assertTrue(utcCal.getTimeZone().getID().equals("GMT+13:00"));
// validate the calendar field based on cal.
this.validateCalendar(utcCal, cal);
}
/**
* Test for converting from GMT datetime representation to java date object.
*/
public void testGMT2Date_Pos0() throws Exception {
Date date = new Date();
String dateTime = date.toString();
Date convertedDate = EbmsUtility.GMT2Date(dateTime);
System.out.println("GMT converted: " + convertedDate);
// Since the millisecond pecision will be lost during conversion.
// we need to create a calendar and set the millisecond to zero.
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(date.getTime());
cal.set(Calendar.MILLISECOND, 0);
// Check whether the time is equal or not.
TestCase.assertEquals(convertedDate.getTime(), cal.getTimeInMillis());
}
/**
* Test for the scenario issued by Martin Kalen from the google group.<br/><br/>
*
* QUOTED FROM martin said:
* <pre>
* Hermes sends ebMS ACK messages with a non-standard timezone part of
* the timestamp (timezone info is not according to ebXML-specification,
* see background below)
*
* Background on #1:
* The recent fix for Hermes UTC timestamps uses the Java
* SimpleDateFormat "Z"-pattern for timezone, which is unfortunately
* incompatible with the ebXML specification for time zone refering to
* the XML schema data-type "dateTime" specified here:
* http://www.w3.org/TR/xmlschema-2/#dateTime
*
* Snippets from the spec:
* "dateTime consists of finite-length sequences of characters of the
* form: '-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)?
* (zzzzzz)?"
* "zzzzzz (if present) represents the timezone"
*
* From 3.2.7.3 Timezones The lexical representation of a timezone is a string of the form:
* (('+' | '-') hh ':' mm) | 'Z'"
* In Java the ':' character is missing between the "hh" and "mm" parts.
* More details on the Java SimpleDateFormat vs XSD dateTime
* incompatibility can be found here:
* </pre>
*
* Detail: http://groups.google.com/group/cecid-hermes2/browse_thread/thread/46cca8b51ca21524
*/
public void testMartinKalenIssue1() throws Exception {
// All UTC datetime should be generated through below methods
String utc = EbmsUtility.getCurrentUTCDateTime();
// if the last character is not 'Z', then the character preceding last two
// should be ":".
System.out.println(utc);
TestCase.assertTrue(
"The converted UTC string should have ':' character between the 'hh' and 'mm' parts",
(utc.charAt(utc.length() -1) != 'Z' && utc.charAt(utc.length() - 3) == ':'));
}
/**
* Test for the scenario issued by Martin Kalen from the google group.<br/><br/>
*
* <pre>
* I live in the UTC+02:00 timezone and today at 14:01 my time (=12:01
* UTC time) an incoming ebXML message with the following TTL timestamp
* was considered expired by Hermes: "2007-07-10T12:04:14Z".
* Without the change in EbmsUtility above, Hermes regards the incoming
* timestamp as 12:04 in my timezone which mutates the expected
* 12:04:14UTC to 10:04:14UTC = incorrect expiry notification to the
* sender.
* </pre>
*
* Detail: http://groups.google.com/group/cecid-hermes2/browse_thread/thread/46cca8b51ca21524
*/
public void testMartinKalenIssue2() throws Exception {
// Incoming ebMS message TTL.
String localTime = "2007-07-10T14:01:14+02:00";
String currentTime = "2007-07-10T12:01:14Z";
String timeToLive = "2007-07-10T12:04:14Z";
Calendar ttlCal = EbmsUtility.UTC2Calendar(timeToLive);
// Get the two calendar which they are representing same instant.
Calendar curCal = EbmsUtility.UTC2Calendar(currentTime);
Calendar locCal = EbmsUtility.UTC2Calendar(localTime);
// Check whether they are representing same instant.
this.validateCalendar(curCal, locCal);
// Create one more calendar for stimulating the expiration validation flow
// The timestamp created is 2007-07-10T12:01:14.
Calendar sysCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+02:00"));
sysCal.set(2007, 06, 10, 12, 01, 14);
System.out.println("System calendar : " + ttlCal.getTime());
System.out.println("System calendar : " + sysCal.getTime());
// The time to live timstamp is later than the system calendar, then it should
// return false.
TestCase.assertFalse(
"TimeToLive calendar should not eariler than system calendar",
ttlCal.getTime().before(sysCal.getTime()));
}
public void testTimeToLive() throws UtilitiesException, InterruptedException {
Calendar sysCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+10:00"));
sysCal.set(2007, 06, 10, 12, 01, 14);
System.out.println(EbmsUtility.calendar2UTC(sysCal));
String ttl = EbmsUtility.applyTimeToLiveOffset(sysCal.getTime(),2);
System.out.println(ttl);
Calendar cal = EbmsUtility.UTC2Calendar(ttl);
assertTrue(cal.after(sysCal));
sysCal.add(Calendar.SECOND, 2);
assertEquals(sysCal.getTimeInMillis(), cal.getTimeInMillis());
}
}