/*
* Minha.pt: middleware testing platform.
* Copyright (c) 2011-2014, Universidade do Minho.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 pt.minha.test.model.net;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.util.ArrayList;
import java.util.List;
import mockit.FullVerifications;
import mockit.Mocked;
import org.testng.annotations.Test;
import pt.minha.api.Entry;
import pt.minha.api.Exit;
import pt.minha.api.sim.Global;
import pt.minha.api.sim.Simulation;
public class MulticastTest {
@Global
public static interface Callback {
public void receive(DatagramPacket packet, InetSocketAddress address);
public void exception(Exception e);
}
@Global
public static interface Target {
public void open(InetSocketAddress addr, Callback cb) throws IOException;
public void send(DatagramPacket packet) throws IOException;
}
public static class Impl implements Target {
private MulticastSocket socket;
private Callback callback;
public void open(InetSocketAddress addr, Callback cb) throws IOException {
this.callback = cb;
this.socket = new MulticastSocket(addr.getPort());
if (addr.getAddress().isMulticastAddress())
socket.joinGroup(addr.getAddress());
new Thread() {
public void run() {
try {
while(true) {
DatagramPacket p = new DatagramPacket(new byte[1024], 1024);
socket.receive(p);
callback.receive(p, (InetSocketAddress)socket.getLocalSocketAddress());
}
} catch(Exception e) {
callback.exception(e);
return;
}
}
}.start();
}
public void send(DatagramPacket packet) throws IOException {
socket.send(packet);
}
}
// https://code.google.com/p/minha/issues/detail?id=6
@Test
public void multicast(@Mocked final Callback cb) throws Exception {
Simulation world = new Simulation();
final int N = 10;
final Entry<Target>[] en = world.createEntries(N, Target.class, Impl.class.getName());
final Exit<Callback>[] ex = world.createExits(en, Callback.class, cb);
final byte[] data = "Message!".getBytes();
final InetSocketAddress addr = new InetSocketAddress("224.1.2.3", 12345);
final DatagramPacket packet = new DatagramPacket(data, data.length, addr);
for(int i = 0; i<en.length; i++)
en[i].queue().open(addr, ex[i].report());
en[0].at(1, SECONDS).queue().send(packet);
world.runAll(ex);
world.close();
List<DatagramPacket> lp = new ArrayList<>();
List<InetSocketAddress> la = new ArrayList<>();
new FullVerifications() {{
cb.receive(withCapture(lp), withCapture(la)); times = N;
}};
for(int i=0; i<N; i++) {
DatagramPacket p = lp.get(i);
InetSocketAddress a = la.get(i);
// Receiver address
assertNotNull(a);
assertEquals(a.getPort(), addr.getPort());
// Sender address
assertNotNull(p);
assertEquals(p.getAddress(), en[0].getProcess().getHost().getAddress());
assertEquals(p.getPort(), addr.getPort());
// Data
assertNotNull(p.getData());
assertTrue(DatagramTest.checkData(p, data));
}
}
@Test
public void filter(@Mocked final Callback yes, @Mocked final Callback no) throws Exception {
Simulation world = new Simulation();
final int N = 3;
final Entry<Target>[] en = world.createEntries(N, Target.class, Impl.class.getName());
final Exit<Callback>[] ex = world.createExits(en, Callback.class, no);
final byte[] data = "Message!".getBytes();
ex[0] = en[0].getProcess().createExit(Callback.class, yes);
final InetSocketAddress addr = new InetSocketAddress("224.1.2.3", 12345);
en[0].queue().open(addr, ex[0].report());
// Same address, different port
en[1].queue().open(new InetSocketAddress("224.1.2.3", 54321), ex[1].report());
// No join (but on joined host), same port
en[1].queue().open(new InetSocketAddress("127.0.0.1", 12345), ex[1].report());
// Different address, same port
en[2].queue().open(new InetSocketAddress("224.3.2.1", 12345), ex[2].report());
final DatagramPacket packet = new DatagramPacket(data, data.length, addr);
en[0].at(1, SECONDS).queue().send(packet);
world.run();
world.close();
new FullVerifications() {
{
yes.receive(withAny(packet), new InetSocketAddress("10.0.0.1", 12345));
}
};
}
}