/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.flume.formatter.output; import org.apache.flume.Clock; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import javax.annotation.Nullable; import java.net.InetAddress; import java.net.UnknownHostException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.SimpleTimeZone; import java.util.TimeZone; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class TestBucketPath { private static final TimeZone CUSTOM_TIMEZONE = new SimpleTimeZone(1, "custom-timezone"); private Calendar cal; private Map<String, String> headers; private Map<String, String> headersWithTimeZone; @Before public void setUp() { cal = createCalendar(2012, 5, 23, 13, 46, 33, 234, null); headers = new HashMap<>(); headers.put("timestamp", String.valueOf(cal.getTimeInMillis())); Calendar calWithTimeZone = createCalendar(2012, 5, 23, 13, 46, 33, 234, CUSTOM_TIMEZONE); headersWithTimeZone = new HashMap<>(); headersWithTimeZone.put("timestamp", String.valueOf(calWithTimeZone.getTimeInMillis())); } /** * Tests if the internally cached SimpleDateFormat instances can be reused with different * TimeZone without interference. */ @Test public void testDateFormatCache() { TimeZone utcTimeZone = TimeZone.getTimeZone("UTC"); String test = "%c"; BucketPath.escapeString( test, headers, utcTimeZone, false, Calendar.HOUR_OF_DAY, 12, false); String escapedString = BucketPath.escapeString( test, headers, false, Calendar.HOUR_OF_DAY, 12); System.out.println("Escaped String: " + escapedString); SimpleDateFormat format = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy"); Date d = new Date(cal.getTimeInMillis()); String expectedString = format.format(d); System.out.println("Expected String: " + expectedString); Assert.assertEquals(expectedString, escapedString); } /** * Tests if the timestamp with the default timezone is properly rounded down * to 12 hours using "%c" ("EEE MMM d HH:mm:ss yyyy") formatting. */ @Test public void testDateFormatHours() { String test = "%c"; String escapedString = BucketPath.escapeString( test, headers, true, Calendar.HOUR_OF_DAY, 12); System.out.println("Escaped String: " + escapedString); Calendar cal2 = createCalendar(2012, 5, 23, 12, 0, 0, 0, null); SimpleDateFormat format = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy"); Date d = new Date(cal2.getTimeInMillis()); String expectedString = format.format(d); System.out.println("Expected String: " + expectedString); Assert.assertEquals(expectedString, escapedString); } /** * Tests if the timestamp with the custom timezone is properly rounded down * to 12 hours using "%c" ("EEE MMM d HH:mm:ss yyyy") formatting. */ @Test public void testDateFormatHoursTimeZone() { String test = "%c"; String escapedString = BucketPath.escapeString( test, headersWithTimeZone, CUSTOM_TIMEZONE, true, Calendar.HOUR_OF_DAY, 12, false); System.out.println("Escaped String: " + escapedString); Calendar cal2 = createCalendar(2012, 5, 23, 12, 0, 0, 0, CUSTOM_TIMEZONE); SimpleDateFormat format = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy"); format.setTimeZone(CUSTOM_TIMEZONE); Date d = new Date(cal2.getTimeInMillis()); String expectedString = format.format(d); System.out.println("Expected String: " + expectedString); Assert.assertEquals(expectedString, escapedString); } /** * Tests if the timestamp with the default timezone is properly rounded down * to 5 minutes using "%s" (seconds) formatting */ @Test public void testDateFormatMinutes() { String test = "%s"; String escapedString = BucketPath.escapeString( test, headers, true, Calendar.MINUTE, 5); System.out.println("Escaped String: " + escapedString); Calendar cal2 = createCalendar(2012, 5, 23, 13, 45, 0, 0, null); String expectedString = String.valueOf(cal2.getTimeInMillis() / 1000); System.out.println("Expected String: " + expectedString); Assert.assertEquals(expectedString, escapedString); } /** * Tests if the timestamp with the custom timezone is properly rounded down * to 5 minutes using "%s" (seconds) formatting */ @Test public void testDateFormatMinutesTimeZone() { String test = "%s"; String escapedString = BucketPath.escapeString( test, headersWithTimeZone, CUSTOM_TIMEZONE, true, Calendar.MINUTE, 5, false); System.out.println("Escaped String: " + escapedString); Calendar cal2 = createCalendar(2012, 5, 23, 13, 45, 0, 0, CUSTOM_TIMEZONE); String expectedString = String.valueOf(cal2.getTimeInMillis() / 1000); System.out.println("Expected String: " + expectedString); Assert.assertEquals(expectedString, escapedString); } /** * Tests if the timestamp with the default timezone is properly rounded down * to 5 seconds using "%s" (seconds) formatting */ @Test public void testDateFormatSeconds() { String test = "%s"; String escapedString = BucketPath.escapeString( test, headers, true, Calendar.SECOND, 5); System.out.println("Escaped String: " + escapedString); Calendar cal2 = createCalendar(2012, 5, 23, 13, 46, 30, 0, null); String expectedString = String.valueOf(cal2.getTimeInMillis() / 1000); System.out.println("Expected String: " + expectedString); Assert.assertEquals(expectedString, escapedString); } /** * Tests if the timestamp with the custom timezone is properly rounded down * to 5 seconds using "%s" (seconds) formatting */ @Test public void testDateFormatSecondsTimeZone() { String test = "%s"; String escapedString = BucketPath.escapeString( test, headersWithTimeZone, CUSTOM_TIMEZONE, true, Calendar.SECOND, 5, false); System.out.println("Escaped String: " + escapedString); Calendar cal2 = createCalendar(2012, 5, 23, 13, 46, 30, 0, CUSTOM_TIMEZONE); String expectedString = String.valueOf(cal2.getTimeInMillis() / 1000); System.out.println("Expected String: " + expectedString); Assert.assertEquals(expectedString, escapedString); } /** * Tests if the timestamp is properly formatted without rounding it down. */ @Test public void testNoRounding() { String test = "%c"; String escapedString = BucketPath.escapeString( test, headers, false, Calendar.HOUR_OF_DAY, 12); System.out.println("Escaped String: " + escapedString); SimpleDateFormat format = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy"); Date d = new Date(cal.getTimeInMillis()); String expectedString = format.format(d); System.out.println("Expected String: " + expectedString); Assert.assertEquals(expectedString, escapedString); } @Test public void testNoPadding() { Calendar calender; Map<String, String> calender_timestamp; calender = Calendar.getInstance(); //Check single digit dates calender.set(2014, (5 - 1), 3, 13, 46, 33); calender_timestamp = new HashMap<String, String>(); calender_timestamp.put("timestamp", String.valueOf(calender.getTimeInMillis())); SimpleDateFormat format = new SimpleDateFormat("M-d"); String test = "%n-%e"; // eg 5-3 String escapedString = BucketPath.escapeString( test, calender_timestamp, false, Calendar.HOUR_OF_DAY, 12); Date d = new Date(calender.getTimeInMillis()); String expectedString = format.format(d); //Check two digit dates calender.set(2014, (11 - 1), 13, 13, 46, 33); calender_timestamp.put("timestamp", String.valueOf(calender.getTimeInMillis())); escapedString += " " + BucketPath.escapeString( test, calender_timestamp, false, Calendar.HOUR_OF_DAY, 12); System.out.println("Escaped String: " + escapedString); d = new Date(calender.getTimeInMillis()); expectedString += " " + format.format(d); System.out.println("Expected String: " + expectedString); Assert.assertEquals(expectedString, escapedString); } @Test public void testDateFormatTimeZone() { TimeZone utcTimeZone = TimeZone.getTimeZone("UTC"); String test = "%c"; String escapedString = BucketPath.escapeString( test, headers, utcTimeZone, false, Calendar.HOUR_OF_DAY, 12, false); System.out.println("Escaped String: " + escapedString); SimpleDateFormat format = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy"); format.setTimeZone(utcTimeZone); Date d = new Date(cal.getTimeInMillis()); String expectedString = format.format(d); System.out.println("Expected String: " + expectedString); Assert.assertEquals(expectedString, escapedString); } @Test public void testDateRace() { Clock mockClock = mock(Clock.class); DateTimeFormatter parser = ISODateTimeFormat.dateTimeParser(); long two = parser.parseMillis("2013-04-21T02:59:59-00:00"); long three = parser.parseMillis("2013-04-21T03:00:00-00:00"); when(mockClock.currentTimeMillis()).thenReturn(two, three); // save & modify static state (yuck) Clock origClock = BucketPath.getClock(); BucketPath.setClock(mockClock); String pat = "%H:%M"; String escaped = BucketPath.escapeString(pat, new HashMap<String, String>(), TimeZone.getTimeZone("UTC"), true, Calendar.MINUTE, 10, true); // restore static state BucketPath.setClock(origClock); Assert.assertEquals("Race condition detected", "02:50", escaped); } private static Calendar createCalendar(int year, int month, int day, int hour, int minute, int second, int ms, @Nullable TimeZone timeZone) { Calendar cal = (timeZone == null) ? Calendar.getInstance() : Calendar.getInstance(timeZone); cal.set(year, month, day, hour, minute, second); cal.set(Calendar.MILLISECOND, ms); return cal; } @Test public void testStaticEscapeStrings() { Map<String, String> staticStrings; staticStrings = new HashMap<>(); try { InetAddress addr = InetAddress.getLocalHost(); staticStrings.put("localhost", addr.getHostName()); staticStrings.put("IP", addr.getHostAddress()); staticStrings.put("FQDN", addr.getCanonicalHostName()); } catch (UnknownHostException e) { Assert.fail("Test failed due to UnkownHostException"); } TimeZone utcTimeZone = TimeZone.getTimeZone("UTC"); String filePath = "%[localhost]/%[IP]/%[FQDN]"; String realPath = BucketPath.escapeString(filePath, headers, utcTimeZone, false, Calendar.HOUR_OF_DAY, 12, false); String[] args = realPath.split("\\/"); Assert.assertEquals(args[0],staticStrings.get("localhost")); Assert.assertEquals(args[1],staticStrings.get("IP")); Assert.assertEquals(args[2],staticStrings.get("FQDN")); StringBuilder s = new StringBuilder(); s.append("Expected String: ").append(staticStrings.get("localhost")); s.append("/").append(staticStrings.get("IP")).append("/"); s.append(staticStrings.get("FQDN")); System.out.println(s); System.out.println("Escaped String: " + realPath ); } @Test (expected = RuntimeException.class) public void testStaticEscapeStringsNoKey() { Map<String, String> staticStrings; staticStrings = new HashMap<>(); TimeZone utcTimeZone = TimeZone.getTimeZone("UTC"); String filePath = "%[abcdefg]/%[IP]/%[FQDN]"; String realPath = BucketPath.escapeString(filePath, headers, utcTimeZone, false, Calendar.HOUR_OF_DAY, 12, false); } }