diff --git a/src/main/java/com/salesforce/dataloader/util/DateOnlyCalendar.java b/src/main/java/com/salesforce/dataloader/util/DateOnlyCalendar.java index 3dacc1d8..ac0ba848 100644 --- a/src/main/java/com/salesforce/dataloader/util/DateOnlyCalendar.java +++ b/src/main/java/com/salesforce/dataloader/util/DateOnlyCalendar.java @@ -31,7 +31,6 @@ import java.util.TimeZone; import com.salesforce.dataloader.config.AppConfig; -import com.salesforce.dataloader.util.DLLogManager; import org.apache.logging.log4j.Logger; public class DateOnlyCalendar extends GregorianCalendar { @@ -59,15 +58,21 @@ public void setTimeInMillis(long specifiedTimeInMilliSeconds) { TimeZone myTimeZone = super.getTimeZone(); if (myTimeZone == null) { - logger.info("timezone is null"); + logger.info("timezone is null. Settting it to GMT"); + myTimeZone = GMT_TZ; + super.setTimeZone(myTimeZone); } else { logger.info("Timezone is " + myTimeZone.getDisplayName()); } Calendar cal = Calendar.getInstance(myTimeZone); cal.setTimeInMillis(specifiedTimeInMilliSeconds); - if (!AppConfig.getCurrentConfig().getBoolean(AppConfig.PROP_GMT_FOR_DATE_FIELD_VALUE) - && myTimeZone != null) { + boolean useGMTForDateField = false; + AppConfig config = AppConfig.getCurrentConfig(); + if (config != null) { + useGMTForDateField = config.getBoolean(AppConfig.PROP_GMT_FOR_DATE_FIELD_VALUE); + } + if (!useGMTForDateField && myTimeZone != null) { // Set hour, minute, second, and millisec to 0 (12:00AM) as it is date-only value cal.set(Calendar.HOUR, 0); cal.set(Calendar.MINUTE, 0); @@ -85,7 +90,12 @@ public void setTimeInMillis(long specifiedTimeInMilliSeconds) { } public static DateOnlyCalendar getInstance(TimeZone timeZone) { - if (AppConfig.getCurrentConfig().getBoolean(AppConfig.PROP_GMT_FOR_DATE_FIELD_VALUE)) { + boolean useGMTForDateField = false; + AppConfig config = AppConfig.getCurrentConfig(); + if (config != null) { + useGMTForDateField = config.getBoolean(AppConfig.PROP_GMT_FOR_DATE_FIELD_VALUE); + } + if (useGMTForDateField || timeZone == null) { timeZone = GMT_TZ; } return new DateOnlyCalendar(timeZone); diff --git a/src/test/java/com/salesforce/dataloader/config/AppConfigEdgeTest.java b/src/test/java/com/salesforce/dataloader/config/AppConfigEdgeTest.java new file mode 100644 index 00000000..050ad952 --- /dev/null +++ b/src/test/java/com/salesforce/dataloader/config/AppConfigEdgeTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015, salesforce.com, inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.salesforce.dataloader.config; +import static org.junit.Assert.*; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import org.junit.Before; +import org.junit.Test; +import com.salesforce.dataloader.exception.ConfigInitializationException; + +public class AppConfigEdgeTest { + private AppConfig appConfig; + + @Before + public void setUp() throws ConfigInitializationException, IOException { + Map testConfigMap = new HashMap<>(); + testConfigMap.put(AppConfig.PROP_SELECTED_SERVER_ENVIRONMENT, AppConfig.SERVER_PROD_ENVIRONMENT_VAL); + appConfig = AppConfig.getInstance(testConfigMap); + } + + @Test + public void testInvalidPropertyName() { + assertEquals(appConfig.getString("invalid.property.name"), ""); + } + + @Test + public void testSpecialCharactersInPropertyValue() { + String specialValue = "valueWith\nNewline\tTab\u2603Unicode"; + appConfig.setValue("special.property", specialValue); + assertEquals(specialValue, appConfig.getString("special.property")); + } + + @Test + public void testEmptyConfigurationMap() throws ConfigInitializationException, IOException { + AppConfig emptyConfig = AppConfig.getInstance(new HashMap<>()); + assertEquals(emptyConfig.getString(AppConfig.PROP_SELECTED_SERVER_ENVIRONMENT), AppConfig.SERVER_PROD_ENVIRONMENT_VAL); + } + + @Test + public void testLargeConfigurationMap() throws ConfigInitializationException, IOException { + Map largeConfigMap = new HashMap<>(); + for (int i = 0; i < 10000; i++) { + largeConfigMap.put("property" + i, "value" + i); + } + AppConfig largeConfig = AppConfig.getInstance(largeConfigMap); + assertEquals("value9999", largeConfig.getString("property9999")); + } + + @Test + public void testConcurrentModifications() throws InterruptedException { + ExecutorService executor = Executors.newFixedThreadPool(10); + for (int i = 0; i < 100; i++) { + executor.submit(() -> { + appConfig.setValue(AppConfig.PROP_BULK_API_ENABLED, true); + assertTrue(appConfig.getBoolean(AppConfig.PROP_BULK_API_ENABLED)); + }); + } + executor.shutdown(); + assertTrue(executor.awaitTermination(1, TimeUnit.MINUTES)); + } + + @Test + public void testDefaultValues() { + assertEquals(AppConfig.STRING_DEFAULT, appConfig.getString("missing.property")); + } + + @Test + public void testCaseSensitivity() { + appConfig.setValue("CaseSensitiveProperty", "value"); + assertEquals(appConfig.getString("casesensitiveproperty"), ""); + } +} diff --git a/src/test/java/com/salesforce/dataloader/util/AppUtilTest.java b/src/test/java/com/salesforce/dataloader/util/AppUtilTest.java index deaa00ae..138c07d6 100644 --- a/src/test/java/com/salesforce/dataloader/util/AppUtilTest.java +++ b/src/test/java/com/salesforce/dataloader/util/AppUtilTest.java @@ -25,17 +25,96 @@ */ package com.salesforce.dataloader.util; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.junit.Assert; import org.junit.Test; import com.salesforce.dataloader.ConfigTestBase; -public class AppUtilTest extends ConfigTestBase { +public class AppUtilTest extends ConfigTestBase { @Test - public void testHttpsTester() { + public void testIsValidHttpsUrl() { Assert.assertTrue(AppUtil.isValidHttpsUrl("https://my.com")); Assert.assertFalse(AppUtil.isValidHttpsUrl("http://my.com")); Assert.assertFalse(AppUtil.isValidHttpsUrl("my.com")); Assert.assertFalse(AppUtil.isValidHttpsUrl("ftp://my.com")); } + + @Test + public void testGetFullPathOfJar() { + String path = AppUtil.getFullPathOfJar(AppUtil.class); + Assert.assertNotNull(path); + Assert.assertTrue(path.endsWith(".jar")); + } + + @Test + public void testGetDirContainingClassJar() { + String dir = AppUtil.getDirContainingClassJar(AppUtil.class); + Assert.assertNotNull(dir); + Assert.assertTrue(new File(dir).isDirectory()); + } + + @Test + public void testConvertCommandArgsArrayToArgMap() { + String[] args = {"key1=value1", "key2=value2"}; + Map argMap = AppUtil.convertCommandArgsArrayToArgMap(args); + Assert.assertEquals("value1", argMap.get("key1")); + Assert.assertEquals("value2", argMap.get("key2")); + } + + @Test + public void testConvertCommandArgsMapToArgsArray() { + Map argMap = new HashMap<>(); + argMap.put("key1", "value1"); + argMap.put("key2", "value2"); + String[] argsArray = AppUtil.convertCommandArgsMapToArgsArray(argMap); + Assert.assertArrayEquals(new String[]{"key1=value1", "key2=value2"}, argsArray); + } + + @Test + public void testIsRunningOnMacOS() { + boolean isMac = AppUtil.isRunningOnMacOS(); + Assert.assertEquals(System.getProperty("os.name").contains("Mac"), isMac); + } + + @Test + public void testIsRunningOnWindows() { + boolean isWindows = AppUtil.isRunningOnWindows(); + Assert.assertEquals(System.getProperty("os.name").contains("Windows"), isWindows); + } + + @Test + public void testIsRunningOnLinux() { + boolean isLinux = AppUtil.isRunningOnLinux(); + Assert.assertEquals(System.getProperty("os.name").contains("Linux"), isLinux); + } + + @Test + public void testExec() { + int exitCode = AppUtil.exec(List.of("echo", "Hello, World!"), "Execution failed"); + Assert.assertEquals(0, exitCode); + } + + @Test + public void testSerializeToJson() throws IOException { + Map map = new HashMap<>(); + map.put("key", "value"); + String json = AppUtil.serializeToJson(map); + Assert.assertEquals("{\"key\":\"value\"}", json); + } + + @Test + public void testDeserializeJsonToObject() throws IOException { + String json = "{\"key\":\"value\"}"; + Map map = AppUtil.deserializeJsonToObject(new ByteArrayInputStream(json.getBytes()), Map.class); + Assert.assertEquals("value", map.get("key")); + } + } diff --git a/src/test/java/com/salesforce/dataloader/util/DateOnlyCalendarTest.java b/src/test/java/com/salesforce/dataloader/util/DateOnlyCalendarTest.java new file mode 100644 index 00000000..84d11bee --- /dev/null +++ b/src/test/java/com/salesforce/dataloader/util/DateOnlyCalendarTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015, salesforce.com, inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.salesforce.dataloader.util; +import static org.junit.Assert.*; +import java.util.Calendar; +import java.util.TimeZone; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +public class DateOnlyCalendarTest { + private DateOnlyCalendar dateOnlyCalendar; + + @Before + public void setUp() { + dateOnlyCalendar = new DateOnlyCalendar(); + } + + @Test + public void testSetTimeInMillisWithDefaultTimeZone() { + long timeInMillis = 1633046400000L; // 2021-10-01 00:00:00 GMT + dateOnlyCalendar.setTimeInMillis(timeInMillis); + // 2021-09-30 17:00:00 PST is transformed to 2021-09-30 00:00:00 PST by DateOnlyCalendar + // which is 1632985200000L + assertEquals(1632985200000L, dateOnlyCalendar.getTimeInMillis()); + } + + @Test + public void testSetTimeInMillisWithCustomTimeZone() { + TimeZone timeZone = TimeZone.getTimeZone("PST"); + DateOnlyCalendar customCalendar = DateOnlyCalendar.getInstance(timeZone); + long timeInMillis = 1633046400000L; // 2021-10-01 00:00:00 GMT, translates to 2021-09-30 17:00:00 PST + customCalendar.setTimeInMillis(timeInMillis); + // 2021-09-30 17:00:00 PST is transformed to 2021-09-30 00:00:00 PST by DateOnlyCalendar + // which is 1632985200000L + assertEquals(1632985200000L, customCalendar.getTimeInMillis()); + } + + @Test + public void testSetTimeInMillisWithNullTimeZone() { + dateOnlyCalendar.setTimeZone(null); + long timeInMillis = 1633046400000L; // 2021-10-01 00:00:00 GMT + dateOnlyCalendar.setTimeInMillis(timeInMillis); + assertEquals(1633046400000L, dateOnlyCalendar.getTimeInMillis()); + } + + @Test + public void testGetInstanceWithGMTTimeZone() { + TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT"); + DateOnlyCalendar gmtCalendar = DateOnlyCalendar.getInstance(gmtTimeZone); + assertEquals(gmtTimeZone, gmtCalendar.getTimeZone()); + } + + @Test + public void testGetInstanceWithCustomTimeZone() { + TimeZone customTimeZone = TimeZone.getTimeZone("PST"); + DateOnlyCalendar customCalendar = DateOnlyCalendar.getInstance(customTimeZone); + assertEquals(customTimeZone, customCalendar.getTimeZone()); + } + + @Test + public void testSetTimeInMillisAdjustForTimeZone() { + TimeZone timeZone = TimeZone.getTimeZone("PST"); + DateOnlyCalendar customCalendar = DateOnlyCalendar.getInstance(timeZone); + long timeInMillis = 1633046400000L; // 2021-10-01 00:00:00 GMT + customCalendar.setTimeInMillis(timeInMillis); + Calendar cal = Calendar.getInstance(timeZone); + cal.setTimeInMillis(timeInMillis); + cal.set(Calendar.HOUR, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + cal.set(Calendar.AM_PM, Calendar.AM); + assertEquals(cal.getTimeInMillis(), customCalendar.getTimeInMillis()); + } +} \ No newline at end of file