/* * Copyright 2013, The Sporting Exchange Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.betfair.platform; import com.betfair.baseline.v2.BaselineSyncClient; import com.betfair.baseline.v2.enumerations.BodyParamEnumObjectBodyParameterEnum; import com.betfair.baseline.v2.enumerations.EnumOperationHeaderParamEnum; import com.betfair.baseline.v2.enumerations.EnumOperationQueryParamEnum; import com.betfair.baseline.v2.enumerations.EnumOperationResponseObjectBodyParameterEnum; import com.betfair.baseline.v2.enumerations.EnumOperationResponseObjectHeaderParameterEnum; import com.betfair.baseline.v2.enumerations.EnumOperationResponseObjectQueryParameterEnum; import com.betfair.baseline.v2.exception.SimpleException; import com.betfair.baseline.v2.exception.WotsitException; import com.betfair.baseline.v2.to.BodyParamEnumObject; import com.betfair.baseline.v2.to.ComplexObject; import com.betfair.baseline.v2.to.EnumOperationResponseObject; import com.betfair.baseline.v2.to.NonMandatoryParamsOperationResponseObject; import com.betfair.baseline.v2.to.NonMandatoryParamsRequest; import com.betfair.baseline.v2.to.SimpleResponse; import com.betfair.cougar.api.ExecutionContext; import com.betfair.cougar.client.socket.ExecutionVenueNioClient; import com.betfair.cougar.core.api.exception.CougarClientException; import com.betfair.cougar.core.api.exception.CougarServiceException; import com.betfair.cougar.core.api.exception.CougarValidationException; import com.betfair.cougar.core.impl.CougarSpringCtxFactoryImpl; import com.betfair.cougar.logging.CougarLoggingUtils; import org.slf4j.LoggerFactory; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * Exercise the baseline app using the binary protocol */ public class BinaryProtocolTest { private static BaselineSyncClient client; private static DefaultHttpClient httpClient; private static ClassPathXmlApplicationContext springContext; private static ExecutionContext ec; @BeforeClass public static void beforeClass() throws ClientProtocolException, IOException, InterruptedException { // set the relevant system props prior to starting cougar.. System.setProperty("cougar.client.rescript.remoteaddress","http://127.0.0.1:8080/"); System.setProperty("baseline.server.binaryProtocol.address","127.0.0.1:9003"); System.setProperty("cougar.log.CONSOLE.level","INFO"); System.setProperty("cougar.geoip.useDefault","true"); System.setProperty("cougar.client.socket.ssl.supportsTls","false"); System.setProperty("cougar.client.socket.ssl.requiresTls","false"); System.setProperty("cougar.client.socket.session.workerTimeout","2"); System.setProperty("cougar.client.socket.reconnectInterval","500"); System.setProperty("cougar.app.name","cougar-binaryprotocol-tests"); httpClient = new DefaultHttpClient(); setServerHealth(OK); CougarLoggingUtils.setTraceLogger(null); //because trace log is static and multiple spring contexts will try to set it CougarSpringCtxFactoryImpl context = new CougarSpringCtxFactoryImpl(); springContext = context.create(); client = (BaselineSyncClient) springContext.getBean("baselineClient"); ec = ExecutionContextHelper.createContext("abc", "127.0.0.1"); } @AfterClass public void afterClass() { ((ExecutionVenueNioClient)springContext.getBean("socketTransport")).stop(); springContext.getBeanFactory().destroySingletons(); springContext.stop(); } @Test(description="Test that making the server unhealthy causes the client to disconnect, and reconnect when the server becomes healthy again") public void testSocketHealth() throws ClientProtocolException, IOException, InterruptedException { setServerHealth(OK); try { Boolean result = client.boolSimpleTypeEcho(ec, true ); Assert.assertEquals(Boolean.TRUE, result); } catch (SimpleException e) { Assert.fail("should be connected"); } setServerHealth(FAIL); try { Boolean result = client.boolSimpleTypeEcho(ec, true); Assert.fail("shouldn't be connected"); } catch (SimpleException e) { Assert.fail(); } catch (CougarClientException e) { //not connected } setServerHealth(WARN); // It can take upto 50s for connection to re-establish try{Thread.sleep(50000);}catch (Exception ex){} try { Boolean result = client.boolSimpleTypeEcho(ec, true ); Assert.assertEquals(Boolean.TRUE, result); } catch (SimpleException e) { Assert.fail("should be connected",e); } } @Test (description = "test application client not acting as proxy or intermediary for another customer or client") public void testNullCustomerIPAddress() { try { ExecutionContext ec = ExecutionContextHelper.createContext("abc",null); SimpleResponse r = client.testSimpleGet(ec,"simples"); Assert.assertEquals(r.getMessage(), "simples"); } catch (SimpleException e) { Assert.fail("unexpected exception",e); } } @Test(description="test basic invocation") public void testSimpleGet() { try { SimpleResponse r = client.testSimpleGet(ec, "simples"); Assert.assertEquals(r.getMessage(), "simples"); } catch (SimpleException e) { Assert.fail("unexpected exception",e); } } @Test(description="test that the binary protocol handles list collections") public void testLists() { try { List<String> request = Arrays.asList("abc","def","ghi"); List<String> result = client.testSimpleListGet(ec, request); Assert.assertEquals(result, request); } catch (SimpleException e) { Assert.fail("unexpected exception",e); } } @Test(description="test that the binary protocol handles sets") public void testSets() { Set<String> request = new HashSet<String>(Arrays.asList("abc","def","ghi")); Set<String> response; try { response = client.testSimpleSetGet(ec, request); Assert.assertEquals(response, request); } catch (SimpleException e) { Assert.fail("unexpected exception",e); } } @Test(description="test the binary protocol handles maps") public void testMaps() { Map<String, String> request = new HashMap<String, String>(); request.put("a", "a"); request.put("b", "b"); try { Map<String,String> response = client.testSimpleMapGet(ec, request); } catch (SimpleException e) { Assert.fail("unexpected exception",e); } } @Test(description="test binary protocol handles void responses") public void testVoidResponse() { try { client.voidResponseOperation(ec, "void"); } catch (SimpleException e) { Assert.fail("unexpected exception",e); } } @Test(description="test no param operations") public void testNoParamOperations() { try { client.testNoParams(ec); } catch (SimpleException e) { Assert.fail("unexpected exception",e); } } @Test(description="test binary protocol handles null parameters") public void testNonMandatoryParams() { try { NonMandatoryParamsRequest request = new NonMandatoryParamsRequest(); request.setBodyParameter1(null); request.setBodyParameter2(null); NonMandatoryParamsOperationResponseObject response = client.nonMandatoryParamsOperation(ec, null, null, request); Assert.assertNull(response.getHeaderParameter()); Assert.assertNull(response.getQueryParameter()); Assert.assertNull(response.getBodyParameter1()); Assert.assertNull(response.getBodyParameter2()); } catch (SimpleException e) { Assert.fail("unexpected exception",e); } } @Test(description="test binary protocol handles null parameters") public void testMandatoryParameterNotSupplied() { try { client.voidResponseOperation(ec, null); Assert.fail("expected an exception as parameter is mandatory"); } catch (SimpleException e) { Assert.fail("unexpected exception",e); } catch (CougarValidationException e) { //all is good } } @Test(description="test binary protocol handles complex objects") public void testComplexObjects() { ComplexObject co = new ComplexObject(); co.setName("sum"); co.setValue1(1); co.setValue2(2); try { SimpleResponse response = client.testComplexMutator(ec, co); Assert.assertEquals(response.getMessage(), "sum = 3"); } catch (SimpleException e) { Assert.fail("unexpected exception",e); } } @Test(description="test complex objects that have optional elements") public void testComplexObjectWithOptionalElement() { ComplexObject co = new ComplexObject(); co.setName("sum"); co.setValue1(1); co.setValue2(null); try { SimpleResponse response = client.testComplexMutator(ec, co); Assert.assertEquals(response.getMessage(), "sum = 1"); } catch (SimpleException e) { Assert.fail("unexpected exception",e); } } @Test(description="test binary protocol handles methods that throw exceptions") public void testExceptions() { try { client.testException(ec, "BadRequest", "aMessage"); } catch (SimpleException e) { Assert.assertEquals(e.getReason(), "aMessage"); Assert.assertEquals(e.getExceptionCode(), "SEX-0002"); } catch (WotsitException e) { Assert.fail("unexpected exception",e); } } @Test(description="test binary protocol handles methods that throw runtime exceptions") public void testRuntimeExceptions() { try { client.testException(ec, "BadRequest", "throwRuntime"); } catch (SimpleException e) { Assert.fail("unexpected exception",e); } catch (WotsitException e) { Assert.fail("unexpected exception",e); } catch (CougarClientException e) { //all good } } @Test(description="test binary protocol handles enumerations") public void testEnumeration() { BodyParamEnumObject obj = new BodyParamEnumObject(); obj.setBodyParameter(BodyParamEnumObjectBodyParameterEnum.BarBody); try { EnumOperationResponseObject response = client.enumOperation(ec, EnumOperationHeaderParamEnum.FooHeader, EnumOperationQueryParamEnum.BarQuery, obj ); Assert.assertEquals(response.getHeaderParameter(), EnumOperationResponseObjectHeaderParameterEnum.FooHeader); Assert.assertEquals(response.getQueryParameter(), EnumOperationResponseObjectQueryParameterEnum.BarQuery); Assert.assertEquals(response.getBodyParameter(), EnumOperationResponseObjectBodyParameterEnum.BarBody); } catch (SimpleException e) { Assert.fail("unexpected exception",e); } } private static void setServerHealth(String health) throws ClientProtocolException, IOException, InterruptedException { HttpPost post = new HttpPost("http://localhost:8080/www/cougarBaseline/v2.0/setHealthStatusInfo"); post.setEntity(new StringEntity(health)); post.setHeader("Content-type", "application/json"); readFully(httpClient.execute(post)); for (int i=0; i<10; i++) { HttpGet get = new HttpGet("http://localhost:8080/www/healthcheck/v2.0/summary?alt=xml"); List<String> lines = readFully(httpClient.execute(get)); String expectedStatus = "OK"; if (health == FAIL ) { expectedStatus = "FAIL"; } for (String line : lines) { if (line.contains(expectedStatus)) { Thread.sleep(1000); return; } } System.err.println("server health not reporting expected status, will try again"); Thread.sleep(1000); } System.err.println("server health not set, expect failing tests to follow "); } private static List<String> readFully(HttpResponse response) throws IllegalStateException, IOException { response.getStatusLine(); InputStream is = response.getEntity().getContent(); InputStreamReader reader = new InputStreamReader(is); BufferedReader br = new BufferedReader(reader); String line = null; List<String> lines = new ArrayList<String>(); while ((line = br.readLine()) != null) { lines.add(line); } return lines; } private static String OK = "{ \"message\" : " + " { \"initialiseHealthStatusObject\" : \"true\", " + " \"DBConnectionStatusDetail\" : \"OK\", " + " \"cacheAccessStatusDetail\" : \"OK\", " + " \"serviceStatusDetail\" : \"OK\" } }"; private static String FAIL = "{ \"message\" : " + " { \"initialiseHealthStatusObject\" : \"true\", " + " \"DBConnectionStatusDetail\" : \"FAIL\", " + " \"cacheAccessStatusDetail\" : \"FAIL\", " + " \"serviceStatusDetail\" : \"FAIL\" } }"; private static String WARN = "{ \"message\" : " + " { \"initialiseHealthStatusObject\" : \"true\", " + " \"DBConnectionStatusDetail\" : \"WARN\", " + " \"cacheAccessStatusDetail\" : \"WARN\", " + " \"serviceStatusDetail\" : \"WARN\" } }"; }