package com.socrata.datasync.config.controlfile; import com.socrata.datasync.PublishMethod; import com.socrata.exceptions.SodaError; import junit.framework.TestCase; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.map.ObjectMapper; import org.junit.Test; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.HashSet; import java.util.Set; public class ControlFileTest { Integer skip = 0; Boolean emptyTextIsNull = true; Boolean trimSpace = true; Boolean trimServerSpace = false; Boolean useGeocoding = true; Boolean columnStatistics = true; Boolean setAsideErrors = false; String encoding = "utf-8"; String timezone = "UTC"; String[] columns = {"boo", "bar", "baz"}; // String fileTypeInnardsStart = "{" + // "\"columns\":[\"boo\",\"bar\",\"baz\"]," + // "\"emptyTextIsNull\":" + emptyTextIsNull + "," + // "\"encoding\":\"" + encoding + "\"," + // "\"fixedTimestampFormat\":[\"ISO8601\",\"MM/dd/yy\",\"MM/dd/yyyy\",\"dd-MMM-yyyy\",\"MM/dd/yyyy HH:mm:ss a Z\",\"MM/dd/yyyy HH:mm:ss a\"]," + // "\"floatingTimestampFormat\":[\"ISO8601\",\"MM/dd/yy\",\"MM/dd/yyyy\",\"dd-MMM-yyyy\",\"MM/dd/yyyy HH:mm:ss a Z\",\"MM/dd/yyyy HH:mm:ss a\"]," + // "\"ignoreColumns\":[]," + // "\"overrides\":{},"; // String fileTypeInnardsStartReplace = "{" + // "\"columnStatistics\":" + columnStatistics + "," + // fileTypeInnardsStart; // // String fileTypeInnardsStartAppend = "{" + // fileTypeInnardsStart; String fileTypeInnardsEnd = "\"setAsideErrors\":" + setAsideErrors + "," + "\"skip\":" + skip + "," + "\"timezone\":\"" + timezone + "\"," + "\"trimServerWhitespace\":" + trimServerSpace + "," + "\"trimWhitespace\":" + trimSpace +"," + "\"useSocrataGeocoding\":" + useGeocoding + "}"; ObjectMapper mapper = new ObjectMapper().enable(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY); private String getFileTypeInnardsStart(PublishMethod method) { StringBuffer fileTypeInnards = new StringBuffer("{"); //Replace adds columns statistics to the FTC if (method.equals(PublishMethod.replace)) fileTypeInnards.append("\"columnStatistics\":" + columnStatistics + ","); fileTypeInnards.append("\"columns\":[\"boo\",\"bar\",\"baz\"]," + "\"emptyTextIsNull\":" + emptyTextIsNull + "," + "\"encoding\":\"" + encoding + "\"," + "\"fixedTimestampFormat\":[\"ISO8601\",\"MM/dd/yy\",\"MM/dd/yyyy\",\"dd-MMM-yyyy\",\"MM/dd/yyyy hh:mm:ss a Z\",\"MM/dd/yyyy hh:mm:ss a\"]," + "\"floatingTimestampFormat\":[\"ISO8601\",\"MM/dd/yy\",\"MM/dd/yyyy\",\"dd-MMM-yyyy\",\"MM/dd/yyyy hh:mm:ss a Z\",\"MM/dd/yyyy hh:mm:ss a\"]," + "\"ignoreColumns\":[]," + "\"overrides\":{},"); return fileTypeInnards.toString(); } @Test public void testDefaultControlFileGenerationReplaceCsv() throws SodaError, InterruptedException, IOException { String expectedJson = "{" + "\"action\":\"Replace\"," + "\"csv\":" + getFileTypeInnardsStart(PublishMethod.replace) + "\"quote\":\"\\\"\"," + "\"separator\":\",\"," + fileTypeInnardsEnd + "}"; ControlFile control = ControlFile.generateControlFile("some_file.csv", PublishMethod.replace, columns, true, true); String actualJson = mapper.writeValueAsString(control); TestCase.assertEquals(expectedJson, actualJson); } @Test public void testDefaultControlFileGenerationDeleteCsv() throws SodaError, InterruptedException, IOException { String expectedJson = "{" + "\"action\":\"Delete\"," + "\"csv\":{" + "\"columns\":[\"myid\"]," + "\"encoding\":\"utf-8\"," + "\"quote\":\"\\\"\"" + "}}"; ControlFile control = ControlFile.generateControlFile("some_file.csv", PublishMethod.delete, new String[]{"myid"}, true,true); String actualJson = mapper.writeValueAsString(control); TestCase.assertEquals(expectedJson, actualJson); } @Test public void testDefaultControlFileGenerationTsv() throws SodaError, InterruptedException, IOException { String expectedJson = "{" + "\"action\":\"Append\"," + "\"tsv\":" + getFileTypeInnardsStart(PublishMethod.append) + "\"quote\":\"\\u0000\"," + "\"separator\":\"\\t\"," + fileTypeInnardsEnd + "}"; ControlFile control = ControlFile.generateControlFile("some_file.tsv", PublishMethod.append, columns, true, true); String actualJson = mapper.writeValueAsString(control); TestCase.assertEquals(expectedJson, actualJson); } @Test public void testDeserializationDefaultControlFile() throws IOException { String controlFileJson = "{" + "\"action\":\"Replace\"," + "\"csv\":" + getFileTypeInnardsStart(PublishMethod.replace) + "\"quote\":\"\\\"\"," + "\"separator\":\",\"," + fileTypeInnardsEnd + "}"; ControlFile cf = mapper.readValue(controlFileJson, ControlFile.class); TestCase.assertEquals("Replace", cf.action); TestCase.assertNotNull(cf.getCsvFtc()); TestCase.assertNull(cf.getTsvFtc()); TestCase.assertEquals(3, cf.getCsvFtc().columns.length); TestCase.assertEquals(skip, cf.getCsvFtc().skip); TestCase.assertEquals(6, cf.getCsvFtc().fixedTimestampFormat.length); TestCase.assertEquals(6, cf.getCsvFtc().floatingTimestampFormat.length); TestCase.assertEquals(encoding, cf.getCsvFtc().encoding); TestCase.assertEquals(emptyTextIsNull, cf.getCsvFtc().emptyTextIsNull); TestCase.assertEquals(trimServerSpace, cf.getCsvFtc().trimServerWhitespace); TestCase.assertEquals(trimSpace, cf.getCsvFtc().trimWhitespace); TestCase.assertNull(cf.getCsvFtc().escape); TestCase.assertTrue(cf.getCsvFtc().useSocrataGeocoding); TestCase.assertNull(cf.getCsvFtc().syntheticLocations); } @Test public void testDeserializationCompleteControlFile() throws IOException { File controlFile = new File("src/test/resources/datasync_complex_control.json"); ControlFile cf = mapper.readValue(controlFile, ControlFile.class); TestCase.assertEquals("someSillyUUIDforMyInternalUse", cf.opaque); TestCase.assertEquals("Delete", cf.action); TestCase.assertNotNull(cf.getCsvFtc()); TestCase.assertNull(cf.getTsvFtc()); TestCase.assertEquals(3, cf.getCsvFtc().columns.length); TestCase.assertEquals(1, cf.getCsvFtc().ignoreColumns.length); TestCase.assertEquals(skip, cf.getCsvFtc().skip); TestCase.assertEquals(4, cf.getCsvFtc().fixedTimestampFormat.length); TestCase.assertEquals(4, cf.getCsvFtc().floatingTimestampFormat.length); TestCase.assertEquals(encoding, cf.getCsvFtc().encoding); TestCase.assertEquals(emptyTextIsNull, cf.getCsvFtc().emptyTextIsNull); TestCase.assertEquals(trimSpace, cf.getCsvFtc().trimServerWhitespace); TestCase.assertEquals(trimSpace, cf.getCsvFtc().trimWhitespace); TestCase.assertEquals("TenPercent", cf.getCsvFtc().dropUninterpretableRows); TestCase.assertEquals("\\\\", cf.getCsvFtc().escape); TestCase.assertEquals(useGeocoding, cf.getCsvFtc().useSocrataGeocoding); TestCase.assertNotNull(cf.getCsvFtc().overrides); TestCase.assertNotNull(cf.getCsvFtc().syntheticLocations); TestCase.assertFalse(cf.getCsvFtc().overrides.get("column1").useSocrataGeocoding); ColumnOverride co = cf.getCsvFtc().overrides.get("column1"); TestCase.assertTrue(co.emptyTextIsNull); TestCase.assertNull(co.trimServerWhitespace); TestCase.assertEquals(2, co.timestampFormat.length); TestCase.assertEquals("PDT", co.timezone); LocationColumn lc = cf.getCsvFtc().syntheticLocations.get("loc1"); TestCase.assertEquals("WA", lc.state); TestCase.assertNull(lc.latitude); } @Test public void testSingleValueAsArray() throws IOException { String controlFileJson = "{" + "\"action\":\"Replace\"," + "\"csv\":" + "{" + "\"fixedTimestampFormat\":\"ISO8601\"" + "}" + "}"; ControlFile cf = mapper.readValue(controlFileJson, ControlFile.class); TestCase.assertEquals("ISO8601", cf.getCsvFtc().fixedTimestampFormat[0]); } @Test public void testLookupTimestampFormatting() throws IOException { File controlFile = new File("src/test/resources/datasync_complex_control.json"); ControlFile cf = mapper.readValue(controlFile, ControlFile.class); Set<String> expectedFormats = new HashSet<>( Arrays.asList("ISO8601","MM/dd/yy", "MM/dd/yyyy", "dd-MMM-yyyy", "MM/YYYY", "YYYY/MM")); Set<String> actualFormats = cf.getCsvFtc().lookupTimestampFormatting(); for(String expected : expectedFormats) TestCase.assertTrue(actualFormats.remove(expected)); TestCase.assertEquals(0, actualFormats.size()); } }