NIFI-2829: Fixed PutSQL time unit test.

The unit test for DATE type used GMT timezone, that causes an assertion error in timezones such as EST (-5).
We need to use local timezone instead of GMT, as Derby and PutSQL uses local timezone.

The unit test failed before as follows:
- Unit test code, passed: '2002-02-02 GMT'
- PutSQL code convertedi it to local: '2002-02-01 EST', and stored as '2002-02-01' in Derby database without timezone info
- Unit test code SELECT the inserted value, passed a GMT calender, then got epoch timestamp, which was '2002-01-31'

Support negative long value for timezones ahead of UTC.

- For timezones such as '+0800', it's possible that a local time e.g. '02:03:04' can be a negative epoch value. This commit changes LONG_PATTERN so that it can accept nevative values.
- Changed time values in unit tests to verify negative epoch values, and avoid using the same digits among different time unit for better readability.

This closes #2082
This commit is contained in:
Koji Kawamura 2017-08-14 11:19:50 +09:00 committed by Jeff Storck
parent 3fb704c58f
commit c6f4421c8e
2 changed files with 25 additions and 33 deletions

View File

@ -191,7 +191,7 @@ public class PutSQL extends AbstractSessionFactoryProcessor {
private static final String FRAGMENT_INDEX_ATTR = FragmentAttributes.FRAGMENT_INDEX.key(); private static final String FRAGMENT_INDEX_ATTR = FragmentAttributes.FRAGMENT_INDEX.key();
private static final String FRAGMENT_COUNT_ATTR = FragmentAttributes.FRAGMENT_COUNT.key(); private static final String FRAGMENT_COUNT_ATTR = FragmentAttributes.FRAGMENT_COUNT.key();
private static final Pattern LONG_PATTERN = Pattern.compile("^\\d{1,19}$"); private static final Pattern LONG_PATTERN = Pattern.compile("^-?\\d{1,19}$");
@Override @Override
protected List<PropertyDescriptor> getSupportedPropertyDescriptors() { protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {

View File

@ -38,11 +38,11 @@ import java.time.LocalTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.TimeZone;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.RandomUtils;
import org.apache.nifi.controller.AbstractControllerService; import org.apache.nifi.controller.AbstractControllerService;
@ -59,9 +59,6 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.mockito.Mockito; import org.mockito.Mockito;
import javax.xml.bind.DatatypeConverter;
import org.junit.Ignore;
public class TestPutSQL { public class TestPutSQL {
private static final String createPersons = "CREATE TABLE PERSONS (id integer primary key, name varchar(100), code integer)"; private static final String createPersons = "CREATE TABLE PERSONS (id integer primary key, name varchar(100), code integer)";
private static final String createPersonsAutoId = "CREATE TABLE PERSONS_AI (id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1), name VARCHAR(100), code INTEGER check(code <= 100))"; private static final String createPersonsAutoId = "CREATE TABLE PERSONS_AI (id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1), name VARCHAR(100), code INTEGER check(code <= 100))";
@ -460,7 +457,6 @@ public class TestPutSQL {
} }
} }
@Ignore("this test needs fixing due to TestPutSQL.testUsingDateTimeValuesWithFormatAttribute:551 expected:<1012608000000> but was:<1012521600000>")
@Test @Test
public void testUsingDateTimeValuesWithFormatAttribute() throws InitializationException, ProcessException, SQLException, IOException, ParseException { public void testUsingDateTimeValuesWithFormatAttribute() throws InitializationException, ProcessException, SQLException, IOException, ParseException {
final TestRunner runner = TestRunners.newTestRunner(PutSQL.class); final TestRunner runner = TestRunners.newTestRunner(PutSQL.class);
@ -474,8 +470,8 @@ public class TestPutSQL {
runner.enableControllerService(service); runner.enableControllerService(service);
runner.setProperty(PutSQL.CONNECTION_POOL, "dbcp"); runner.setProperty(PutSQL.CONNECTION_POOL, "dbcp");
final String dateStr = "2002-02-02"; final String dateStr = "2002-03-04";
final String timeStr = "12:02:02"; final String timeStr = "02:03:04";
final String timeFormatString = "HH:mm:ss"; final String timeFormatString = "HH:mm:ss";
final String dateFormatString ="yyyy-MM-dd"; final String dateFormatString ="yyyy-MM-dd";
@ -492,19 +488,7 @@ public class TestPutSQL {
final long expectedTimeInLong = expectedTime.getTime(); final long expectedTimeInLong = expectedTime.getTime();
final long expectedDateInLong = expectedDate.getTime(); final long expectedDateInLong = expectedDate.getTime();
//test with time zone GMT to avoid negative value unmatched with long pattern problem. // test with ISO LOCAL format attribute
SimpleDateFormat timeFormat = new SimpleDateFormat(timeFormatString);
timeFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
java.util.Date parsedTimeGMT = timeFormat.parse(timeStr);
SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatString);
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
java.util.Date parsedDateGMT = dateFormat.parse(dateStr);
Calendar gmtCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
//test with ISO LOCAL format attribute
Map<String, String> attributes = new HashMap<>(); Map<String, String> attributes = new HashMap<>();
attributes.put("sql.args.1.type", String.valueOf(Types.TIME)); attributes.put("sql.args.1.type", String.valueOf(Types.TIME));
attributes.put("sql.args.1.value", timeStr); attributes.put("sql.args.1.value", timeStr);
@ -515,22 +499,31 @@ public class TestPutSQL {
runner.enqueue("INSERT INTO TIMESTAMPTEST3 (ID, ts1, ts2) VALUES (1, ?, ?)".getBytes(), attributes); runner.enqueue("INSERT INTO TIMESTAMPTEST3 (ID, ts1, ts2) VALUES (1, ?, ?)".getBytes(), attributes);
//test Long pattern without format attribute // Since Derby database which is used for unit test does not have timezone in DATE and TIME type,
// and PutSQL converts date string into long representation using local timezone,
// we need to use local timezone.
SimpleDateFormat timeFormat = new SimpleDateFormat(timeFormatString);
java.util.Date parsedLocalTime = timeFormat.parse(timeStr);
SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatString);
java.util.Date parsedLocalDate = dateFormat.parse(dateStr);
// test Long pattern without format attribute
attributes = new HashMap<>(); attributes = new HashMap<>();
attributes.put("sql.args.1.type", String.valueOf(Types.TIME)); attributes.put("sql.args.1.type", String.valueOf(Types.TIME));
attributes.put("sql.args.1.value", Long.toString(parsedTimeGMT.getTime())); attributes.put("sql.args.1.value", Long.toString(parsedLocalTime.getTime()));
attributes.put("sql.args.2.type", String.valueOf(Types.DATE)); attributes.put("sql.args.2.type", String.valueOf(Types.DATE));
attributes.put("sql.args.2.value", Long.toString(parsedDateGMT.getTime())); attributes.put("sql.args.2.value", Long.toString(parsedLocalDate.getTime()));
runner.enqueue("INSERT INTO TIMESTAMPTEST3 (ID, ts1, ts2) VALUES (2, ?, ?)".getBytes(), attributes); runner.enqueue("INSERT INTO TIMESTAMPTEST3 (ID, ts1, ts2) VALUES (2, ?, ?)".getBytes(), attributes);
//test with format attribute // test with format attribute
attributes = new HashMap<>(); attributes = new HashMap<>();
attributes.put("sql.args.1.type", String.valueOf(Types.TIME)); attributes.put("sql.args.1.type", String.valueOf(Types.TIME));
attributes.put("sql.args.1.value", "120202000"); attributes.put("sql.args.1.value", "020304000");
attributes.put("sql.args.1.format", "HHmmssSSS"); attributes.put("sql.args.1.format", "HHmmssSSS");
attributes.put("sql.args.2.type", String.valueOf(Types.DATE)); attributes.put("sql.args.2.type", String.valueOf(Types.DATE));
attributes.put("sql.args.2.value", "20020202"); attributes.put("sql.args.2.value", "20020304");
attributes.put("sql.args.2.format", "yyyyMMdd"); attributes.put("sql.args.2.format", "yyyyMMdd");
runner.enqueue("INSERT INTO TIMESTAMPTEST3 (ID, ts1, ts2) VALUES (3, ?, ?)".getBytes(), attributes); runner.enqueue("INSERT INTO TIMESTAMPTEST3 (ID, ts1, ts2) VALUES (3, ?, ?)".getBytes(), attributes);
@ -549,8 +542,8 @@ public class TestPutSQL {
assertTrue(rs.next()); assertTrue(rs.next());
assertEquals(2, rs.getInt(1)); assertEquals(2, rs.getInt(1));
assertEquals(parsedTimeGMT.getTime(), rs.getTime(2).getTime()); assertEquals(parsedLocalTime.getTime(), rs.getTime(2).getTime());
assertEquals(parsedDateGMT.getTime(), rs.getDate(3,gmtCalendar).getTime()); assertEquals(parsedLocalDate.getTime(), rs.getDate(3).getTime());
assertTrue(rs.next()); assertTrue(rs.next());
assertEquals(3, rs.getInt(1)); assertEquals(3, rs.getInt(1));
@ -692,11 +685,10 @@ public class TestPutSQL {
runner.enableControllerService(service); runner.enableControllerService(service);
runner.setProperty(PutSQL.CONNECTION_POOL, "dbcp"); runner.setProperty(PutSQL.CONNECTION_POOL, "dbcp");
final String arg2TS = "00:01:01"; final String arg2TS = "00:01:02";
final String art3TS = "12:02:02"; final String art3TS = "02:03:04";
final String timeFormatString = "HH:mm:ss"; final String timeFormatString = "HH:mm:ss";
SimpleDateFormat dateFormat = new SimpleDateFormat(timeFormatString); SimpleDateFormat dateFormat = new SimpleDateFormat(timeFormatString);
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
java.util.Date parsedDate = dateFormat.parse(arg2TS); java.util.Date parsedDate = dateFormat.parse(arg2TS);