/*
* Copyright 2014 LinkedIn Corp.
*
* Licensed 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 azkaban.utils;
import java.io.IOException;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
public class PropsUtilsTest {
@Test
public void testGoodResolveProps() throws IOException {
Props propsGrandParent = new Props();
Props propsParent = new Props(propsGrandParent);
Props props = new Props(propsParent);
// Testing props in general
props.put("letter", "a");
propsParent.put("letter", "b");
propsGrandParent.put("letter", "c");
Assert.assertEquals("a", props.get("letter"));
propsParent.put("my", "name");
propsParent.put("your", "eyes");
propsGrandParent.put("their", "ears");
propsGrandParent.put("your", "hair");
Assert.assertEquals("name", props.get("my"));
Assert.assertEquals("eyes", props.get("your"));
Assert.assertEquals("ears", props.get("their"));
props.put("res1", "${my}");
props.put("res2", "${their} ${letter}");
props.put("res7", "${my} ${res5}");
propsParent.put("res3", "${your} ${their} ${res4}");
propsGrandParent.put("res4", "${letter}");
propsGrandParent.put("res5", "${their}");
propsParent.put("res6", " t ${your} ${your} ${their} ${res5}");
Props resolved = PropsUtils.resolveProps(props);
Assert.assertEquals("name", resolved.get("res1"));
Assert.assertEquals("ears a", resolved.get("res2"));
Assert.assertEquals("eyes ears a", resolved.get("res3"));
Assert.assertEquals("a", resolved.get("res4"));
Assert.assertEquals("ears", resolved.get("res5"));
Assert.assertEquals(" t eyes eyes ears ears", resolved.get("res6"));
Assert.assertEquals("name ears", resolved.get("res7"));
}
@Test
public void testInvalidSyntax() throws Exception {
Props propsGrandParent = new Props();
Props propsParent = new Props(propsGrandParent);
Props props = new Props(propsParent);
propsParent.put("my", "name");
props.put("res1", "$(my)");
Props resolved = PropsUtils.resolveProps(props);
Assert.assertEquals("$(my)", resolved.get("res1"));
}
@Test
public void testExpressionResolution() throws IOException {
Props props =
Props.of("normkey", "normal", "num1", "1", "num2", "2", "num3", "3",
"variablereplaced", "${num1}", "expression1", "$(1+10)",
"expression2", "$(1+10)*2", "expression3",
"$($(${num1} + ${num3})*10)", "expression4",
"$(${num1} + ${expression3})", "expression5",
"$($($(2+3)) + 3) + $(${expression3} + 1)", "expression6",
"$(1 + ${normkey})", "expression7", "$(\"${normkey}\" + 1)",
"expression8", "${expression1}", "expression9", "$((2+3) + 3)");
Props resolved = PropsUtils.resolveProps(props);
Assert.assertEquals("normal", resolved.get("normkey"));
Assert.assertEquals("1", resolved.get("num1"));
Assert.assertEquals("2", resolved.get("num2"));
Assert.assertEquals("3", resolved.get("num3"));
Assert.assertEquals("1", resolved.get("variablereplaced"));
Assert.assertEquals("11", resolved.get("expression1"));
Assert.assertEquals("11*2", resolved.get("expression2"));
Assert.assertEquals("40", resolved.get("expression3"));
Assert.assertEquals("41", resolved.get("expression4"));
Assert.assertEquals("8 + 41", resolved.get("expression5"));
Assert.assertEquals("1", resolved.get("expression6"));
Assert.assertEquals("normal1", resolved.get("expression7"));
Assert.assertEquals("11", resolved.get("expression8"));
Assert.assertEquals("8", resolved.get("expression9"));
}
@Test
public void testMalformedExpressionProps() throws IOException {
// unclosed
Props props = Props.of("key", "$(1+2");
failIfNotException(props);
props = Props.of("key", "$((1+2)");
failIfNotException(props);
// bad variable replacement
props = Props.of("key", "$(${dontexist}+2)");
failIfNotException(props);
// bad expression
props = Props.of("key", "$(2 +)");
failIfNotException(props);
// bad expression
props = Props.of("key", "$(2 + #hello)");
failIfNotException(props);
}
@Test
public void testGetFlattenedProps() throws Exception {
// for empty props empty flattened map is expected to be returned.
Props grandParentProps = new Props();
Assert.assertTrue(grandParentProps.getFlattened().isEmpty());
// single level
grandParentProps.put("test1","value1");
grandParentProps.put("test2","value2");
Map<String,String> set = grandParentProps.getFlattened();
Assert.assertEquals(2,set.size());
Assert.assertEquals("value1", set.get("test1"));
Assert.assertEquals("value2", set.get("test2"));
// multiple levels .
Props parentProps = new Props(grandParentProps);
parentProps.put("test3","value3");
parentProps.put("test4","value4");
set = parentProps.getFlattened();
Assert.assertEquals(4,set.size());
Assert.assertEquals("value3", set.get("test3"));
Assert.assertEquals("value1", set.get("test1"));
// multiple levels with same keys .
Props props = new Props(parentProps);
props.put("test5","value5");
props.put("test1","value1.1");
set = props.getFlattened();
Assert.assertEquals(5,set.size());
Assert.assertEquals("value5", set.get("test5"));
Assert.assertEquals("value1.1", set.get("test1"));
// verify when iterating the elements are sorted by the key value.
Props props2 = new Props();
props2.put("2","2");
props2.put("0","0");
props2.put("1","1");
set = props2.getFlattened();
int index = 0 ;
for (Map.Entry<String, String> item : set.entrySet())
{
Assert.assertEquals(item.getKey(),Integer.toString(index++));
}
}
@Test
public void testCyclesResolveProps() throws IOException {
Props propsGrandParent = new Props();
Props propsParent = new Props(propsGrandParent);
Props props = new Props(propsParent);
// Testing props in general
props.put("a", "${a}");
failIfNotException(props);
props.put("a", "${b}");
props.put("b", "${a}");
failIfNotException(props);
props.clearLocal();
props.put("a", "${b}");
props.put("b", "${c}");
propsParent.put("d", "${a}");
failIfNotException(props);
props.clearLocal();
props.put("a", "testing ${b}");
props.put("b", "${c}");
propsGrandParent.put("c", "${d}");
propsParent.put("d", "${a}");
failIfNotException(props);
props.clearLocal();
props.put("a", "testing ${c} ${b}");
props.put("b", "${c} test");
propsGrandParent.put("c", "${d}");
propsParent.put("d", "${a}");
failIfNotException(props);
}
@Test
public void testGetPropertyDiff() throws IOException {
Props oldProps = new Props();
Props newProps1 = new Props();
oldProps.put("a", "a_value1");
oldProps.put("b", "b_value1");
newProps1.put("b", "b_value2");
String message1 = PropsUtils.getPropertyDiff(oldProps, newProps1);
Assert.assertEquals(message1, "Deleted Properties: [ a, a_value1], \nModified Properties: [ b, b_value1-->b_value2], ");
Props newProps2 = new Props();
newProps2.put("a", "a_value1");
newProps2.put("b", "b_value1");
newProps2.put("c", "c_value1");
String message2 = PropsUtils.getPropertyDiff(oldProps, newProps2);
Assert.assertEquals(message2, "Newly created Properties: [ c, c_value1], \n");
Props newProps3 = new Props();
newProps3.put("b", "b_value1");
newProps3.put("c", "a_value1");
String message3 = PropsUtils.getPropertyDiff(oldProps, newProps3);
Assert.assertEquals(message3, "Newly created Properties: [ c, a_value1], \nDeleted Properties: [ a, a_value1], \n");
}
private void failIfNotException(Props props) {
try {
PropsUtils.resolveProps(props);
Assert.fail();
} catch (UndefinedPropertyException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}