package ch.usi.da.smr; import static org.junit.Assert.assertEquals; import java.io.File; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.sun.net.httpserver.HttpServer; import ch.usi.da.smr.message.Command; import ch.usi.da.smr.message.CommandType; import ch.usi.da.smr.message.Message; import ch.usi.da.smr.recovery.DfsRecovery; import ch.usi.da.smr.recovery.HttpRecovery; import ch.usi.da.smr.transport.Receiver; import ch.usi.da.smr.transport.UDPListener; public class ReplicaTest implements Receiver { Logger logger = Logger.getLogger("ch.usi.da"); List<Message> received; Replica replica; UDPListener udp; @Before public void initialize() throws Exception { logger.setLevel(Level.FATAL); new File(HttpRecovery.state_file).delete(); new File(HttpRecovery.snapshot_file).delete(); new File("/tmp/smr/0/1/" + DfsRecovery.state_file).delete(); new File("/tmp/smr/0/1/" + DfsRecovery.snapshot_file).delete(); new File("/tmp/smr/0/2/" + DfsRecovery.state_file).delete(); new File("/tmp/smr/0/2/" + DfsRecovery.snapshot_file).delete(); replica = new Replica("0",1,1,0,"localhost:2181"); replica.start(); received = new ArrayList<Message>(); udp = new UDPListener(1234); udp.registerReceiver(this); Thread t = new Thread(udp); t.start(); } @After public void close() { replica.close(); udp.close(); } @Test public void applyCmd() throws Exception { // put List<Command> cmd = new ArrayList<Command>(); cmd.add(new Command(1, CommandType.PUT, "test", "Value".getBytes())); Message m = new Message(1,"127.0.0.1;1234","", cmd); m.setInstance(1); m.setRing(1); replica.receive(m); // get cmd = new ArrayList<Command>(); cmd.add(new Command(2, CommandType.GET, "test",new byte[0])); m = new Message(2,"127.0.0.1;1234","", cmd); m.setInstance(2); m.setRing(1); replica.receive(m); // wait response Command response = null; for(int i=0;i<5;i++){ Thread.sleep(1000); for(Message r : received){ for(Command c : r.getCommands()){ if(c.getID() == 2){ response = c; break; } } } } assertEquals("Value",new String(response.getValue())); } @Test public void isReady() throws Exception { assertEquals(false,replica.is_ready(1,2L)); assertEquals(true,replica.is_ready(1,1L)); } @Test public void localSyncRecovery() throws Exception { Replica replica2 = new Replica("0",1,2,0,"localhost:2181"); replica2.start(); // set state and checkpoint for(int i=1;i<11;i++){ List<Command> cmd = new ArrayList<Command>(); cmd.add(new Command(i, CommandType.PUT, "test" + i, "Value".getBytes())); Message m = new Message(1,"127.0.0.1;1234","", cmd); m.setRing(1); m.setInstance(i); replica.receive(m); } replica.sync_checkpoint(); // recover assertEquals(false,replica2.is_ready(1,2L)); // triggers recovery Thread.sleep(2000); assertEquals(true,replica2.is_ready(1,2L)); assertEquals(true,replica2.is_ready(1,11L)); assertEquals(false,replica2.is_ready(1,12L)); replica2.close(); } @Test public void localAsyncRecovery() throws Exception { Replica replica2 = new Replica("0",1,2,0,"localhost:2181"); replica2.start(); // set state and checkpoint for(int i=1;i<11;i++){ List<Command> cmd = new ArrayList<Command>(); cmd.add(new Command(i, CommandType.PUT, "test" + i, "Value".getBytes())); Message m = new Message(1,"127.0.0.1;1234","", cmd); m.setRing(1); m.setInstance(i); replica.receive(m); } replica.async_checkpoint(); Thread.sleep(2000); // recover assertEquals(false,replica2.is_ready(1,2L)); // triggers recovery Thread.sleep(4000); assertEquals(true,replica2.is_ready(1,2L)); assertEquals(true,replica2.is_ready(1,11L)); assertEquals(false,replica2.is_ready(1,12L)); replica2.close(); } @Test public void remoteRecovery() throws Exception { // set state and checkpoint for(int i=1;i<11;i++){ List<Command> cmd = new ArrayList<Command>(); cmd.add(new Command(i, CommandType.PUT, "test" + i, "Value".getBytes())); Message m = new Message(1,"127.0.0.1;1234","", cmd); m.setRing(1); m.setInstance(i); replica.receive(m); } replica.sync_checkpoint(); replica.close(); //Thread.sleep(2000); // wait until port 8080 is free // mv checkpoint File state = new File(HttpRecovery.state_file + "J"); new File(HttpRecovery.state_file).renameTo(state); File data = new File(HttpRecovery.snapshot_file + "J"); new File(HttpRecovery.snapshot_file).renameTo(data); // remote snapshot transfer server try { HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); server.createContext("/state", new HttpRecovery.SendFile(HttpRecovery.state_file + "J")); server.createContext("/snapshot", new HttpRecovery.SendFile(HttpRecovery.snapshot_file + "J")); server.setExecutor(null); // creates a default executor server.start(); }catch(Exception e){ logger.error("remoteRecovery test could not start http server: " + e); } // recover Replica replica2 = new Replica("0",1,2,0,"localhost:2181"); replica2.start(); assertEquals(true,replica2.is_ready(1,11L)); replica2.close(); state.delete(); data.delete(); } @Test public void newerState() throws Exception { Map<Integer,Long> state = new HashMap<Integer,Long>(); Map<Integer,Long> nstate = new HashMap<Integer,Long>(); state.put(1,1L); nstate.put(1,1L); assertEquals(false,Replica.newerState(nstate, state)); state.put(1,1L); nstate.put(1,2L); assertEquals(true,Replica.newerState(nstate, state)); state.put(1,1L); nstate.put(1,1L); state.put(16,2L); nstate.put(16,3L); assertEquals(true,Replica.newerState(nstate, state)); state.put(1,1L); nstate.put(1,1L); state.put(16,3L); nstate.put(16,2L); assertEquals(false,Replica.newerState(nstate, state)); state.put(1,1L); nstate.put(1,2L); state.put(16,3L); // should not happen, since round-robin start in lowest ring nstate.put(16,2L); assertEquals(true,Replica.newerState(nstate, state)); state.clear(); nstate.clear(); assertEquals(false,Replica.newerState(nstate, state)); state.put(0,0L); // special case: ring 0 means not global ring state.put(1,1L); nstate.put(1,2L); assertEquals(true,Replica.newerState(nstate, state)); } @Test public void copyOnWrite() throws Exception { Map<Integer,Long> state = new HashMap<Integer,Long>(); state.put(1,1L); Map<Integer,Long> nstate = new HashMap<Integer,Long>(state); assertEquals(state.get(1),nstate.get(1)); nstate.put(1,2L); assertEquals(true,state.get(1) == 1L); assertEquals(true,nstate.get(1) == 2L); } @Override public void receive(Message m) { received.add(m); } @Override public boolean is_ready(Integer ring, Long instance) { return true; } }