From 986352111d5b552eeb478547df58928b9351025f Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Mon, 8 Jun 2009 07:03:11 +0000 Subject: [PATCH] @update:79; First end-to-end integration test git-svn-id: https://svn.argeo.org/slc/trunk@2512 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../org.argeo.slc.demo.log4j/log4j.properties | 2 +- .../slc/it/webapp/SimpleScenarioTest.java | 27 ++++ .../server/client/SlcServerHttpClient.java | 8 ++ .../impl/AbstractHttpServicesClient.java | 116 +++++++++++++++--- .../client/impl/SlcServerHttpClientImpl.java | 55 ++++++++- .../unit/AbstractHttpClientTestCase.java | 19 +-- .../impl/process/SlcExecutionServiceImpl.java | 1 - .../process/NewSlcExecutionController.java | 2 + .../org/argeo/slc/server/client/spring.xml | 1 + .../resources/org/argeo/slc/castor/spring.xml | 10 +- .../process/SlcExecutionDaoHibernate.java | 1 + 11 files changed, 203 insertions(+), 39 deletions(-) create mode 100644 integration-tests/org.argeo.slc.it.webapp/src/test/java/org/argeo/slc/it/webapp/SimpleScenarioTest.java diff --git a/demo/site/org.argeo.slc.demo.log4j/log4j.properties b/demo/site/org.argeo.slc.demo.log4j/log4j.properties index a1a6509b6..bae808ee8 100644 --- a/demo/site/org.argeo.slc.demo.log4j/log4j.properties +++ b/demo/site/org.argeo.slc.demo.log4j/log4j.properties @@ -6,7 +6,7 @@ log4j.logger.org.argeo.slc.execution.ExecutionParameterPostProcessor=TRACE log4j.logger.org.argeo.slc.execution.ExecutionContext=DEBUG log4j.logger.org.argeo.slc.execution.SimpleExecutionSpec=DEBUG -log4j.logger.org.argeo.slc.services=DEBUG +log4j.logger.org.argeo.slc.web.mvc=DEBUG log4j.logger.org.hibernate=WARN diff --git a/integration-tests/org.argeo.slc.it.webapp/src/test/java/org/argeo/slc/it/webapp/SimpleScenarioTest.java b/integration-tests/org.argeo.slc.it.webapp/src/test/java/org/argeo/slc/it/webapp/SimpleScenarioTest.java new file mode 100644 index 000000000..1d751f3cb --- /dev/null +++ b/integration-tests/org.argeo.slc.it.webapp/src/test/java/org/argeo/slc/it/webapp/SimpleScenarioTest.java @@ -0,0 +1,27 @@ +package org.argeo.slc.it.webapp; + +import org.argeo.slc.Condition; +import org.argeo.slc.core.test.tree.TreeTestResultList; +import org.argeo.slc.runtime.SlcAgentDescriptor; +import org.argeo.slc.server.unit.AbstractHttpClientTestCase; + +public class SimpleScenarioTest extends AbstractHttpClientTestCase { + public void testSimpleScenario() throws Exception { + // Get agent + SlcAgentDescriptor agentDescriptor = getHttpClient().waitForOneAgent(); + assertNotNull(agentDescriptor); + + // Launch SLC Execution + // TODO: don't hardcode tested version + assertAnswerOk(getHttpClient().startFlow(agentDescriptor.getUuid(), + "org.argeo.slc.demo.basic", "0.11.4.SNAPSHOT", "main")); + + getHttpClient().callServiceSafe("listResults.service", null, + new Condition() { + + public Boolean check(TreeTestResultList obj) { + return obj.getList().size() == 3; + } + }, null); + } +} diff --git a/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/client/SlcServerHttpClient.java b/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/client/SlcServerHttpClient.java index 2113438f8..3bd51e910 100644 --- a/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/client/SlcServerHttpClient.java +++ b/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/client/SlcServerHttpClient.java @@ -1,9 +1,17 @@ package org.argeo.slc.server.client; +import org.argeo.slc.msg.ExecutionAnswer; import org.argeo.slc.runtime.SlcAgentDescriptor; /** Abstraction of the access to HTTP services of an SLC Server. */ public interface SlcServerHttpClient extends HttpServicesClient { /** Wait for one agent to be available. */ public SlcAgentDescriptor waitForOneAgent(); + + /** Wait for the http server to be ready. */ + public void waitForServerToBeReady(); + + /** Start an execution flow on the given agent. */ + public ExecutionAnswer startFlow(String agentId, String moduleName, + String version, String flowName); } diff --git a/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/client/impl/AbstractHttpServicesClient.java b/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/client/impl/AbstractHttpServicesClient.java index ba4e584ef..410e8d9af 100644 --- a/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/client/impl/AbstractHttpServicesClient.java +++ b/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/client/impl/AbstractHttpServicesClient.java @@ -1,11 +1,18 @@ package org.argeo.slc.server.client.impl; import java.io.IOException; -import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; import java.net.HttpURLConnection; import java.net.URL; +import java.net.URLEncoder; +import java.util.Iterator; import java.util.Map; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.commons.io.IOUtils; @@ -14,6 +21,7 @@ import org.apache.commons.logging.LogFactory; import org.argeo.slc.Condition; import org.argeo.slc.SlcException; import org.argeo.slc.server.client.HttpServicesClient; +import org.springframework.oxm.Marshaller; import org.springframework.oxm.Unmarshaller; import org.springframework.util.Assert; @@ -21,13 +29,22 @@ public abstract class AbstractHttpServicesClient implements HttpServicesClient { private final static Log log = LogFactory .getLog(AbstractHttpServicesClient.class); private Unmarshaller unmarshaller; + private Marshaller marshaller; private String baseUrl; + private String encoding = "UTF-8"; private Long retryPeriod = 1000l; - @SuppressWarnings(value = { "unchecked" }) + private Long defaultTimeout = 30 * 1000l; + public T callService(String path, Map parameters) { + return callService(path, parameters, null); + } + + @SuppressWarnings(value = { "unchecked" }) + public T callService(String path, Map parameters, + Object body) { try { - return (T) callServiceLowLevel(path, parameters); + return (T) callServiceLowLevel(path, parameters, body); } catch (Exception e) { throw new SlcException("Cannot call service " + path + " on " + baseUrl, e); @@ -37,13 +54,16 @@ public abstract class AbstractHttpServicesClient implements HttpServicesClient { @SuppressWarnings(value = { "unchecked" }) public T callServiceSafe(String path, Map parameters, Condition condition, Long timeout) { + if (timeout == null) + timeout = defaultTimeout; + long begin = System.currentTimeMillis(); try { Object obj = null; long duration = System.currentTimeMillis() - begin; while (duration < timeout) { try { - obj = callServiceLowLevel(path, parameters); + obj = callServiceLowLevel(path, parameters, null); } catch (IOException e) { if (log.isTraceEnabled()) log.trace("Exception when calling service " + path @@ -83,27 +103,76 @@ public abstract class AbstractHttpServicesClient implements HttpServicesClient { } protected Object callServiceLowLevel(String path, - Map parameters) throws IOException { + Map parameters, Object body) throws IOException { Assert.notNull(baseUrl, "base url"); - InputStream in = null; + HttpURLConnection connection = null; + Writer writer = null; + Reader reader = null; try { - URL url = new URL(baseUrl + path); - HttpURLConnection connection = (HttpURLConnection) url - .openConnection(); - if (parameters != null) { - for (String key : parameters.keySet()) { - connection.addRequestProperty(key, parameters.get(key)); - } + URL url = createUrl(path, parameters); + connection = (HttpURLConnection) url.openConnection(); + + if (body != null) { + connection.setRequestMethod("POST"); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setUseCaches(false); + connection.setAllowUserInteraction(false); + connection.setRequestProperty("Content-type", + "text/xml; charset=" + encoding); } + // Establish the connection connection.connect(); - in = connection.getInputStream(); - StreamSource source = new StreamSource(in); + if (body != null) { + writer = new OutputStreamWriter(connection.getOutputStream(), + encoding); + StreamResult result = new StreamResult(writer); + marshaller.marshal(body, result); + writer.flush(); + IOUtils.closeQuietly(writer); + } + + // Read answer + reader = new InputStreamReader(connection.getInputStream(), + encoding); + Source source = new StreamSource(reader); Object obj = unmarshaller.unmarshal(source); return obj; } finally { - IOUtils.closeQuietly(in); + IOUtils.closeQuietly(reader); + IOUtils.closeQuietly(writer); + if (connection != null) { + connection.disconnect(); + } + } + } + + protected URL createUrl(String service, Map parameters) { + // URL encoded with UTF-8, as recommended by W3C + final String urlEncoding = "UTF-8"; + + StringBuffer buf = new StringBuffer(baseUrl + service); + try { + if (parameters != null && parameters.size() != 0) { + buf.append('?'); + Iterator it = parameters.keySet().iterator(); + String key = null; + while (it.hasNext()) { + if (key != null) + buf.append('&'); + key = it.next(); + String keyEncoded = URLEncoder.encode(key, urlEncoding); + String valueEncoded = URLEncoder.encode( + parameters.get(key), urlEncoding); + buf.append(keyEncoded).append('=').append(valueEncoded); + } + } + + return new URL(buf.toString()); + } catch (Exception e) { + throw new SlcException("Cannot create URL: " + buf, e); } } @@ -123,4 +192,19 @@ public abstract class AbstractHttpServicesClient implements HttpServicesClient { public void setRetryPeriod(Long retryPeriod) { this.retryPeriod = retryPeriod; } + + public void setMarshaller(Marshaller marshaller) { + this.marshaller = marshaller; + } + + /** Default is UTF-8. */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** Default is 30s*/ + public void setDefaultTimeout(Long defaultTimeout) { + this.defaultTimeout = defaultTimeout; + } + } diff --git a/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/client/impl/SlcServerHttpClientImpl.java b/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/client/impl/SlcServerHttpClientImpl.java index 75e4e8ea0..e640c5c69 100644 --- a/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/client/impl/SlcServerHttpClientImpl.java +++ b/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/client/impl/SlcServerHttpClientImpl.java @@ -1,20 +1,55 @@ package org.argeo.slc.server.client.impl; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.slc.Condition; +import org.argeo.slc.SlcException; +import org.argeo.slc.execution.ExecutionFlowDescriptor; +import org.argeo.slc.msg.ExecutionAnswer; +import org.argeo.slc.msg.MsgConstants; import org.argeo.slc.msg.ObjectList; +import org.argeo.slc.process.RealizedFlow; +import org.argeo.slc.process.SlcExecution; import org.argeo.slc.runtime.SlcAgentDescriptor; import org.argeo.slc.server.client.SlcServerHttpClient; public class SlcServerHttpClientImpl extends AbstractHttpServicesClient implements SlcServerHttpClient { public final static String LIST_AGENTS = "listAgents.service"; + public final static String IS_SERVER_READY = "isServerReady.service"; + public final static String NEW_SLC_EXECUTION = "newSlcExecution.service"; private final static Log log = LogFactory .getLog(SlcServerHttpClientImpl.class); private Long retryTimeout = 60 * 1000l; + private Long serverReadyTimeout = 120 * 1000l; + + public ExecutionAnswer startFlow(String agentId, String moduleName, + String version, String flowName) { + SlcExecution slcExecution = new SlcExecution(); + slcExecution.setUuid(UUID.randomUUID().toString()); + + RealizedFlow realizedFlow = new RealizedFlow(); + realizedFlow.setModuleName(moduleName); + realizedFlow.setModuleVersion(version); + + ExecutionFlowDescriptor flowDescriptor = new ExecutionFlowDescriptor(); + flowDescriptor.setName(flowName); + + realizedFlow.setFlowDescriptor(flowDescriptor); + slcExecution.getRealizedFlows().add(realizedFlow); + + Map parameters = new HashMap(); + parameters.put(MsgConstants.PROPERTY_SLC_AGENT_ID, agentId); + ExecutionAnswer answer = callService(NEW_SLC_EXECUTION, parameters, + slcExecution); + return answer; + } public SlcAgentDescriptor waitForOneAgent() { ObjectList objectList = callServiceSafe(LIST_AGENTS, null, @@ -29,9 +64,27 @@ public class SlcServerHttpClientImpl extends AbstractHttpServicesClient return (SlcAgentDescriptor) objectList.getObjects().get(0); } - /** Timeout in ms after which a safe call will throw an exception. */ + public void waitForServerToBeReady() { + ExecutionAnswer answer = callServiceSafe(IS_SERVER_READY, null, null, + serverReadyTimeout); + if (!answer.isOk()) + throw new SlcException("Server is not ready: " + answer); + } + + /** + * Timeout in ms after which a safe call will throw an exception. Default is + * 60s. + */ public void setRetryTimeout(Long retryTimeout) { this.retryTimeout = retryTimeout; } + /** + * Timeout in ms after which the client will stop waiting for the server to + * be ready and throw an exception. Default is 120s. + */ + public void setServerReadyTimeout(Long serverReadyTimeout) { + this.serverReadyTimeout = serverReadyTimeout; + } + } diff --git a/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/unit/AbstractHttpClientTestCase.java b/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/unit/AbstractHttpClientTestCase.java index f0142ba50..5abb3f6e9 100644 --- a/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/unit/AbstractHttpClientTestCase.java +++ b/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/server/unit/AbstractHttpClientTestCase.java @@ -1,6 +1,5 @@ package org.argeo.slc.server.unit; -import org.argeo.slc.SlcException; import org.argeo.slc.msg.ExecutionAnswer; import org.argeo.slc.server.client.SlcServerHttpClient; import org.argeo.slc.unit.AbstractSpringTestCase; @@ -8,19 +7,10 @@ import org.argeo.slc.unit.AbstractSpringTestCase; public abstract class AbstractHttpClientTestCase extends AbstractSpringTestCase { private SlcServerHttpClient httpClient = null; - private String isServerReadyService = "isServerReady.service"; - protected void setUp() throws Exception { super.setUp(); httpClient = createHttpClient(); - waitForServerToBeReady(); - } - - protected void waitForServerToBeReady() { - ExecutionAnswer answer = httpClient.callServiceSafe( - isServerReadyService, null, null, getServerReadyTimeout()); - if (!answer.isOk()) - throw new SlcException("Server is not ready: " + answer); + httpClient.waitForServerToBeReady(); } protected SlcServerHttpClient createHttpClient() { @@ -32,8 +22,9 @@ public abstract class AbstractHttpClientTestCase extends AbstractSpringTestCase return httpClient; } - /** Default is 120s */ - protected Long getServerReadyTimeout() { - return 120 * 1000l; + protected void assertAnswerOk(ExecutionAnswer answer) { + if (!answer.isOk()) { + fail("Server execution answer is not ok: " + answer.getMessage()); + } } } diff --git a/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/services/impl/process/SlcExecutionServiceImpl.java b/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/services/impl/process/SlcExecutionServiceImpl.java index 023988799..b3c6f71fc 100644 --- a/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/services/impl/process/SlcExecutionServiceImpl.java +++ b/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/services/impl/process/SlcExecutionServiceImpl.java @@ -4,7 +4,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.slc.SlcException; import org.argeo.slc.dao.process.SlcExecutionDao; -import org.argeo.slc.msg.process.SlcExecutionRequest; import org.argeo.slc.msg.process.SlcExecutionStatusRequest; import org.argeo.slc.process.SlcExecution; import org.argeo.slc.services.process.SlcExecutionService; diff --git a/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/web/mvc/process/NewSlcExecutionController.java b/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/web/mvc/process/NewSlcExecutionController.java index 2e19764e6..2e6a45cfe 100644 --- a/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/web/mvc/process/NewSlcExecutionController.java +++ b/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/web/mvc/process/NewSlcExecutionController.java @@ -14,6 +14,7 @@ import org.argeo.slc.runtime.SlcAgentFactory; import org.argeo.slc.services.process.SlcExecutionService; import org.argeo.slc.web.mvc.AbstractServiceController; import org.springframework.oxm.Unmarshaller; +import org.springframework.util.Assert; import org.springframework.web.servlet.ModelAndView; import org.springframework.xml.transform.StringSource; @@ -38,6 +39,7 @@ public class NewSlcExecutionController extends AbstractServiceController { String agentId = request .getParameter(MsgConstants.PROPERTY_SLC_AGENT_ID); + Assert.notNull(agentId, "agent id"); String answer = request.getParameter("body"); if (answer == null) { diff --git a/runtime/org.argeo.slc.server/src/main/resources/org/argeo/slc/server/client/spring.xml b/runtime/org.argeo.slc.server/src/main/resources/org/argeo/slc/server/client/spring.xml index 8f63be9b1..c9af00057 100644 --- a/runtime/org.argeo.slc.server/src/main/resources/org/argeo/slc/server/client/spring.xml +++ b/runtime/org.argeo.slc.server/src/main/resources/org/argeo/slc/server/client/spring.xml @@ -13,6 +13,7 @@ + \ No newline at end of file diff --git a/runtime/org.argeo.slc.support.castor/src/main/resources/org/argeo/slc/castor/spring.xml b/runtime/org.argeo.slc.support.castor/src/main/resources/org/argeo/slc/castor/spring.xml index de3e0c977..bdcd63a64 100644 --- a/runtime/org.argeo.slc.support.castor/src/main/resources/org/argeo/slc/castor/spring.xml +++ b/runtime/org.argeo.slc.support.castor/src/main/resources/org/argeo/slc/castor/spring.xml @@ -3,8 +3,7 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" default-lazy-init="true"> - + @@ -31,10 +30,10 @@ + - @@ -43,8 +42,7 @@ - + diff --git a/runtime/org.argeo.slc.support.hibernate/src/main/java/org/argeo/slc/hibernate/process/SlcExecutionDaoHibernate.java b/runtime/org.argeo.slc.support.hibernate/src/main/java/org/argeo/slc/hibernate/process/SlcExecutionDaoHibernate.java index 5cfde101e..303443d02 100644 --- a/runtime/org.argeo.slc.support.hibernate/src/main/java/org/argeo/slc/hibernate/process/SlcExecutionDaoHibernate.java +++ b/runtime/org.argeo.slc.support.hibernate/src/main/java/org/argeo/slc/hibernate/process/SlcExecutionDaoHibernate.java @@ -33,6 +33,7 @@ public class SlcExecutionDaoHibernate extends HibernateDaoSupport implements uuid); } + @SuppressWarnings("unchecked") public List listSlcExecutions() { return (List) getHibernateTemplate().loadAll( SlcExecution.class); -- 2.39.2