package com.workshare.msnos.core.protocols.ip.http;
import static com.workshare.msnos.core.Iden.Type.AGT;
import static com.workshare.msnos.core.Iden.Type.CLD;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.util.UUID;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.util.EntityUtils;
import org.junit.Before;
import org.junit.Test;
import com.workshare.msnos.core.Cloud;
import com.workshare.msnos.core.CoreHelper;
import com.workshare.msnos.core.Iden;
import com.workshare.msnos.core.Identifiable;
import com.workshare.msnos.core.Message;
import com.workshare.msnos.core.Ring;
import com.workshare.msnos.core.Message.Type;
import com.workshare.msnos.core.MessageBuilder;
import com.workshare.msnos.core.MsnosException;
import com.workshare.msnos.core.Receipt;
import com.workshare.msnos.core.protocols.ip.BaseEndpoint;
import com.workshare.msnos.core.protocols.ip.Endpoint;
import com.workshare.msnos.core.protocols.ip.Endpoints;
import com.workshare.msnos.core.protocols.ip.HttpEndpoint;
import com.workshare.msnos.core.protocols.ip.www.HttpClientHelper;
import com.workshare.msnos.core.serializers.WireJsonSerializer;
public class HttpGatewayTest {
private static final Iden AGENT_SMITH = newIden(AGT);
private static final String AGENT_SMITH_URL = "http://agents.smith:123/foo";
private static final String SAMPLE_HOST = "21.21.21.21";
private static final HttpEndpoint SAMPLE_ENDPOINT = new HttpEndpoint(CoreHelper.asPublicNetwork(SAMPLE_HOST), "http://123.com", newIden(AGT));
private HttpGateway gate;
private Cloud cloud;
private HttpClientHelper http;
private WireJsonSerializer sz;
@Before
public void setup() throws Exception {
http = new HttpClientHelper();
gate = new HttpGateway(http.client());
cloud = mock(Cloud.class);
when(cloud.getIden()).thenReturn(newIden(CLD));
when(cloud.getRing()).thenReturn(Ring.random());
sz = new WireJsonSerializer();
installEndpoint("25.25.25.25", AGENT_SMITH, AGENT_SMITH_URL);
}
@Test
public void shouldReturnInstallableEndpoints() throws Exception {
Endpoints endpoints = gate.endpoints();
Endpoint ep1 = endpoints.install(SAMPLE_ENDPOINT);
assertTrue(endpoints.all().contains(ep1));
}
@Test
public void shouldReturnRemovableEndpoints() throws Exception {
Endpoints endpoints = gate.endpoints();
int currentSize = endpoints.all().size();
Endpoint ep1 = endpoints.install(SAMPLE_ENDPOINT);
endpoints.remove(ep1);
assertEquals(currentSize, endpoints.all().size());
}
@Test(expected=MsnosException.class)
public void shouldRefuseToInstallNonHttpEndpoints() throws Exception {
gate.endpoints().install(new BaseEndpoint(Endpoint.Type.UDP, CoreHelper.asPublicNetwork("10.10.10.1")));
}
@Test
public void shouldStampReceiptWithGatewayName() throws Exception {
Message message = newSampleMessage(newIden(AGT), newIden(CLD));
Receipt receipt = gate.send(cloud, message, null);
assertEquals("HTTP", receipt.getGate());
}
@Test
public void shouldReturnFailedDeliveryReceiptWhenMessageDirectedToCloudAndNoMeansToDeliverIt() throws Exception {
Message message = newSampleMessage(newIden(AGT), newIden(CLD));
Receipt receipt = gate.send(cloud, message, null);
assertEquals(Message.Status.FAILED, receipt.getStatus());
}
@Test
public void shouldReturnFailedDeliveryReceiptWhenNoRouteToTarget() throws Exception {
Message message = newSampleMessage(newIden(AGT), newIden(AGT));
Receipt receipt = gate.send(cloud, message, null);
assertEquals(Message.Status.FAILED, receipt.getStatus());
}
@Test
public void shouldSendTheMessageUsingHttpClient() throws Exception {
Message message = newSampleMessage(newIden(AGT), AGENT_SMITH);
Receipt receipt = gate.send(cloud, message, null);
HttpPost request = http.getLastPostToWWW();
assertNotNull(request);
assertEquals(AGENT_SMITH_URL, request.getURI().toString());
assertEquals(toText(message), toText(request.getEntity()));
assertEquals(Message.Status.DELIVERED, receipt.getStatus());
}
@Test
public void shouldPreferIdentifiableAgaubsMessageTo() throws Exception {
Message message = newSampleMessage(newIden(AGT), newIden(AGT));
gate.send(cloud, message, asIdentifiable(AGENT_SMITH));
assertEquals(AGENT_SMITH_URL, http.getLastPostToWWW().getURI().toString());
}
private Identifiable asIdentifiable(Iden iden) {
Identifiable target = mock(Identifiable.class);
when(target.getIden()).thenReturn(iden);
return target;
}
@Test
public void shouldHandleFailures() throws Exception {
when(http.client().execute(any(HttpUriRequest.class))).thenThrow(new IOException("boom!"));
Receipt receipt = gate.send(cloud, newSampleMessage(newIden(AGT), AGENT_SMITH), null);
assertEquals(Message.Status.FAILED, receipt.getStatus());
}
private String toText(Message message) {
return sz.toText(message);
}
public String toText(HttpEntity entity) throws ParseException, IOException {
return EntityUtils.toString(entity);
}
private void installEndpoint(final String host, Iden agent, final String url) throws MsnosException {
gate.endpoints().install(new HttpEndpoint(CoreHelper.asPublicNetwork(host), url, agent));
}
private static Iden newIden(final com.workshare.msnos.core.Iden.Type idenType) {
return new Iden(idenType, UUID.randomUUID());
}
private Message newSampleMessage(Iden from, Iden to) {
return new MessageBuilder(Type.APP, from, to).with(UUID.randomUUID()).make();
}
}