/*
* JBoss, Home of Professional Open Source
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @authors tag. All rights reserved.
*/
package org.searchisko.api.util;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import javax.ws.rs.core.MultivaluedMap;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.elasticsearch.common.joda.time.LocalDateTime;
import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.searchisko.api.testtools.TestUtils;
/**
* Unit test for {@link SearchUtils}.
*
* @author Vlastimil Elias (velias at redhat dot com)
* @author Lukas Vlcek
*/
public class SearchUtilsTest {
@Test
public void dateFromISOString() throws ParseException {
Assert.assertNull(SearchUtils.dateFromISOString(null, false));
Assert.assertNull(SearchUtils.dateFromISOString(null, true));
try {
Assert.assertNull(SearchUtils.dateFromISOString("", false));
Assert.fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
// OK
}
Assert.assertNull(SearchUtils.dateFromISOString("", true));
try {
Assert.assertNull(SearchUtils.dateFromISOString("badvalue", false));
Assert.fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
// OK
}
// case - silent mode test
Assert.assertNull(SearchUtils.dateFromISOString("badvalue", true));
Assert.assertEquals(1361386810123l, SearchUtils.dateFromISOString("2013-02-20T20:00:10.123+0100", false).getTime());
Assert.assertEquals(1361386810123l, SearchUtils.dateFromISOString("2013-02-20T20:00:10.123+01", false).getTime());
Assert
.assertEquals(1361386810123l, SearchUtils.dateFromISOString("2013-02-20T20:00:10.123+01:00", false).getTime());
Assert.assertEquals(1361390410123l, SearchUtils.dateFromISOString("2013-02-20T20:00:10.123Z", false).getTime());
}
@Test
public void getISODateFormat() throws ParseException {
DateFormat df = SearchUtils.getISODateFormat();
// Previous date format initialized with yyyy-MM-dd'T'HH:mm:ss.SSSZ for comparison.
SimpleDateFormat previousdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
previousdf.setTimeZone(TimeZone.getTimeZone("GMT"));
previousdf.setLenient(false);
// This date format will work correctly for both formatters
Assert.assertEquals( 1361386810123l , df.parse("2013-02-20T20:00:10.123+0100").getTime() );
Assert.assertEquals( 1361386810123l , previousdf.parse("2013-02-20T20:00:10.123+0100").getTime() );
// However this one with Z will work without an exception only with the new format.
Assert.assertEquals( 1361390410123l , df.parse("2013-02-20T20:00:10.123Z").getTime() );
// The following set of commands is expected to throw ParseException
// The previous format won't parse date which timezone of +0000 difference is shortened to Z
try {
previousdf.parse("2013-02-20T20:00:10.123Z").getTime();
Assert.fail();
} catch (ParseException e) {
// If the exception is being thrown it means that we correctly expected the old format to fail.
}
// Giving it a totally bad value to both formatters will correctly result in ParseException.
try {
df.parse("badvalue");
Assert.fail();
} catch (ParseException e) {
// It's all good, it should fail on such value.
}
try {
previousdf.parse("badvalue");
Assert.fail();
} catch (ParseException e) {
// It's all good, it shoudl fail on such value.
}
}
@Test
public void isDateBefore() {
Assert.assertTrue(SearchUtils.isDateAfter(new Date(), 1));
Assert
.assertFalse(SearchUtils.isDateAfter(SearchUtils.dateFromISOString("2013-02-20T20:00:10.123+0100", false), 10));
Assert
.assertTrue(SearchUtils.isDateAfter(SearchUtils.dateFromISOString("2100-02-20T20:00:10.123+0100", false), 10));
LocalDateTime now = new LocalDateTime();
Assert.assertTrue(SearchUtils.isDateAfter(now.minusMinutes(9).toDate(), 10));
}
@Test
public void trimToNull() {
Assert.assertNull(SearchUtils.trimToNull(null));
Assert.assertNull(SearchUtils.trimToNull(""));
Assert.assertNull(SearchUtils.trimToNull(" "));
Assert.assertNull(SearchUtils.trimToNull(" \t "));
Assert.assertEquals("a", SearchUtils.trimToNull("a"));
Assert.assertEquals("a", SearchUtils.trimToNull("a "));
Assert.assertEquals("a", SearchUtils.trimToNull(" a"));
Assert.assertEquals("abcd aaa", SearchUtils.trimToNull(" abcd aaa \t "));
}
@Test
public void isBlank_String() {
Assert.assertTrue(SearchUtils.isBlank((String) null));
Assert.assertTrue(SearchUtils.isBlank(""));
Assert.assertTrue(SearchUtils.isBlank(" "));
Assert.assertTrue(SearchUtils.isBlank(" "));
Assert.assertTrue(SearchUtils.isBlank(" \t"));
Assert.assertFalse(SearchUtils.isBlank("a"));
Assert.assertFalse(SearchUtils.isBlank("Z"));
Assert.assertFalse(SearchUtils.isBlank("1"));
Assert.assertFalse(SearchUtils.isBlank("-"));
}
@Test
public void isBlank_Object() {
Assert.assertTrue(SearchUtils.isBlank((Object) null));
Assert.assertFalse(SearchUtils.isBlank(new Object()));
// String handling
Assert.assertTrue(SearchUtils.isBlank((Object) ""));
Assert.assertTrue(SearchUtils.isBlank((Object) " "));
Assert.assertTrue(SearchUtils.isBlank((Object) " "));
Assert.assertTrue(SearchUtils.isBlank((Object) " \t"));
Assert.assertFalse(SearchUtils.isBlank((Object) "a"));
Assert.assertFalse(SearchUtils.isBlank((Object) "Z"));
Assert.assertFalse(SearchUtils.isBlank((Object) "1"));
Assert.assertFalse(SearchUtils.isBlank((Object) "-"));
// Collections handling
{
List<String> l = new ArrayList<>();
Assert.assertTrue(SearchUtils.isBlank(l));
l.add("a");
Assert.assertFalse(SearchUtils.isBlank(l));
}
{
Map<String, String> l = new HashMap<>();
Assert.assertTrue(SearchUtils.isBlank(l));
l.put("a", "b");
Assert.assertFalse(SearchUtils.isBlank(l));
}
}
@Test
public void convertJsonMapToString() throws IOException {
{
Assert.assertEquals("", SearchUtils.convertJsonMapToString(null));
}
Map<String, Object> data = new HashMap<String, Object>();
{
TestUtils.assertJsonContent("{}", SearchUtils.convertJsonMapToString(data));
}
// case - conversion of distinct basic data types
{
Map<String, Object> sysTitleConfig = new HashMap<String, Object>();
sysTitleConfig.put("fragment_size", "-1");
sysTitleConfig.put("number_of_fragments", "0");
sysTitleConfig.put("fragment_offset", 0);
sysTitleConfig.put("fragment_offset_long", new Long(25l));
sysTitleConfig.put("boolean", true);
sysTitleConfig.put("boolean2", false);
sysTitleConfig.put("date", new Date(65132498465l));
data.put("sys_title", sysTitleConfig);
TestUtils.assertJsonContent("{\"sys_title\":{" + "\"fragment_size\":\"-1\"," + "\"number_of_fragments\":\"0\","
+ "\"fragment_offset\":0," + "\"fragment_offset_long\":25," + "\"boolean\":true," + "\"boolean2\":false,"
+ "\"date\":\"1972-01-24T20:21:38.465Z\"" + "}}", SearchUtils.convertJsonMapToString(data));
}
// case - conversion of List data type
Map<String, Object> map = new HashMap<String, Object>();
List<String> l = new ArrayList<String>();
l.add("aaa");
l.add("bbb");
map.put("l", l);
TestUtils.assertJsonContent("{\"l\":[\"aaa\",\"bbb\"]}", SearchUtils.convertJsonMapToString(map));
}
@SuppressWarnings("unchecked")
@Test
public void convertToJsonMap() throws JsonParseException, JsonMappingException, IOException {
Assert.assertNull(SearchUtils.convertToJsonMap(null));
try {
SearchUtils.convertToJsonMap("");
Assert.fail("IOException expected");
} catch (IOException e) {
// OK
}
try {
SearchUtils.convertToJsonMap("sdfqwrewr");
Assert.fail("JsonParseException expected");
} catch (JsonParseException e) {
// OK
}
try {
SearchUtils.convertToJsonMap("{aers");
Assert.fail("JsonParseException expected");
} catch (JsonParseException e) {
// OK
}
try {
SearchUtils.convertToJsonMap("{ \"dsdsd\": true,}");
Assert.fail("JsonParseException expected");
} catch (JsonParseException e) {
// OK
}
// case - basic data types
{
Map<String, Object> m = SearchUtils
.convertToJsonMap("{ \"test\": true, \"int\":10, \"str\":\"string\", \"datestring\":\"1972-01-24T20:21:38.465+0000\"}");
Assert.assertEquals(4, m.size());
Assert.assertEquals(true, m.get("test"));
Assert.assertEquals(10, m.get("int"));
Assert.assertEquals("string", m.get("str"));
Assert.assertEquals("1972-01-24T20:21:38.465+0000", m.get("datestring"));
}
// case - array JSON type to List java type
{
Map<String, Object> m = SearchUtils
.convertToJsonMap("{ \"test\": [true, 10, \"string\", \"1972-01-24T20:21:38.465+0000\"]}");
Assert.assertEquals(1, m.size());
List<Object> l = (List<Object>) m.get("test");
Assert.assertEquals(true, l.get(0));
Assert.assertEquals(10, l.get(1));
Assert.assertEquals("string", l.get(2));
Assert.assertEquals("1972-01-24T20:21:38.465+0000", l.get(3));
}
}
private static final String KEY = "key";
@Test
public void getIntegerFromJsonMap() {
Assert.assertNull(SearchUtils.getIntegerFromJsonMap(null, KEY));
Map<String, Object> m = new HashMap<>();
Assert.assertNull(SearchUtils.getIntegerFromJsonMap(m, KEY));
m.put(KEY, new Integer(10));
Assert.assertEquals(new Integer(10), SearchUtils.getIntegerFromJsonMap(m, KEY));
m.put(KEY, new Long(12));
Assert.assertEquals(new Integer(12), SearchUtils.getIntegerFromJsonMap(m, KEY));
m.put(KEY, new Float(15));
Assert.assertEquals(new Integer(15), SearchUtils.getIntegerFromJsonMap(m, KEY));
m.put(KEY, "20");
Assert.assertEquals(new Integer(20), SearchUtils.getIntegerFromJsonMap(m, KEY));
m.put(KEY, "-20");
Assert.assertEquals(new Integer(-20), SearchUtils.getIntegerFromJsonMap(m, KEY));
m.put(KEY, "a");
try {
SearchUtils.getIntegerFromJsonMap(m, KEY);
Assert.fail("NumberFormatException must be thrown");
} catch (NumberFormatException e) {
// OK
}
m.put(KEY, new Object());
try {
SearchUtils.getIntegerFromJsonMap(m, KEY);
Assert.fail("NumberFormatException must be thrown");
} catch (NumberFormatException e) {
// OK
}
}
@SuppressWarnings("rawtypes")
@Test
public void mergeJsonMaps_basic() {
// case - call is null safe and do not modify nothing in this case
{
Map<String, Object> source = new HashMap<>();
source.put("ks", "vs");
Map<String, Object> target = new HashMap<>();
target.put("kt", "vt");
SearchUtils.mergeJsonMaps(source, null);
SearchUtils.mergeJsonMaps(null, target);
Assert.assertEquals(1, source.size());
Assert.assertEquals(1, target.size());
}
// case - simple value, same key in source and target so list is created for different values but not for same
{
Map<String, Object> source = new HashMap<>();
Map<String, Object> target = new HashMap<>();
// create List for these two values for same key
source.put("key1", "v1");
target.put("key1", "v2");
// common merge of distinct keys
source.put("key2", "v22");
target.put("key3", "v33");
source.put("key4", "v44");
target.put("key5", "v55");
// do not create List for these two values for same key as they are same
source.put("key6", "v1");
target.put("key6", "v1");
SearchUtils.mergeJsonMaps(source, target);
Assert.assertEquals(6, target.size());
Assert.assertTrue(target.get("key1") instanceof List);
List l = (List) target.get("key1");
Assert.assertTrue(l.contains("v1"));
Assert.assertTrue(l.contains("v2"));
Assert.assertEquals("v22", target.get("key2"));
Assert.assertEquals("v33", target.get("key3"));
Assert.assertEquals("v44", target.get("key4"));
Assert.assertEquals("v55", target.get("key5"));
Assert.assertEquals("v1", target.get("key6"));
}
}
@SuppressWarnings("rawtypes")
@Test
public void mergeJsonMaps_Lists() {
// case - simple value in source, List in target - must be merged
{
Map<String, Object> source = new HashMap<>();
Map<String, Object> target = new HashMap<>();
source.put("key1", "v1");
target.put("key1", TestUtils.createListOfStrings("v2", "v3"));
SearchUtils.mergeJsonMaps(source, target);
Assert.assertTrue(target.get("key1") instanceof List);
List tl = (List) target.get("key1");
Assert.assertEquals(3, tl.size());
Assert.assertTrue(tl.contains("v1"));
Assert.assertTrue(tl.contains("v2"));
Assert.assertTrue(tl.contains("v3"));
}
// case - simple value in source duplicate to value in List in target - must be merged without duplication
{
Map<String, Object> source = new HashMap<>();
Map<String, Object> target = new HashMap<>();
source.put("key1", "v1");
target.put("key1", TestUtils.createListOfStrings("v1", "v3"));
SearchUtils.mergeJsonMaps(source, target);
Assert.assertTrue(target.get("key1") instanceof List);
List tl = (List) target.get("key1");
Assert.assertEquals(2, tl.size());
Assert.assertTrue(tl.contains("v1"));
Assert.assertTrue(tl.contains("v3"));
}
// case - map in source, List in target - must be merged
{
Map<String, Object> source = new HashMap<>();
Map<String, Object> target = new HashMap<>();
Map sourceMap = new HashMap<>();
source.put("key1", sourceMap);
target.put("key1", TestUtils.createListOfStrings("v1", "v3"));
SearchUtils.mergeJsonMaps(source, target);
Assert.assertTrue(target.get("key1") instanceof List);
List tl = (List) target.get("key1");
Assert.assertEquals(3, tl.size());
Assert.assertTrue(tl.contains("v1"));
Assert.assertTrue(tl.contains("v3"));
Assert.assertTrue(tl.contains(sourceMap));
}
// case - List in source (with simple values and Map) with duplicates to values in List in target - must be merged
// without duplication.
{
Map<String, Object> source = new HashMap<>();
Map<String, Object> target = new HashMap<>();
List<Object> sourceList = new ArrayList<>();
sourceList.add("v1");
sourceList.add("v2");
Map mapValue = new HashMap<>();
sourceList.add(mapValue);
source.put("key1", sourceList);
target.put("key1", TestUtils.createListOfStrings("v1", "v3"));
SearchUtils.mergeJsonMaps(source, target);
Assert.assertTrue(target.get("key1") instanceof List);
List tl = (List) target.get("key1");
Assert.assertEquals(4, tl.size());
Assert.assertTrue(tl.contains("v1"));
Assert.assertTrue(tl.contains("v2"));
Assert.assertTrue(tl.contains("v3"));
Assert.assertTrue(tl.contains(mapValue));
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void mergeJsonMaps_Maps() {
// case - simple value in source, Map in target - source is ignored
{
Map<String, Object> source = new HashMap<>();
Map<String, Object> target = new HashMap<>();
source.put("key1", "v1");
Map targetMap = new HashMap<>();
targetMap.put("tk1", "tv1");
target.put("key1", targetMap);
SearchUtils.mergeJsonMaps(source, target);
Assert.assertTrue(target.get("key1") instanceof Map);
Map tl = (Map) target.get("key1");
Assert.assertEquals(1, tl.size());
Assert.assertEquals("tv1", tl.get("tk1"));
}
// case - List value in source, Map in target - source is ignored
{
Map<String, Object> source = new HashMap<>();
Map<String, Object> target = new HashMap<>();
source.put("key1", TestUtils.createListOfStrings("v1"));
Map targetMap = new HashMap<>();
targetMap.put("tk1", "tv1");
target.put("key1", targetMap);
SearchUtils.mergeJsonMaps(source, target);
Assert.assertTrue(target.get("key1") instanceof Map);
Map tl = (Map) target.get("key1");
Assert.assertEquals(1, tl.size());
Assert.assertEquals("tv1", tl.get("tk1"));
}
// case - Map in source and target - must be merged
{
Map<String, Object> source = new HashMap<>();
Map sourceMap = new HashMap<>();
sourceMap.put("sk1", "sv1");
sourceMap.put("k1", "v1");
source.put("key1", sourceMap);
Map<String, Object> target = new HashMap<>();
Map targetMap = new HashMap<>();
targetMap.put("tk1", "tv1");
targetMap.put("k1", "v2");
target.put("key1", targetMap);
SearchUtils.mergeJsonMaps(source, target);
Assert.assertTrue(target.get("key1") instanceof Map);
Map tl = (Map) target.get("key1");
Assert.assertEquals(3, tl.size());
Assert.assertEquals("tv1", tl.get("tk1"));
Assert.assertEquals("sv1", tl.get("sk1"));
Assert.assertTrue(tl.get("k1") instanceof List);
Assert.assertEquals(2, ((List) tl.get("k1")).size());
}
}
@Test
public void collapseURLParams() {
{
MultivaluedMap<String, String> map = new MultivaluedMapImpl<>();
Map<String, Object> collapsedMap = SearchUtils.collapseURLParams(map);
Assert.assertTrue(collapsedMap.isEmpty());
}
{
MultivaluedMap<String, String> map = new MultivaluedMapImpl<>();
map.put(null, null);
Map<String, Object> collapsedMap = SearchUtils.collapseURLParams(map);
Assert.assertTrue(collapsedMap.isEmpty());
}
{
MultivaluedMap<String, String> map = new MultivaluedMapImpl<>();
map.put("key1", null);
Map<String, Object> collapsedMap = SearchUtils.collapseURLParams(map);
Assert.assertTrue(collapsedMap.isEmpty());
}
// test multiple key values
{
List<String> values = new ArrayList<>();
values.add("value1");
values.add("value2");
values.add("value3");
MultivaluedMap<String, String> map = new MultivaluedMapImpl<>();
map.put("key1", values);
Map<String, Object> collapsedMap = SearchUtils.collapseURLParams(map);
Assert.assertFalse(collapsedMap.isEmpty());
Assert.assertEquals(1, collapsedMap.keySet().size());
Assert.assertTrue(collapsedMap.containsKey("key1"));
// Elasticsearch assumes the Object is either String or an Array
Assert.assertTrue(collapsedMap.get("key1") instanceof Object[]);
Assert.assertArrayEquals(values.toArray(), (Object[]) collapsedMap.get("key1"));
}
// test multiple key values "corner case"
{
List<String> values = new ArrayList<>();
values.add(null);
values.add(null);
values.add(null);
MultivaluedMap<String, String> map = new MultivaluedMapImpl<>();
map.put("key1", values);
Map<String, Object> collapsedMap = SearchUtils.collapseURLParams(map);
Assert.assertFalse(collapsedMap.isEmpty());
Assert.assertEquals(1, collapsedMap.keySet().size());
Assert.assertTrue(collapsedMap.containsKey("key1"));
// Elasticsearch assumes the Object is either String or an Array
Assert.assertTrue(collapsedMap.get("key1") instanceof Object[]);
Assert.assertArrayEquals(values.toArray(), (Object[]) collapsedMap.get("key1"));
}
// test single key value
{
List<String> values = new ArrayList<>();
values.add("value1");
MultivaluedMap<String, String> map = new MultivaluedMapImpl<>();
map.put("key1", values);
Map<String, Object> collapsedMap = SearchUtils.collapseURLParams(map);
Assert.assertFalse(collapsedMap.isEmpty());
Assert.assertEquals(1, collapsedMap.keySet().size());
Assert.assertTrue(collapsedMap.containsKey("key1"));
// Elasticsearch assumes the Object is either String or an Array
Assert.assertTrue(collapsedMap.get("key1") instanceof String);
Assert.assertEquals(values.get(0), collapsedMap.get("key1"));
}
}
}