|
@@ -19,6 +19,7 @@
|
|
|
package org.apache.hadoop.mapreduce.v2.jobhistory;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
+import static java.nio.charset.StandardCharsets.UTF_8;
|
|
|
|
|
|
import org.apache.hadoop.mapreduce.JobID;
|
|
|
import org.apache.hadoop.mapreduce.TypeConverter;
|
|
@@ -30,14 +31,14 @@ import org.junit.Test;
|
|
|
public class TestFileNameIndexUtils {
|
|
|
|
|
|
private static final String OLD_JOB_HISTORY_FILE_FORMATTER = "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + JobHistoryUtils.JOB_HISTORY_FILE_EXTENSION;
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + JobHistoryUtils.JOB_HISTORY_FILE_EXTENSION;
|
|
|
|
|
|
private static final String OLD_FORMAT_BEFORE_ADD_START_TIME = "%s"
|
|
|
+ FileNameIndexUtils.DELIMITER + "%s"
|
|
@@ -51,29 +52,29 @@ public class TestFileNameIndexUtils {
|
|
|
+ JobHistoryUtils.JOB_HISTORY_FILE_EXTENSION;
|
|
|
|
|
|
private static final String JOB_HISTORY_FILE_FORMATTER = "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
- + JobHistoryUtils.JOB_HISTORY_FILE_EXTENSION;
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + FileNameIndexUtils.DELIMITER + "%s"
|
|
|
+ + JobHistoryUtils.JOB_HISTORY_FILE_EXTENSION;
|
|
|
|
|
|
private static final String JOB_ID = "job_1317928501754_0001";
|
|
|
private static final String SUBMIT_TIME = "1317928742025";
|
|
|
private static final String USER_NAME = "username";
|
|
|
private static final String USER_NAME_WITH_DELIMITER = "user"
|
|
|
- + FileNameIndexUtils.DELIMITER + "name";
|
|
|
+ + FileNameIndexUtils.DELIMITER + "name";
|
|
|
private static final String USER_NAME_WITH_DELIMITER_ESCAPE = "user"
|
|
|
- + FileNameIndexUtils.DELIMITER_ESCAPE + "name";
|
|
|
+ + FileNameIndexUtils.DELIMITER_ESCAPE + "name";
|
|
|
private static final String JOB_NAME = "mapreduce";
|
|
|
private static final String JOB_NAME_WITH_DELIMITER = "map"
|
|
|
- + FileNameIndexUtils.DELIMITER + "reduce";
|
|
|
+ + FileNameIndexUtils.DELIMITER + "reduce";
|
|
|
private static final String JOB_NAME_WITH_DELIMITER_ESCAPE = "map"
|
|
|
- + FileNameIndexUtils.DELIMITER_ESCAPE + "reduce";
|
|
|
+ + FileNameIndexUtils.DELIMITER_ESCAPE + "reduce";
|
|
|
private static final String FINISH_TIME = "1317928754958";
|
|
|
private static final String NUM_MAPS = "1";
|
|
|
private static final String NUM_REDUCES = "1";
|
|
@@ -123,7 +124,7 @@ public class TestFileNameIndexUtils {
|
|
|
Assert.assertEquals("Queue name different after encoding and decoding",
|
|
|
info.getQueueName(), parsedInfo.getQueueName());
|
|
|
Assert.assertEquals("Job start time different after encoding and decoding",
|
|
|
- info.getJobStartTime(), parsedInfo.getJobStartTime());
|
|
|
+ info.getJobStartTime(), parsedInfo.getJobStartTime());
|
|
|
}
|
|
|
|
|
|
@Test
|
|
@@ -173,6 +174,158 @@ public class TestFileNameIndexUtils {
|
|
|
parsedInfo.getJobName());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Verify the name of jobhistory file is not greater than 255 bytes
|
|
|
+ * even if there are some multibyte characters in the job name.
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ public void testJobNameWithMultibyteChars() throws IOException {
|
|
|
+ JobIndexInfo info = new JobIndexInfo();
|
|
|
+ JobID oldJobId = JobID.forName(JOB_ID);
|
|
|
+ JobId jobId = TypeConverter.toYarn(oldJobId);
|
|
|
+ info.setJobId(jobId);
|
|
|
+ info.setSubmitTime(Long.parseLong(SUBMIT_TIME));
|
|
|
+ info.setUser(USER_NAME);
|
|
|
+
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ info.setFinishTime(Long.parseLong(FINISH_TIME));
|
|
|
+ info.setNumMaps(Integer.parseInt(NUM_MAPS));
|
|
|
+ info.setNumReduces(Integer.parseInt(NUM_REDUCES));
|
|
|
+ info.setJobStatus(JOB_STATUS);
|
|
|
+ info.setQueueName(QUEUE_NAME);
|
|
|
+ info.setJobStartTime(Long.parseLong(JOB_START_TIME));
|
|
|
+
|
|
|
+ // Test for 1 byte UTF-8 character
|
|
|
+ // which is encoded into 1 x 3 = 3 characters by URL encode.
|
|
|
+ for (int i = 0; i < 100; i++) {
|
|
|
+ sb.append('%');
|
|
|
+ }
|
|
|
+ String longJobName = sb.toString();
|
|
|
+ info.setJobName(longJobName);
|
|
|
+
|
|
|
+ String jobHistoryFile =
|
|
|
+ FileNameIndexUtils.getDoneFileName(info, 50);
|
|
|
+
|
|
|
+ Assert.assertTrue(jobHistoryFile.length() <= 255);
|
|
|
+ String trimedJobName = jobHistoryFile.split(
|
|
|
+ FileNameIndexUtils.DELIMITER)[3]; // 3 is index of job name
|
|
|
+
|
|
|
+ // 3 x 16 < 50 < 3 x 17 so the length of trimedJobName should be 48
|
|
|
+ Assert.assertEquals(48, trimedJobName.getBytes(UTF_8).length);
|
|
|
+
|
|
|
+ // validate whether trimmedJobName by testing reversibility
|
|
|
+ byte[] trimedJobNameInByte = trimedJobName.getBytes(UTF_8);
|
|
|
+ String reEncodedTrimedJobName = new String(trimedJobNameInByte, UTF_8);
|
|
|
+ Assert.assertArrayEquals(trimedJobNameInByte,
|
|
|
+ reEncodedTrimedJobName.getBytes(UTF_8));
|
|
|
+ sb.setLength(0);
|
|
|
+
|
|
|
+ // Test for 2 bytes UTF-8 character
|
|
|
+ // which is encoded into 2 x 3 = 6 characters by URL encode.
|
|
|
+ for (int i = 0; i < 100; i++) {
|
|
|
+ sb.append('\u03A9'); // large omega
|
|
|
+ }
|
|
|
+ longJobName = sb.toString();
|
|
|
+ info.setJobName(longJobName);
|
|
|
+
|
|
|
+ jobHistoryFile =
|
|
|
+ FileNameIndexUtils.getDoneFileName(info, 27);
|
|
|
+
|
|
|
+ Assert.assertTrue(jobHistoryFile.length() <= 255);
|
|
|
+ trimedJobName = jobHistoryFile.split(
|
|
|
+ FileNameIndexUtils.DELIMITER)[3]; // 3 is index of job name
|
|
|
+
|
|
|
+ // 6 x 4 < 27 < 6 x 5 so the length of trimedJobName should be 24
|
|
|
+ Assert.assertEquals(24, trimedJobName.getBytes(UTF_8).length);
|
|
|
+
|
|
|
+ // validate whether trimmedJobName by testing reversibility
|
|
|
+ trimedJobNameInByte = trimedJobName.getBytes(UTF_8);
|
|
|
+ reEncodedTrimedJobName = new String(trimedJobNameInByte, UTF_8);
|
|
|
+ Assert.assertArrayEquals(trimedJobNameInByte,
|
|
|
+ reEncodedTrimedJobName.getBytes(UTF_8));
|
|
|
+ sb.setLength(0);
|
|
|
+
|
|
|
+ // Test for 3 bytes UTF-8 character
|
|
|
+ // which is encoded into 3 x 3 = 9 characters by URL encode.
|
|
|
+ for (int i = 0; i < 100; i++) {
|
|
|
+ sb.append('\u2192'); // rightwards arrow
|
|
|
+ }
|
|
|
+ longJobName = sb.toString();
|
|
|
+ info.setJobName(longJobName);
|
|
|
+
|
|
|
+ jobHistoryFile =
|
|
|
+ FileNameIndexUtils.getDoneFileName(info, 40);
|
|
|
+
|
|
|
+ Assert.assertTrue(jobHistoryFile.length() <= 255);
|
|
|
+ trimedJobName = jobHistoryFile.split(
|
|
|
+ FileNameIndexUtils.DELIMITER)[3]; // 3 is index of job name
|
|
|
+
|
|
|
+ // 9 x 4 < 40 < 9 x 5 so the length of trimedJobName should be 36
|
|
|
+ Assert.assertEquals(36, trimedJobName.getBytes(UTF_8).length);
|
|
|
+
|
|
|
+ // validate whether trimmedJobName by testing reversibility
|
|
|
+ trimedJobNameInByte = trimedJobName.getBytes(UTF_8);
|
|
|
+ reEncodedTrimedJobName = new String(trimedJobNameInByte, UTF_8);
|
|
|
+ Assert.assertArrayEquals(trimedJobNameInByte,
|
|
|
+ reEncodedTrimedJobName.getBytes(UTF_8));
|
|
|
+ sb.setLength(0);
|
|
|
+
|
|
|
+ // Test for 4 bytes UTF-8 character
|
|
|
+ // which is encoded into 4 x 3 = 12 characters by URL encode.
|
|
|
+ for (int i = 0; i < 100; i++) {
|
|
|
+ sb.append("\uD867\uDE3D"); // Mugil cephalus in Kanji.
|
|
|
+ }
|
|
|
+ longJobName = sb.toString();
|
|
|
+ info.setJobName(longJobName);
|
|
|
+
|
|
|
+ jobHistoryFile =
|
|
|
+ FileNameIndexUtils.getDoneFileName(info, 49);
|
|
|
+
|
|
|
+ Assert.assertTrue(jobHistoryFile.length() <= 255);
|
|
|
+ trimedJobName = jobHistoryFile.split(
|
|
|
+ FileNameIndexUtils.DELIMITER)[3]; // 3 is index of job name
|
|
|
+
|
|
|
+ // 12 x 4 < 49 < 12 x 5 so the length of trimedJobName should be 48
|
|
|
+ Assert.assertEquals(48, trimedJobName.getBytes(UTF_8).length);
|
|
|
+
|
|
|
+ // validate whether trimmedJobName by testing reversibility
|
|
|
+ trimedJobNameInByte = trimedJobName.getBytes(UTF_8);
|
|
|
+ reEncodedTrimedJobName = new String(trimedJobNameInByte, UTF_8);
|
|
|
+ Assert.assertArrayEquals(trimedJobNameInByte,
|
|
|
+ reEncodedTrimedJobName.getBytes(UTF_8));
|
|
|
+ sb.setLength(0);
|
|
|
+
|
|
|
+ // Test for the combination of 1 to 4 bytes UTF-8 characters
|
|
|
+ sb.append('\u732B') // cat in Kanji (encoded into 3 bytes x 3 characters)
|
|
|
+ .append("[") // (encoded into 1 byte x 3 characters)
|
|
|
+ .append('\u03BB') // small lambda (encoded into 2 bytes x 3 characters)
|
|
|
+ .append('/') // (encoded into 1 byte x 3 characters)
|
|
|
+ .append('A') // not url-encoded (1 byte x 1 character)
|
|
|
+ .append("\ud867\ude49") // flying fish in
|
|
|
+ // Kanji (encoded into 4 bytes x 3 characters)
|
|
|
+ .append('\u72AC'); // dog in Kanji (encoded into 3 bytes x 3 characters)
|
|
|
+
|
|
|
+ longJobName = sb.toString();
|
|
|
+ info.setJobName(longJobName);
|
|
|
+
|
|
|
+ jobHistoryFile =
|
|
|
+ FileNameIndexUtils.getDoneFileName(info, 23);
|
|
|
+
|
|
|
+ Assert.assertTrue(jobHistoryFile.length() <= 255);
|
|
|
+ trimedJobName = jobHistoryFile.split(
|
|
|
+ FileNameIndexUtils.DELIMITER)[3]; // 3 is index of job name
|
|
|
+
|
|
|
+ // total size of the first 5 characters = 22
|
|
|
+ // 23 < total size of the first 6 characters
|
|
|
+ Assert.assertEquals(22, trimedJobName.getBytes(UTF_8).length);
|
|
|
+
|
|
|
+ // validate whether trimmedJobName by testing reversibility
|
|
|
+ trimedJobNameInByte = trimedJobName.getBytes(UTF_8);
|
|
|
+ reEncodedTrimedJobName = new String(trimedJobNameInByte, UTF_8);
|
|
|
+ Assert.assertArrayEquals(trimedJobNameInByte,
|
|
|
+ reEncodedTrimedJobName.getBytes(UTF_8));
|
|
|
+ }
|
|
|
+
|
|
|
@Test
|
|
|
public void testUserNamePercentDecoding() throws IOException {
|
|
|
String jobHistoryFile = String.format(JOB_HISTORY_FILE_FORMATTER,
|