/*
* A CCNx library test.
*
* Copyright (C) 2008-2013 Palo Alto Research Center, Inc.
*
* This work is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation.
* This work is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details. You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
package org.ccnx.ccn.test.impl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.SignatureException;
import java.util.List;
import java.util.Random;
import org.ccnx.ccn.config.ConfigurationException;
import org.ccnx.ccn.impl.InterestTable;
import org.ccnx.ccn.impl.support.DataUtils;
import org.ccnx.ccn.impl.support.Log;
import org.ccnx.ccn.protocol.CCNTime;
import org.ccnx.ccn.protocol.ContentName;
import org.ccnx.ccn.protocol.ContentObject;
import org.ccnx.ccn.protocol.Interest;
import org.ccnx.ccn.protocol.KeyLocator;
import org.ccnx.ccn.protocol.MalformedContentNameStringException;
import org.ccnx.ccn.protocol.PublisherID;
import org.ccnx.ccn.protocol.PublisherPublicKeyDigest;
import org.ccnx.ccn.protocol.SignedInfo;
import org.ccnx.ccn.protocol.PublisherID.PublisherType;
import org.ccnx.ccn.test.CCNTestBase;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* Tests InterestTable, the core implementation of interest matching
* and dispatching.
*/
public class InterestTableTest extends CCNTestBase {
static public PublisherID ids[] = new PublisherID[3];
static public PublisherPublicKeyDigest keyids[] = new PublisherPublicKeyDigest[3];
// IDs are parameters that establish test condition so same
// code can be run under different conditions
static public PublisherPublicKeyDigest activeKeyID = null;
static public PublisherID activeID = null;
// removeByMatch controls whether remove operations are tested
// via the removeMatch* (true) or the removeValue* (false) methods
// of the InterestTable. This global parameter permits the conditions
// to be varied for different runs of the same code.
static public boolean removeByMatch = true;
// additionalComponents controls the number of additionalComponents
// to use during the additionalComponents testing
static public Integer additionalComponents = 1;
// prefixCount controls the prefixCount
// to use during the prefixCount testing
static public Integer prefixCount = 1;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
CCNTestBase.setUpBeforeClass();
byte [] publisher = new byte[32];
try {
Random rnd = new Random();
for (int i = 0; i < ids.length; i++) {
rnd.nextBytes(publisher);
// Note that when this was first written, trust matching
// could not handle anything more complicated than a KEY
ids[i] = new PublisherID(publisher, PublisherType.KEY);
keyids[i] = new PublisherPublicKeyDigest(publisher);
}
} catch (Exception ex) {
ex.printStackTrace();
Log.info(Log.FAC_TEST, "Unable To Initialize Test!!!");
fail();
}
}
public static void setID(int i) {
if (i >= 0) {
activeID = ids[i];
activeKeyID = keyids[i];
} else {
activeID = null;
activeKeyID = null;
}
}
@Before
public void setUp() throws Exception {
}
@Test
public void testAdd() throws MalformedContentNameStringException {
Log.info(Log.FAC_TEST, "Starting testAdd");
Interest intA = new Interest("/a/b/c");
Interest intB = new Interest("/a/b/c");
Interest intC = new Interest("/a/b/c/d");
ContentName namA = ContentName.fromNative("/a/b/c");
ContentName namB = ContentName.fromNative("/a/b/c");
ContentName namC = ContentName.fromNative("/a/b/c/d");
InterestTable<Object> interests = new InterestTable<Object>();
interests.add(intA, null);
interests.add(intB, null);
interests.add(intC, null);
interests.add(intA, null);
try {
interests.add((Interest)null, null);
fail();
} catch (NullPointerException ex) {
// good
}
assertEquals(4, interests.size());
assertEquals(2, interests.sizeNames());
InterestTable<Object> names = new InterestTable<Object>();
names.add(namA, null);
names.add(namB, null);
names.add(namC, null);
names.add(namA, null);
try {
names.add((ContentName)null, null);
fail();
} catch (NullPointerException ex) {
// good
}
assertEquals(4, names.size());
assertEquals(2, names.sizeNames());
Log.info(Log.FAC_TEST, "Completed testAdd");
}
private ContentObject getContentObject(ContentName name) throws ConfigurationException, InvalidKeyException, SignatureException, MalformedContentNameStringException {
return getContentObject(name, activeKeyID);
}
/*
* Note: This method appends an automatically generated random element onto the end of the
* input content name
*/
private ContentObject getContentObject(ContentName name, PublisherPublicKeyDigest pub) throws ConfigurationException, InvalidKeyException, SignatureException, MalformedContentNameStringException {
// contents = current date value
CCNTime now = CCNTime.now();
ByteBuffer bb = ByteBuffer.allocate(Long.SIZE/Byte.SIZE);
bb.putLong(now.getTime());
byte[] contents = bb.array();
// security bits
KeyLocator locator = new KeyLocator(ContentName.fromNative("/key/" + DataUtils.printBytes(pub.digest())));
SignedInfo si = new SignedInfo(pub, now, SignedInfo.ContentType.DATA, locator);
// unique name
return new ContentObject(
new ContentName(name, Long.toString(now.getTime())), si, contents, fakeSignature);
}
private ContentObject getContentObject(ContentName name, int value) throws InvalidKeyException, SignatureException, MalformedContentNameStringException, ConfigurationException {
ContentObject cn = getContentObject(name);
return new ContentObject(cn.name(), cn.signedInfo(), new Integer(value).toString().getBytes(), cn.signature());
}
private void match(InterestTable<Integer> table, ContentName name, int v) throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
// Test both methods
assertEquals(v, (null == activeKeyID) ? table.getMatch(name).value().intValue() :
table.getMatch(getContentObject(name, v)).value().intValue());
assertEquals(v, (null == activeKeyID) ? table.getValue(name).intValue() :
table.getValue(getContentObject(name,v)).intValue());
}
private void match(InterestTable<Integer> table, String name, int v) throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
match(table, ContentName.fromNative(name), v);
}
private void removeMatch(InterestTable<Integer> table, ContentName name, int v) throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
if (removeByMatch) {
assertEquals(v, table.removeMatch(getContentObject(name)).value().intValue());
} else {
assertEquals(v, table.removeValue(getContentObject(name)).intValue());
}
}
private void removeMatch(InterestTable<Integer> table, String name, int v) throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
removeMatch(table, ContentName.fromNative(name), v);
}
private void remove(InterestTable<Integer> table, ContentName name, int v) {
if (null == activeKeyID) {
assertEquals(v, table.remove(name, new Integer(v)).value().intValue());
} else {
assertEquals(v, table.remove(new Interest(name, activeID), v).value().intValue());
}
}
private void remove(InterestTable<Integer> table, String name, int v) throws MalformedContentNameStringException {
remove(table, ContentName.fromNative(name), v);
}
private void noRemove(InterestTable<Integer> table, ContentName name, int v) {
if (null == activeKeyID) {
assertNull(table.remove(name, new Integer(v)));
} else {
assertNull(table.remove(new Interest(name, activeID), v));
}
}
private void noRemove(InterestTable<Integer> table, String name, int v) throws MalformedContentNameStringException {
noRemove(table, ContentName.fromNative(name), v);
}
private void noRemoveMatch(InterestTable<Integer> table, ContentName name) throws InvalidKeyException, SignatureException, MalformedContentNameStringException, ConfigurationException {
assertNull(table.removeMatch(getContentObject(name)));
assertNull(table.removeValue(getContentObject(name)));
}
private void noRemoveMatch(InterestTable<Integer> table, String name) throws InvalidKeyException, SignatureException, MalformedContentNameStringException, ConfigurationException {
noRemoveMatch(table, ContentName.fromNative(name));
}
private void noMatch(InterestTable<Integer> table, ContentName name) throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
assertNull((null == activeKeyID) ? table.getMatch(name) :
table.getMatch(getContentObject(name, 0)));
assertNull((null == activeKeyID) ? table.getValue(name) :
table.getValue(getContentObject(name, 0)));
}
private void noMatch(InterestTable<Integer> table, String name) throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
noMatch(table, ContentName.fromNative(name));
}
private void matches(InterestTable<Integer> table, ContentName name, ContentName[] n, int[] v) throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
List<InterestTable.Entry<Integer>> result = (null == activeKeyID) ? table.getMatches(name) :
table.getMatches(getContentObject(name, 0));
assertEquals(v.length, result.size());
for (int i = 0; i < v.length; i++) {
assertEquals(v[i], result.get(i).value().intValue());
assertEquals(n[i], result.get(i).name());
}
List<Integer> values = (null == activeKeyID) ? table.getValues(name) :
table.getValues(getContentObject(name, 0));
assertEquals(v.length, values.size());
for (int i=0; i < v.length; i++) {
assertEquals(v[i], values.get(i).intValue());
}
}
private void matches(InterestTable<Integer> table, String name, String[] n, int[] v) throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
ContentName[] cn = new ContentName[n.length];
for (int i = 0; i < n.length; i++) {
cn[i] = ContentName.fromNative(n[i]);
}
matches(table, ContentName.fromNative(name), cn, v);
}
private void removeMatches(InterestTable<Integer> table, ContentName name, ContentName[] n, int[] v) throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
if (removeByMatch) {
List<InterestTable.Entry<Integer>> result = table.removeMatches(getContentObject(name, 0));
assertEquals(v.length, result.size());
for (int i = 0; i < v.length; i++) {
assertEquals(v[i], result.get(i).value().intValue());
assertEquals(n[i], result.get(i).name());
}
} else {
List<Integer> result = table.removeValues(getContentObject(name, 0));
assertEquals(v.length, result.size());
for (int i = 0; i < v.length; i++) {
assertEquals(v[i], result.get(i).intValue());
}
}
}
private void removeMatches(InterestTable<Integer> table, String name, String[] n, int[] v) throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
ContentName[] cn = new ContentName[n.length];
for (int i = 0; i < n.length; i++) {
cn[i] = ContentName.fromNative(n[i]);
}
removeMatches(table, ContentName.fromNative(name), cn, v);
}
private void addEntry(InterestTable<Integer> table, ContentName name, Integer value) throws MalformedContentNameStringException {
if (null == activeKeyID) {
table.add(name, value);
} else {
table.add(new Interest(name, activeID), value);
}
}
private void addEntry(InterestTable<Integer> table, String name, Integer value) throws MalformedContentNameStringException {
addEntry(table, ContentName.fromNative(name), value);
}
private void sizes(InterestTable<Integer> table, int s, int n) {
assertEquals(s, table.size());
assertEquals(n, table.sizeNames());
assertEquals(s, table.values().size());
}
final String a = "/a";
final String ab = "/a/b";
final String a_bb = "/a/bb";
final String abc = "/a/b/c";
final String abb = "/a/b/b";
final String b = "/b";
final String c = "/c";
final String _aa = "/aa";
final ContentName zero = new ContentName(new byte[]{0x00, 0x02, 0x03, 0x04});
final ContentName one = new ContentName(new byte[]{0x01, 0x02, 0x03, 0x04});
final ContentName onethree = new ContentName(new byte[]{0x01, 0x02, 0x03, 0x04}, new byte[]{0x03});
private InterestTable<Integer> initTable() throws MalformedContentNameStringException {
InterestTable<Integer> table = new InterestTable<Integer>();
addEntry(table, a, new Integer(1));
addEntry(table, ab, new Integer(2));
addEntry(table, c, new Integer(3));
addEntry(table, b, new Integer(4));
addEntry(table, a_bb, new Integer(5));
addEntry(table, _aa, new Integer(6));
addEntry(table, abc, new Integer(7));
addEntry(table, zero, new Integer(8));
addEntry(table, onethree, new Integer(9));
addEntry(table, one, new Integer(10));
addEntry(table, ab, new Integer(45));
sizes(table, 11, 10);
return table;
}
private void runMatchName() throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
InterestTable<Integer> names = initTable();
match(names, a_bb, 5);
match(names, abc, 7);
match(names, ab, 2);
match(names, "/a/b/d", 2);
match(names, "/a/b/c/d", 7);
match(names, abb, 2);
match(names, b, 4);
match(names, c, 3);
match(names, one, 10);
match(names, zero, 8);
match(names, onethree, 9);
match(names, "/a/b/b/a", 2);
match(names, _aa, 6);
matches(names, _aa, new String[] {_aa}, new int[] {6});
matches(names, c, new String[] {c}, new int[] {3});
matches(names, "/a/b/c/d", new String[] {abc, ab, ab, a}, new int[] {7, 2, 45, 1});
matches(names, abc, new String[] {abc, ab, ab, a}, new int[] {7, 2, 45, 1});
matches(names, ab, new String[] {ab, ab, a}, new int[] {2, 45, 1});
matches(names, a, new String[] {a}, new int[] {1});
matches(names, a_bb, new String[] {a_bb, a}, new int[] {5, 1});
matches(names, "/a/b/d", new String[] {ab, ab, a}, new int[] {2, 45, 1});
matches(names, zero, new ContentName[] {zero}, new int[] {8});
matches(names, onethree, new ContentName[] {onethree, one}, new int[] {9, 10});
matches(names, one, new ContentName[] {one}, new int[] {10});
addEntry(names, abb, new Integer(11));
sizes(names, 12, 11);
match(names, abb, 11);
match(names, abc, 7);
match(names, "/a/b/c/d", 7);
matches(names, "/a/b/c/d", new String[] {abc, ab, ab, a}, new int[] {7, 2, 45, 1});
matches(names, "/a/b/b/a", new String[] {abb, ab, ab, a}, new int[] {11, 2, 45, 1});
noMatch(names, "/q");
remove(names, ab, 2);
sizes(names, 11, 11);
matches(names, "/a/b/b/a", new String[] {abb, ab, a}, new int[] {11, 45, 1});
}
@Test
public void testMatchName() throws InvalidKeyException, MalformedContentNameStringException, SignatureException, ConfigurationException {
Log.info(Log.FAC_TEST, "Starting testMatchName");
// First test names matching against names, no ContentObject
setID(-1);
runMatchName();
// Next run ContentObject against names in table
setID(0);
runMatchName();
Log.info(Log.FAC_TEST, "Completed testMatchName");
}
public InterestTable<Integer> initPub() throws MalformedContentNameStringException {
InterestTable<Integer> table = new InterestTable<Integer>();
setID(0);
addEntry(table, a, new Integer(1));
addEntry(table, b, new Integer(2));
addEntry(table, a_bb, new Integer(3));
addEntry(table, abb, new Integer(4));
setID(1);
addEntry(table, ab, new Integer(5));
addEntry(table, abc, new Integer(6));
addEntry(table, _aa, new Integer(7));
setID(2);
addEntry(table, abb, new Integer(8));
sizes(table, 8, 7);
return table;
}
@Test
public void testMatchPub() throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
Log.info(Log.FAC_TEST, "Starting testMatchPub");
InterestTable<Integer> names = initPub();
setID(2);
match(names, abb, 8);
match(names, "/a/b/b/a", 8);
matches(names, "/a/b/b/a", new String[] {abb}, new int[] {8});
noMatch(names, a_bb);
noMatch(names, abc);
match(names, abb, 8);
setID(0);
noMatch(names, _aa);
match(names, "/a/b/b/a", 4);
match(names, abc, 1);
matches(names, abc, new String[] {a}, new int[] {1});
match(names, "/a/b/c/d", 1);
matches(names, "/a/b/b/a", new String[] {abb, a}, new int[] {4, 1});
match(names, abb, 4);
matches(names, abb, new String[] {abb, a}, new int[] {4, 1});
setID(1);
noMatch(names, b);
match(names, abc, 6);
matches(names, abc, new String[] {abc, ab}, new int[] {6, 5});
match(names, "/a/b/b/a", 5);
noMatch(names, a_bb);
setID(-1);
match(names, a, 1);
matches(names, "/a/b/b/a", new String[] {abb, abb, ab, a}, new int[] {4, 8, 5, 1});
Log.info(Log.FAC_TEST, "Completed testMatchPub");
}
@Test
public void testSimpleRemoves() throws InvalidKeyException, MalformedContentNameStringException, SignatureException, ConfigurationException {
Log.info(Log.FAC_TEST, "Starting testSimpleRemoves");
removeByMatch = true;
runSimpleRemoves();
removeByMatch = false;
runSimpleRemoves();
Log.info(Log.FAC_TEST, "Completed testSimpleRemoves");
}
private void runSimpleRemoves() throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
setID(0);
InterestTable<Integer> names = initTable();
noRemoveMatch(names, "/q");
removeMatch(names, a_bb, 5);
sizes(names, 10, 9);
removeMatch(names, a_bb, 1);
sizes(names, 9, 8);
noRemoveMatch(names, a_bb);
removeMatches(names, abc, new String[] {abc, ab, ab}, new int[] {7, 2, 45});
sizes(names, 6, 6);
noRemoveMatch(names, abc);
removeMatch(names, onethree, 9);
removeMatch(names, onethree, 10);
noRemoveMatch(names, onethree);
noRemoveMatch(names, one);
sizes(names, 4, 4);
removeMatch(names, zero, 8);
noRemoveMatch(names, zero);
sizes(names, 3, 3);
removeMatch(names, "/aa/b", 6);
noRemoveMatch(names, "/aa/b");
noRemoveMatch(names, "/aa/c");
sizes(names, 2, 2);
removeMatch(names, "/c/d", 3);
noRemoveMatch(names, "/c");
removeMatch(names, "/b/d/d/a", 4);
noRemoveMatch(names, "/b");
sizes(names, 0, 0);
noRemoveMatch(names, "/a");
sizes(names, 0, 0);
}
@Test
public void testRemovesPub() throws InvalidKeyException, MalformedContentNameStringException, SignatureException, ConfigurationException {
Log.info(Log.FAC_TEST, "Starting testRemovesPub");
removeByMatch = true;
runRemovesPub();
removeByMatch = false;
runRemovesPub();
Log.info(Log.FAC_TEST, "Completed testRemovesPub");
}
private void runRemovesPub() throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
InterestTable<Integer> names = initPub();
setID(2);
removeMatch(names, abb, 8);
noRemoveMatch(names, "/a/b/b/a");
sizes(names, 7, 7);
noMatch(names, a_bb);
noRemoveMatch(names, a_bb);
noMatch(names, abc);
noRemoveMatch(names, abc);
names = initPub();
setID(0);
noMatch(names, _aa);
noRemoveMatch(names, _aa);
removeMatch(names, "/a/b/b/a", 4);
sizes(names, 7, 7);
match(names, abc, 1);
removeMatches(names, abc, new String[] {a}, new int[] {1});
sizes(names, 6, 6);
noMatch(names, "/a/b/c/d");
noRemoveMatch(names, "/a/b/b/a");
noRemove(names, abb, 8); // Can't remove id 0 version
setID(2);
remove(names, abb, 8); // Can remove id 2 version
names = initPub();
setID(1);
noRemoveMatch(names, b);
match(names, abc, 6);
removeMatches(names, abc, new String[] {abc, ab}, new int[] {6, 5});
noRemoveMatch(names, "/a/b/b/a");
sizes(names, 6, 5);
}
private enum InterestType {Next, Last, MaxSuffixComponents, Exclude};
private InterestTable<Integer> initInterest(InterestType type) throws MalformedContentNameStringException {
InterestTable<Integer> table = new InterestTable<Integer>();
addEntry(table, a, type, new Integer(1));
addEntry(table, ab, type, new Integer(2));
addEntry(table, c, type, new Integer(3));
addEntry(table, b, type, new Integer(4));
addEntry(table, a_bb, type, new Integer(5));
addEntry(table, _aa, type, new Integer(6));
addEntry(table, abc, type, new Integer(7));
sizes(table, 7, 7);
return table;
}
private void addEntry(InterestTable<Integer> table, String name, InterestType type, Integer value) throws MalformedContentNameStringException {
Interest i = new Interest(ContentName.fromNative(name));
switch (type) {
case Next:
break;
case Last:
i.childSelector(Interest.CHILD_SELECTOR_RIGHT);
break;
case MaxSuffixComponents:
i.maxSuffixComponents(additionalComponents);
break;
}
table.add(i, value);
}
@Test
public void testMatchNext() throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
Log.info(Log.FAC_TEST, "Starting testMatchNext");
matchNextOrLast(InterestType.Next);
Log.info(Log.FAC_TEST, "Completed testMatchNext");
}
@Test
public void testMatchLast() throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
Log.info(Log.FAC_TEST, "Starting testMatchLast");
matchNextOrLast(InterestType.Last);
Log.info(Log.FAC_TEST, "Completed testMatchLast");
}
public void matchNextOrLast(InterestType type) throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
InterestTable<Integer> names = initInterest(type);
setID(1);
noMatch(names, zero);
match(names, "/a/b/b/a", 2);
matches(names, "/a/b/b/a", new String[] {ab, a}, new int[] {2, 1});
noMatch(names, "/d");
match(names, "/c/c", 3);
}
private void runRemovesNextOrLast(InterestType type) throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
InterestTable<Integer> names = initInterest(type);
noRemoveMatch(names, zero);
removeMatch(names, "/a/b/b/a", 2);
sizes(names, 6, 6);
noRemoveMatch(names, "/d");
removeMatch(names, "/c/c", 3);
}
@Test
public void testRemovesNext() throws InvalidKeyException, MalformedContentNameStringException, SignatureException, ConfigurationException {
Log.info(Log.FAC_TEST, "Starting testRemovesNext");
setID(0);
removeByMatch = true;
runRemovesNextOrLast(InterestType.Next);
removeByMatch = false;
runRemovesNextOrLast(InterestType.Next);
Log.info(Log.FAC_TEST, "Completed testRemovesNext");
}
@Test
public void testRemovesLast() throws InvalidKeyException, MalformedContentNameStringException, SignatureException, ConfigurationException {
Log.info(Log.FAC_TEST, "Starting testRemovesLast");
setID(0);
removeByMatch = true;
runRemovesNextOrLast(InterestType.Last);
removeByMatch = false;
runRemovesNextOrLast(InterestType.Last);
Log.info(Log.FAC_TEST, "Completed testRemovesLast");
}
@Test
public void testLRU() throws MalformedContentNameStringException, InvalidKeyException, SignatureException, ConfigurationException {
Log.info(Log.FAC_TEST, "Starting testLRU");
InterestTable<Integer> table = new InterestTable<Integer>();
table.setCapacity(6);
addEntry(table, a, new Integer(1));
addEntry(table, ab, new Integer(2));
addEntry(table, c, new Integer(3));
addEntry(table, b, new Integer(4));
addEntry(table, a_bb, new Integer(5));
addEntry(table, _aa, new Integer(6));
addEntry(table, ab, new Integer(45));
addEntry(table, abc, new Integer(7));
addEntry(table, zero, new Integer(8));
addEntry(table, onethree, new Integer(9));
addEntry(table, one, new Integer(10));
match(table, abc, 7);
matches(table, ab, new String[] {ab, ab}, new int[] {2, 45});
noMatch(table, a);
Log.info(Log.FAC_TEST, "Completed testLRU");
}
}