/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.falcon.util;
import org.apache.falcon.entity.store.FeedPathStore;
import org.apache.falcon.entity.v0.feed.LocationType;
import org.apache.falcon.resource.FeedLookupResult;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.Collection;
import java.util.List;
/**
* Tests for Radix Tree.
*/
public class RadixTreeTest {
private RadixTree<String> tree;
private FalconRadixUtils.INodeAlgorithm regexAlgorithm = new FalconRadixUtils.FeedRegexAlgorithm();
@BeforeMethod
public void setUp() {
tree = new RadixTree<String>();
tree.insert("key1", "value1");
tree.insert("key2", "value2");
tree.insert("random", "random");
}
@AfterMethod
public void reset() {
tree = null;
}
@Test
public void testInsertAtRootTest() {
FeedPathStore<String> tree2 = new RadixTree<String>();
tree2.insert("/data/cas/projects/dwh/", "dwh");
Assert.assertEquals(tree2.find("/data/cas/projects/dwh/").size(), 1);
Assert.assertTrue(tree2.find("/data/cas/projects/dwh/").contains("dwh"));
}
@Test
public void testDuplicateKeyInsert() {
tree.insert("duplicatekey", "value1");
tree.insert("duplicatekey", "value2");
Assert.assertEquals(tree.find("duplicatekey").size(), 2);
Assert.assertTrue(tree.find("duplicatekey").contains("value1"));
Assert.assertTrue(tree.find("duplicatekey").contains("value2"));
}
@Test
public void testGetNextCandidate() {
tree.insert("/projects/userplatform/${YEAR}-${MONTH}-${DAY}", "feed1");
tree.insert("/projects/userplatform/another", "feed2");
Collection<String> result = tree.find("/projects/userplatform/another");
Assert.assertTrue(result.contains("feed2"));
result = tree.find("/projects/userplatform/2014-07-07", regexAlgorithm);
Assert.assertTrue(result.contains("feed1"));
}
@Test
public void testNoOverlap() {
tree.insert("water", "No Overlap");
Assert.assertEquals(tree.getSize(), 4);
}
@Test
public void testInputKeySubset() {
tree.insert("rand", "Input Subset");
Assert.assertEquals(tree.getSize(), 4);
}
@Test
public void testInputKeySuperset() {
tree.insert("randomiser", "Input Superset");
Assert.assertEquals(tree.getSize(), 4);
}
@Test
public void testInputKeyPathStyle() {
tree.insert("/data/cas/projects/", "path");
Assert.assertEquals(tree.getSize(), 4);
Assert.assertTrue(tree.find("/data/cas/projects/").contains("path"));
}
// Tests for find String
@Test
public void testSubstringPathFind() {
tree.insert("/data/cas/projects/rtbd/", "rtbd");
tree.insert("/data/cas/projects/dwh/", "dwh");
Assert.assertEquals(tree.getSize(), 5);
Assert.assertTrue(tree.find("/data/cas/projects/rtbd/").contains("rtbd"));
Assert.assertTrue(tree.find("/data/cas/projects/dwh/").contains("dwh"));
Assert.assertNull(tree.find("/data/cas/projects/"));
}
@Test
public void testStringSplitFind() {
tree.insert("rand", "rand");
tree.insert("randomizer", "randomizer");
Assert.assertTrue(tree.find("rand").contains("rand"));
Assert.assertTrue(tree.find("random").contains("random"));
Assert.assertTrue(tree.find("randomizer").contains("randomizer"));
}
//Tests for find using regular expression
@Test
public void testFindUsingRegex() {
tree.insert("/data/cas/${YEAR}/", "rtbd");
Assert.assertTrue(tree.find("/data/cas/2014/", regexAlgorithm).contains("rtbd"));
Assert.assertNull(tree.find("/data/cas/", regexAlgorithm));
Assert.assertNull(tree.find("/data/cas/2014/09", regexAlgorithm));
Assert.assertNull(tree.find("/data/cas/${YEAR}/", regexAlgorithm));
tree.insert("/data/cas/${YEAR}/colo", "local");
tree.insert("/data/cas/${YEAR}/colo", "duplicate-local");
Assert.assertNull(tree.find("/data/cas/${YEAR}/", regexAlgorithm));
Assert.assertNull(tree.find("/data/cas/${YEAR}/colo", regexAlgorithm));
Assert.assertNull(tree.find("/data/cas/", regexAlgorithm));
Assert.assertTrue(tree.find("/data/cas/2014/", regexAlgorithm).contains("rtbd"));
Assert.assertTrue(tree.find("/data/cas/2014/colo", regexAlgorithm).contains("local"));
Assert.assertTrue(tree.find("/data/cas/2014/colo", regexAlgorithm).contains("duplicate-local"));
}
// Tests for delete method
@Test
public void testDeleteChildOfTerminal() {
tree.insert("rand", "rand");
tree.insert("randomizer", "randomizer");
Assert.assertTrue(tree.delete("randomizer", "randomizer"));
Assert.assertNull(tree.find("randomizer"));
Assert.assertTrue(tree.find("random").contains("random"));
}
@Test
public void testMarkingNonTerminal() {
tree.insert("rand", "rand");
tree.insert("randomizer", "randomizer");
tree.delete("rand", "rand");
Assert.assertNull(tree.find("rand"));
Assert.assertTrue(tree.find("random").contains("random"));
Assert.assertTrue(tree.find("randomizer").contains("randomizer"));
}
@Test
public void testDoubleDelete() {
tree.insert("rand", "rand");
tree.insert("randomizer", "randomizer");
Assert.assertTrue(tree.delete("rand", "rand"));
Assert.assertFalse(tree.delete("rand", "rand"));
Assert.assertNull(tree.find("rand"));
Assert.assertTrue(tree.find("random").contains("random"));
Assert.assertTrue(tree.find("randomizer").contains("randomizer"));
}
@Test
public void testChildCompactionDelete() {
tree.insert("rand", "rand");
tree.insert("randomizer", "randomizer");
Assert.assertTrue(tree.delete("random", "random"));
Assert.assertNull(tree.find("random"));
Assert.assertTrue(tree.find("rand").contains("rand"));
Assert.assertTrue(tree.find("randomizer").contains("randomizer"));
Assert.assertEquals(tree.getSize(), 4);
}
@Test
public void testParentCompactionDelete() {
tree.insert("rand", "rand");
tree.insert("randomizer", "randomizer");
Assert.assertTrue(tree.delete("randomizer", "randomizer"));
Assert.assertNull(tree.find("randomizer"));
Assert.assertTrue(tree.find("rand").contains("rand"));
Assert.assertTrue(tree.find("random").contains("random"));
Assert.assertEquals(tree.getSize(), 4);
}
@Test
public void testSequencesOfDelete() {
tree.insert("rand", "rand");
tree.insert("randomizer", "randomizer");
Assert.assertTrue(tree.delete("randomizer", "randomizer"));
Assert.assertNull(tree.find("randomizer"));
Assert.assertTrue(tree.find("rand").contains("rand"));
Assert.assertTrue(tree.find("random").contains("random"));
Assert.assertEquals(tree.getSize(), 4);
Assert.assertTrue(tree.delete("rand", "rand"));
Assert.assertNull(tree.find("rand"));
Assert.assertTrue(tree.find("random").contains("random"));
Assert.assertEquals(tree.getSize(), 3);
Assert.assertTrue(tree.delete("random", "random"));
Assert.assertNull(tree.find("random"));
Assert.assertEquals(tree.getSize(), 2);
}
@Test
public void testRootNotCompactedInDelete() {
Assert.assertTrue(tree.delete("random", "random"));
Assert.assertTrue(tree.delete("key2", "value2"));
tree.insert("water", "water");
Assert.assertTrue(tree.find("water").contains("water"));
}
@Test
public void testDeleteFromListAndChildren() {
//check that a delete of a key with multiple values and children is handled
tree.insert("keyWithManyValuesAndChild", "value1");
tree.insert("keyWithManyValuesAndChild", "value2");
tree.insert("keyWithManyValuesAndChildren", "childValue");
Assert.assertTrue(tree.delete("keyWithManyValuesAndChild", "value1"));
}
@Test
public void testDeleteNonExistent() {
Assert.assertFalse(tree.delete("zzz", "zzz"));
}
@Test
public void testDeleteSubstring() {
Assert.assertFalse(tree.delete("ke", "ke"));
}
@Test
public void testDeleteNonTerminal() {
Assert.assertFalse(tree.delete("key", "key"));
}
@Test
public void testDeleteBlankOrEmptyOrNullString(){
Assert.assertFalse(tree.delete("", ""));
Assert.assertFalse(tree.delete(" ", " "));
Assert.assertFalse(tree.delete(null, null));
}
@Test
public void testAllSuffixForFirstLevelKey() {
tree.insert("key123", "Key was key123");
tree.insert("key124", "Key was key124");
List<String> result = tree.findSuffixChildren("key", 2);
Assert.assertEquals(result.size(), 2);
Assert.assertTrue(result.contains("1"));
Assert.assertTrue(result.contains("2"));
}
@Test
public void testAllSuffixForNestedLevelKey() {
tree.insert("key123", "Key was key123");
tree.insert("key124", "Key was key124");
Assert.assertEquals(tree.findSuffixChildren("key1", 2).size(), 1);
Assert.assertEquals(tree.findSuffixChildren("key1", 2).get(0), "2");
}
@Test
public void testFeedPropertiesEquals() {
FeedLookupResult.FeedProperties f1 = new FeedLookupResult.FeedProperties("feed",
LocationType.DATA, "cluster");
FeedLookupResult.FeedProperties f1Copy = new FeedLookupResult.FeedProperties("feed",
LocationType.DATA, "cluster");
FeedLookupResult.FeedProperties f3 = new FeedLookupResult.FeedProperties("anotherFeed",
LocationType.DATA, "cluster");
FeedLookupResult.FeedProperties f4 = new FeedLookupResult.FeedProperties("feed",
LocationType.STATS, "cluster");
FeedLookupResult.FeedProperties f5 = new FeedLookupResult.FeedProperties("feed",
LocationType.DATA, "anotherCluster");
Assert.assertTrue(f1.equals(f1Copy));
Assert.assertFalse(f1.equals(f3));
Assert.assertFalse(f1.equals(f4));
Assert.assertFalse(f1.equals(f5));
}
@Test
public void testMultipleValues(){
tree.insert("keyWithMultipleValues", "value1");
tree.insert("keyWithMultipleValues", "value2");
Assert.assertEquals(tree.find("keyWithMultipleValues").size(), 2);
Assert.assertTrue(tree.find("keyWithMultipleValues").contains("value1"));
Assert.assertTrue(tree.find("keyWithMultipleValues").contains("value2"));
tree.delete("keyWithMultipleValues", "value1");
Assert.assertTrue(tree.find("keyWithMultipleValues").contains("value2"));
Assert.assertFalse(tree.find("keyWithMultipleValues").contains("value1"));
tree.delete("keyWithMultipleValues", "value2");
Assert.assertNull(tree.find("keyWithMultipleValues"));
}
}