package net.windwards.dnsfrontend.frontend;
import junit.framework.Assert;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.windwards.dnsfrontend.api.AbstractTaskKeeper;
import net.windwards.dnsfrontend.api.Backend;
import net.windwards.dnsfrontend.api.BackendRepository;
import net.windwards.dnsfrontend.api.NoSuchDomainException;
import net.windwards.dnsfrontend.util.TestingBackend;
import net.windwards.dnsfrontend.util.TestUtils;
import org.junit.Test;
import org.xbill.DNS.AAAARecord;
import org.xbill.DNS.ARecord;
import org.xbill.DNS.DClass;
import org.xbill.DNS.Flags;
import org.xbill.DNS.Message;
import org.xbill.DNS.Name;
import org.xbill.DNS.Rcode;
import org.xbill.DNS.Record;
import org.xbill.DNS.Section;
import org.xbill.DNS.Type;
import org.xbill.DNS.Update;
import java.net.InetAddress;
import java.util.LinkedList;
import java.util.List;
public class TestResolveTask {
/* Resolution logic testing */
@Test
public void cacheHit() throws Exception {
final List<Message> replies = new LinkedList<Message>();
final Ehcache cache = TestUtils.getEhcache();
Query query = TestUtils.getQuery(replies);
Record reply = TestUtils.getReplyRecord();
Element lmnt = new Element("A:" + reply.getName().toString(), reply);
cache.put(lmnt);
ResolveTask task = new ResolveTask(query);
task.setCache(cache);
final LinkedList<Record> notified = new LinkedList<Record>();
task.setBackendStore(new BackendRepository() {
@Override
public Backend lookup(int type) {
return new TestingBackend(notified);
}
@Override public void stop() {}
});
Assert.assertEquals(0, replies.size());
task.run();
Assert.assertEquals(1, replies.size());
Assert.assertEquals(0, notified.size());
Message result = replies.get(0);
ARecord arec = (ARecord) result.getSectionArray(Section.ANSWER)[0];
Assert.assertEquals("127.0.0.1", arec.getAddress().getHostAddress());
}
@Test
public void cacheMiss() throws Exception {
final List<Message> replies = new LinkedList<Message>();
final Ehcache cache = TestUtils.getEhcache();
Query query = TestUtils.getQuery(replies);
final List<ResolveTask> parked = new LinkedList<ResolveTask>();
AbstractTaskKeeper zone = new AbstractTaskKeeper() {
@Override public void start() { }
@Override public void stop() { }
@Override public void keep(ResolveTask task) { parked.add(task); }
@Override public void replyArrived(Ehcache cache, Element lmnt) { }
@Override public void discard(ResolveTask task) { }
};
ResolveTask task = new ResolveTask(query);
task.setCache(cache);
task.setStagingZone(zone);
final List<Record> pushed = new LinkedList<Record>();
task.setBackendStore(new BackendRepository() {
@Override
public Backend lookup(int type) {
return new TestingBackend(pushed);
}
@Override public void stop() {}
});
Assert.assertEquals(0, replies.size() + pushed.size() + parked.size());
task.run();
Assert.assertEquals(1, pushed.size());
Assert.assertEquals(1, parked.size());
Assert.assertEquals(0, replies.size());
task.answer(TestUtils.getReplyRecord(), true);
Message result = replies.get(0);
Assert.assertTrue(result.getHeader().getFlag(Flags.AA));
ARecord arec = (ARecord) result.getSectionArray(Section.ANSWER)[0];
Assert.assertEquals("127.0.0.1", arec.getAddress().getHostAddress());
}
@Test
public void unknownDomain() throws Exception {
final List<Message> replies = new LinkedList<Message>();
final Ehcache cache = TestUtils.getEhcache();
Query query = TestUtils.getQuery(replies);
final List<ResolveTask> parked = new LinkedList<ResolveTask>();
AbstractTaskKeeper zone = new AbstractTaskKeeper() {
@Override public void start() { }
@Override public void stop() { }
@Override public void keep(ResolveTask task) { parked.add(task); }
@Override public void replyArrived(Ehcache cache, Element lmnt) { }
@Override public void discard(ResolveTask task) { parked.remove(task); }
};
ResolveTask task = new ResolveTask(query);
task.setCache(cache);
task.setStagingZone(zone);
task.setBackendStore(new BackendRepository() {
@Override
public Backend lookup(int type) {
return new TestingBackend(new LinkedList<Record>()) {
@Override
public void notify(Record query) throws NoSuchDomainException {
throw new NoSuchDomainException("BOOM");
}
};
}
@Override public void stop() {}
});
Assert.assertEquals(0, replies.size());
task.run();
Assert.assertEquals(0, parked.size());
Message result = replies.get(0);
Assert.assertFalse(result.getHeader().getFlag(Flags.AA));
Assert.assertEquals(Rcode.NXDOMAIN, result.getRcode());
}
@Test
public void timeoutQuery() throws Exception {
final List<Message> replies = new LinkedList<Message>();
final Ehcache cache = TestUtils.getEhcache();
Query query = TestUtils.getQuery(replies);
final List<ResolveTask> parked = new LinkedList<ResolveTask>();
AbstractTaskKeeper zone = new AbstractTaskKeeper() {
@Override public void start() { }
@Override public void stop() { }
@Override public void keep(ResolveTask task) { parked.add(task); }
@Override public void replyArrived(Ehcache cache, Element lmnt) { }
@Override public void discard(ResolveTask task) { }
};
ResolveTask task = new ResolveTask(query);
task.setCache(cache);
task.setStagingZone(zone);
task.setBackendStore(new BackendRepository() {
@Override
public Backend lookup(int type) {
return new TestingBackend(new LinkedList<Record>());
}
@Override public void stop() {}
});
task.run();
task.timeout();
Message result = replies.get(0);
Assert.assertTrue(result.getHeader().getFlag(Flags.AA));
Assert.assertEquals(Rcode.NXDOMAIN, result.getRcode());
}
@Test
public void refuseUnimplementedQueryType() throws Exception {
final List<Message> replies = new LinkedList<Message>();
Message message = Message.newQuery(Record.newRecord(new Name("foo.example.com."), Type.AFSDB, DClass.IN));
Query query = TestUtils.getQuery(replies, message);
ResolveTask task = new ResolveTask(query);
task.setCache(TestUtils.getEhcache());
task.setBackendStore(new BackendRepository() {
@Override
public Backend lookup(int type) {
return null;
}
@Override public void stop() {}
});
task.run();
Message result = replies.get(0);
Assert.assertEquals(Rcode.REFUSED, result.getRcode());
}
@Test
public void refuseUnimplementedOpcodes() throws Exception {
final List<Message> replies = new LinkedList<Message>();
Name zone = Name.fromString("dyn.test.example.");
Name host = Name.fromString("host", zone);
Update message = new Update(zone);
message.replace(host, Type.A, 3600, "1.2.3.4");
Query query = TestUtils.getQuery(replies, message);
ResolveTask task = new ResolveTask(query);
task.setCache(TestUtils.getEhcache());
task.setBackendStore(new BackendRepository() {
@Override
public Backend lookup(int type) {
return null;
}
@Override public void stop() {}
});
task.run();
Message result = replies.get(0);
Assert.assertEquals(Rcode.REFUSED, result.getRcode());
}
@Test
public void answerTypeDoesntMatchQueryType() throws Exception {
final List<Message> replies = new LinkedList<Message>();
final Ehcache cache = TestUtils.getEhcache();
Query query = TestUtils.getQuery(replies);
final List<Record> pushed = new LinkedList<Record>();
Backend backend = new TestingBackend(pushed);
AbstractTaskKeeper zone = new AbstractTaskKeeper() {
@Override public void start() { }
@Override public void stop() { }
@Override public void keep(ResolveTask task) { }
@Override public void replyArrived(Ehcache cache, Element lmnt) { }
@Override public void discard(ResolveTask task) { }
};
ResolveTask task = new ResolveTask(query);
task.setCache(cache);
task.setStagingZone(zone);
task.setBackendStore(new BackendRepository() {
@Override
public Backend lookup(int type) {
return new TestingBackend(new LinkedList<Record>());
}
@Override public void stop() {}
});
task.run();
Record reply = new AAAARecord(new Name("foo.example.com."), DClass.IN,
1800, InetAddress.getByName("2002:53fe:52a1:7::c9d9"));
task.answer(reply, false);
Message result = replies.get(0);
Assert.assertEquals(Rcode.SERVFAIL, result.getRcode());
}
}