From c57c0dd550f48f352c8a43758d179957cc72127e Mon Sep 17 00:00:00 2001 From: Jose Date: Wed, 19 Oct 2022 07:54:56 -0500 Subject: [PATCH] chore(agama): add test cases for agama engine (#2673) * chore: add Java test cases #2672 * docs: minor update #2672 * chore: add testNG configurations #2672 * chore: add agama resources for reference #2672 * chore: log statements optimization #2672 --- agama/engine/pom.xml | 73 +++++++ .../default/config-agama-test.properties | 6 + .../agama/engine/service/ActionService.java | 10 +- .../java/io/jans/agama/test/BaseTest.java | 183 ++++++++++++++++++ .../agama/test/CustomConfigsFlowTest.java | 64 ++++++ .../java/io/jans/agama/test/MathFlowTest.java | 62 ++++++ .../agama/test/SaySomething2FlowTest.java | 57 ++++++ .../agama/test/SaySomething3FlowTest.java | 40 ++++ .../jans/agama/test/SaySomethingFlowTest.java | 59 ++++++ .../io/jans/agama/test/UidOnlyAuthTest.java | 42 ++++ .../flows/io.jans.agama.test.auth.uidOnly | 10 + .../resources/flows/io.jans.agama.test.math | 54 ++++++ .../flows/io.jans.agama.test.showConfig | 8 + .../src/test/resources/flows/org.gluu.flow1 | 11 ++ .../src/test/resources/flows/org.gluu.flow2 | 14 ++ .../src/test/resources/flows/org.gluu.flow3 | 7 + .../engine/src/test/resources/log4j2-test.xml | 21 ++ .../templates/custom/printConfigs.ftlh | 14 ++ .../src/test/resources/templates/f1/index.ftl | 14 ++ .../test/resources/templates/f1/index2.ftl | 15 ++ .../test/resources/templates/hello/index.ftlh | 11 ++ .../src/test/resources/templates/login.ftlh | 59 ++++++ .../test/resources/templates/me/myindex.ftlh | 14 ++ .../src/test/resources/testng.properties | 8 + agama/engine/src/test/resources/testng.xml | 43 ++++ docs/admin/developer/agama/dsl-full.md | 2 +- 26 files changed, 897 insertions(+), 4 deletions(-) create mode 100644 agama/engine/profiles/default/config-agama-test.properties create mode 100644 agama/engine/src/test/java/io/jans/agama/test/BaseTest.java create mode 100644 agama/engine/src/test/java/io/jans/agama/test/CustomConfigsFlowTest.java create mode 100644 agama/engine/src/test/java/io/jans/agama/test/MathFlowTest.java create mode 100644 agama/engine/src/test/java/io/jans/agama/test/SaySomething2FlowTest.java create mode 100644 agama/engine/src/test/java/io/jans/agama/test/SaySomething3FlowTest.java create mode 100644 agama/engine/src/test/java/io/jans/agama/test/SaySomethingFlowTest.java create mode 100644 agama/engine/src/test/java/io/jans/agama/test/UidOnlyAuthTest.java create mode 100644 agama/engine/src/test/resources/flows/io.jans.agama.test.auth.uidOnly create mode 100644 agama/engine/src/test/resources/flows/io.jans.agama.test.math create mode 100644 agama/engine/src/test/resources/flows/io.jans.agama.test.showConfig create mode 100644 agama/engine/src/test/resources/flows/org.gluu.flow1 create mode 100644 agama/engine/src/test/resources/flows/org.gluu.flow2 create mode 100644 agama/engine/src/test/resources/flows/org.gluu.flow3 create mode 100644 agama/engine/src/test/resources/log4j2-test.xml create mode 100644 agama/engine/src/test/resources/templates/custom/printConfigs.ftlh create mode 100644 agama/engine/src/test/resources/templates/f1/index.ftl create mode 100644 agama/engine/src/test/resources/templates/f1/index2.ftl create mode 100644 agama/engine/src/test/resources/templates/hello/index.ftlh create mode 100644 agama/engine/src/test/resources/templates/login.ftlh create mode 100644 agama/engine/src/test/resources/templates/me/myindex.ftlh create mode 100644 agama/engine/src/test/resources/testng.properties create mode 100644 agama/engine/src/test/resources/testng.xml diff --git a/agama/engine/pom.xml b/agama/engine/pom.xml index 872f92ef4c7..bb9e81908a8 100644 --- a/agama/engine/pom.xml +++ b/agama/engine/pom.xml @@ -26,6 +26,46 @@ + + + profiles/${cfg}/config-agama-test.properties + + + + + src/test/resources + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + + target/test-classes/testng.xml + + + + + + + + + set-configuration-name + + + !cfg + + + + default + + + + @@ -146,12 +186,45 @@ commons-codec + com.esotericsoftware kryo 5.3.0 + + + net.sourceforge.htmlunit + htmlunit + 2.65.1 + test + + + org.testng + testng + test + + + io.jans + agama-inbound + ${jans.version} + test + + + org.json + json + 20220924 + test + + + + org.apache.logging.log4j + log4j-jcl + 2.19.0 + test + + \ No newline at end of file diff --git a/agama/engine/profiles/default/config-agama-test.properties b/agama/engine/profiles/default/config-agama-test.properties new file mode 100644 index 00000000000..64cf8839cdf --- /dev/null +++ b/agama/engine/profiles/default/config-agama-test.properties @@ -0,0 +1,6 @@ +#The URL of your Jans installation +server=https://jgomer2001-guiding-herring.gluu.info + +clientId=1800.5e01b3bb-1f68-4847-b9ba-d5c999a05e33 + +custParamName=customParam1 diff --git a/agama/engine/src/main/java/io/jans/agama/engine/service/ActionService.java b/agama/engine/src/main/java/io/jans/agama/engine/service/ActionService.java index c1886a4069a..7ac0c37583f 100644 --- a/agama/engine/src/main/java/io/jans/agama/engine/service/ActionService.java +++ b/agama/engine/src/main/java/io/jans/agama/engine/service/ActionService.java @@ -105,7 +105,9 @@ public Object callAction(Object instance, String className, String methodName, O throw new InstantiationException(msg); } - logger.debug("Constructor found: {}", constr.toGenericString()); + if (logger.isDebugEnabled()) { + logger.debug("Constructor found: {}", constr.toGenericString()); + } Object[] args = getArgsForCall(constr, arity, rhinoArgs); logger.debug("Creating an instance"); @@ -128,7 +130,9 @@ public Object callAction(Object instance, String className, String methodName, O throw new NoSuchMethodException(msg); } - logger.debug("Method found: {}", javaMethod.toGenericString()); + if (logger.isDebugEnabled()) { + logger.debug("Method found: {}", javaMethod.toGenericString()); + } Object[] args = getArgsForCall(javaMethod, arity, rhinoArgs); logger.debug("Performing method call"); @@ -174,7 +178,7 @@ private Object[] getArgsForCall(Executable javaExec, int arity, Object[] argumen logger.trace("Parameter is a primitive (or wrapped) {}", typeName); javaArgs[i] = arg; - } else if (argClass.isAssignableFrom(Number.class)) { + } else if (Number.class.isAssignableFrom(argClass)) { Object number = PrimitiveUtils.primitiveNumberFrom((Number) arg, paramType); if (number != null) { diff --git a/agama/engine/src/test/java/io/jans/agama/test/BaseTest.java b/agama/engine/src/test/java/io/jans/agama/test/BaseTest.java new file mode 100644 index 00000000000..e3fb8e1cb1c --- /dev/null +++ b/agama/engine/src/test/java/io/jans/agama/test/BaseTest.java @@ -0,0 +1,183 @@ +package io.jans.agama.test; + +import com.gargoylesoftware.htmlunit.BrowserVersion; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.WebClientOptions; +import com.gargoylesoftware.htmlunit.WebResponse; +import com.gargoylesoftware.htmlunit.html.DomElement; +import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlPage; + +import io.jans.inbound.oauth2.CodeGrantUtil; +import io.jans.inbound.oauth2.OAuthParams; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.net.URISyntaxException; +import java.net.URLEncoder; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.json.JSONObject; +import org.testng.ITestContext; +import org.testng.annotations.BeforeSuite; + +import static java.nio.charset.StandardCharsets.UTF_8; + +//import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class BaseTest { + + private static String AGAMA_ACR = "agama"; + private Map map = null; + + Logger logger = LogManager.getLogger(getClass()); + WebClient client = null; + + BaseTest() { + + client = new WebClient(BrowserVersion.CHROME); + WebClientOptions options = client.getOptions(); + + options.setThrowExceptionOnFailingStatusCode(false); + //prevents the finish page to autosubmit the POST to AS's postlogin endpoint + options.setJavaScriptEnabled(false); + + } + + @BeforeSuite + public void init(ITestContext context) throws IOException { + + String propertiesFile = context.getCurrentXmlTest().getParameter("propertiesFile"); + Properties prop = new Properties(); + prop.load(Files.newBufferedReader(Paths.get(propertiesFile), UTF_8)); + + map = new Hashtable<>(); + //do not bother about empty keys... but + //If a value is found null, this will throw a NPE since we are using a Hashtable + prop.forEach((key, value) -> map.put(key.toString(), value.toString())); + context.getSuite().getXmlSuite().setParameters(map); + + } + + String authzRequestUrl(String flowQName, Map inputs) { + + OAuthParams p = new OAuthParams(); + p.setAuthzEndpoint(map.get("authzEndpoint")); + p.setClientId(map.get("clientId")); + p.setRedirectUri(map.get("redirectUri")); + p.setScopes(Collections.singletonList("openid")); + + String queryParam = URLEncoder.encode(map.get("custParamName"), UTF_8); + + StringBuilder builder = new StringBuilder(flowQName); + if (inputs != null) { + JSONObject jo = new JSONObject(inputs); + builder.append("-").append(jo.toString()); + } + + Map custParams = new HashMap<>(); + custParams.put("acr_values", AGAMA_ACR); + custParams.put(queryParam, builder.toString()); + p.setCustParamsAuthReq(custParams); + + String url = null; + CodeGrantUtil grant = new CodeGrantUtil(p); + + try { + url = grant.makeAuthzRequest().getFirst(); + logger.debug("Authentication request built is: {}", url); + } catch (URISyntaxException e) { + fail(e.getMessage(), e); + } + return url; + + } + + HtmlPage launch(String flowQName, Map parameters) { + + //Generate an authn request and launch it in the htmlUnit browser + String url = authzRequestUrl(flowQName, parameters); + logger.info("Starting flow {}", flowQName); + try { + Page p = client.getPage(url); + + //Check it is an ok web page + assertTrue(p.isHtmlPage(), "Not an html page"); + assertOK(p); + return (HtmlPage) p; + + } catch (IOException e) { + fail(e.getMessage(), e); + return null; + } + + } + + void validateFinishPage(HtmlPage page, boolean success) { + + assertOK(page); + //check we are effectively at the finish page + String title = page.getTitleText().toLowerCase(); + + if (success) { + assertTrue(title.contains("redirect"), "'redirect' word not found in page title"); + + List forms = page.getForms(); + assertEquals(forms.size(), 1, "Page should have one and only one form"); + + HtmlForm form = forms.get(0); + assertTrue(form.getActionAttribute().contains("postlogin"), "Form does not have the expected action attribute"); + assertEquals(form.getMethodAttribute().toLowerCase(), "post", "Form does not use POST"); + + } else { + + assertTrue(title.contains("error"), "'error' word not found in page title"); + + String text = page.getVisibleText().toLowerCase(); + assertTrue(text.contains("authentication"), "'authentication' word not found in page text"); + assertTrue(text.contains("failed"), "'failed' word not found in page text"); + } + + } + + void assertOK(Page page) { + assertEquals(page.getWebResponse().getStatusCode(), WebResponse.OK); + } + + void assertServerError(Page page) { + assertEquals(page.getWebResponse().getStatusCode(), WebResponse.INTERNAL_SERVER_ERROR); + } + +

P doClick(DomElement el) { + + try { + return el.click(); + } catch (IOException e) { + fail(e.getMessage(), e); + return null; + } + + } + + void typeInInputWithName(HtmlForm form, String name, String text) { + + try { + //See f1/index.ftl + form.getInputByName("something").type(text); + } catch (IOException e) { + fail(e.getMessage(), e); + } + + } + +} \ No newline at end of file diff --git a/agama/engine/src/test/java/io/jans/agama/test/CustomConfigsFlowTest.java b/agama/engine/src/test/java/io/jans/agama/test/CustomConfigsFlowTest.java new file mode 100644 index 00000000000..6e511e5df9b --- /dev/null +++ b/agama/engine/src/test/java/io/jans/agama/test/CustomConfigsFlowTest.java @@ -0,0 +1,64 @@ +package io.jans.agama.test; + +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; +import com.gargoylesoftware.htmlunit.WebResponse; + +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +@org.testng.annotations.Ignore +public class CustomConfigsFlowTest extends BaseTest { + + private static final String QNAME = "io.jans.agama.test.showConfig"; + + @Test + public void withTimeout() { + + HtmlPage page = launchAndWait(10); + //Flow should have timed out now - see flow impl + //The page currently shown may correspond to the Agama timeout template or to + //the mismatch (not found) page in case the cleaner job already wiped the flow execution + + int status = page.getWebResponse().getStatusCode(); + String text = page.getVisibleText().toLowerCase(); + + if (status == WebResponse.OK) { + //See timeout.ftlh + assertTrue(text.contains("took")); + assertTrue(text.contains("more")); + assertTrue(text.contains("expected")); + } else if (status == WebResponse.NOT_FOUND) { + //See mismatch.ftlh + assertTrue(text.contains("not")); + assertTrue(text.contains("found")); + } else { + fail("Unexpected status code " + status); + } + + } + + @Test + public void noTimeout() { + HtmlPage page = launchAndWait(2); + validateFinishPage(page, false); + } + + private HtmlPage launchAndWait(int wait) { + + HtmlPage page = launch(QNAME, null); + try { + Thread.sleep(1000L * wait); + } catch (InterruptedException e) { + fail(e.getMessage(), e); + } + + //click on the "Continue" button + HtmlSubmitInput button = page.getForms().get(0).getInputByValue("Continue"); + return doClick(button); + + } + +} \ No newline at end of file diff --git a/agama/engine/src/test/java/io/jans/agama/test/MathFlowTest.java b/agama/engine/src/test/java/io/jans/agama/test/MathFlowTest.java new file mode 100644 index 00000000000..1d5ebeead10 --- /dev/null +++ b/agama/engine/src/test/java/io/jans/agama/test/MathFlowTest.java @@ -0,0 +1,62 @@ +package io.jans.agama.test; + +import com.gargoylesoftware.htmlunit.html.HtmlPage; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +@org.testng.annotations.Ignore +public class MathFlowTest extends BaseTest { + + private static final String QNAME = "io.jans.agama.test.math"; + + @Test + public void runEmpty() { + HtmlPage page = launch(QNAME, Collections.singletonMap("numbers",Collections.emptyList())); + logger.info("Landed at {}", page.getUrl()); + assertServerError(page); + } + + @Test + public void runRandom() { + + int len = (int) (Math.random() * 10); + List list = new ArrayList<>(); + + for (int i = 0; i < len; i++) { + list.add(1 + (int) (Math.random() * 100)); + } + run(list); + + } + + @Test + public void runFixed1() { + run(Arrays.asList(30, 42, 70, 105)); + } + + @Test + public void runFixed2() { + run(Arrays.asList(6, 12, 22, 27)); + } + + @Test + public void runFixed3() { + run(Arrays.asList(1, 1, 1)); + } + + private void run(List list) { + + HtmlPage page = launch(QNAME, Collections.singletonMap("numbers", list)); + logger.info("Landed at {}", page.getUrl()); + validateFinishPage(page, true); + + } + +} diff --git a/agama/engine/src/test/java/io/jans/agama/test/SaySomething2FlowTest.java b/agama/engine/src/test/java/io/jans/agama/test/SaySomething2FlowTest.java new file mode 100644 index 00000000000..4a8ee169cfa --- /dev/null +++ b/agama/engine/src/test/java/io/jans/agama/test/SaySomething2FlowTest.java @@ -0,0 +1,57 @@ +package io.jans.agama.test; + +import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +@org.testng.annotations.Ignore +public class SaySomething2FlowTest extends BaseTest { + + private static final String QNAME = "org.gluu.flow1"; + + @Test + public void something() { + HtmlPage page = run("Rosamaria Montibeller"); + validateFinishPage(page, true); + } + + @Test + public void nothing() { + HtmlPage page = run(null); + validateFinishPage(page, false); + } + + private HtmlPage run(String text) { + + HtmlPage page = launch(QNAME, null); + + //click on the "Continue" button + HtmlSubmitInput button = page.getForms().get(0).getInputByValue("Continue"); + page = doClick(button); + + assertOK(page); + assertTrue(page.getVisibleText().contains("Gluu")); //see f1/*.ftl + + HtmlForm form = page.getForms().get(0); + if (text != null) { + //See f1/index.ftl + typeInInputWithName(form, "something", text); + } + + //click on the "Continue" button + button = form.getInputByValue("Continue"); + return doClick(button); + + } + +} diff --git a/agama/engine/src/test/java/io/jans/agama/test/SaySomething3FlowTest.java b/agama/engine/src/test/java/io/jans/agama/test/SaySomething3FlowTest.java new file mode 100644 index 00000000000..1edc5ec8723 --- /dev/null +++ b/agama/engine/src/test/java/io/jans/agama/test/SaySomething3FlowTest.java @@ -0,0 +1,40 @@ +package io.jans.agama.test; + +import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +@org.testng.annotations.Ignore +public class SaySomething3FlowTest extends BaseTest { + + private static final String QNAME = "org.gluu.flow3"; + + @Test + public void test() { + HtmlPage page = launch(QNAME, null); + + //click on the "Go" button + HtmlSubmitInput button = page.getForms().get(0).getInputByValue("Go"); + page = doClick(button); + + assertOK(page); + assertTrue(page.getVisibleText().contains("Agama")); //see me/myindex.ftl and f1/index2.ftl + + button = page.getForms().get(0).getInputByValue("Continue"); + page = doClick(button); + + validateFinishPage(page, false); + + } + +} \ No newline at end of file diff --git a/agama/engine/src/test/java/io/jans/agama/test/SaySomethingFlowTest.java b/agama/engine/src/test/java/io/jans/agama/test/SaySomethingFlowTest.java new file mode 100644 index 00000000000..509a7f9f17a --- /dev/null +++ b/agama/engine/src/test/java/io/jans/agama/test/SaySomethingFlowTest.java @@ -0,0 +1,59 @@ +package io.jans.agama.test; + +import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +@org.testng.annotations.Ignore +public class SaySomethingFlowTest extends BaseTest { + + private static final String QNAME = "org.gluu.flow2"; + + @Test + public void nothing() { + HtmlPage page = run(null, null); + validateFinishPage(page, false); + } + + @Test + public void NoOnesomething() { + HtmlPage page = run(null, "Jans over Gluu"); + validateFinishPage(page, true); + } + + @Test + public void someOnesomething() { + HtmlPage page = run("jgomer2001", "I like CE"); + validateFinishPage(page, true); + } + + private HtmlPage run(String name, String text) { + + boolean nameEmpty = name == null; + HtmlPage page = launch(QNAME, nameEmpty ? null : Collections.singletonMap("val", name)); + + if (!nameEmpty) assertTrue(page.getVisibleText().contains(name)); + + HtmlForm form = page.getForms().get(0); + + if (text != null) { + //See f1/index.ftl + typeInInputWithName(form, "something", text); + } + //click on the "Continue" button + HtmlSubmitInput button = form.getInputByValue("Continue"); + return doClick(button); + + } + +} \ No newline at end of file diff --git a/agama/engine/src/test/java/io/jans/agama/test/UidOnlyAuthTest.java b/agama/engine/src/test/java/io/jans/agama/test/UidOnlyAuthTest.java new file mode 100644 index 00000000000..0c7720f5afa --- /dev/null +++ b/agama/engine/src/test/java/io/jans/agama/test/UidOnlyAuthTest.java @@ -0,0 +1,42 @@ +package io.jans.agama.test; + +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +@org.testng.annotations.Ignore +public class UidOnlyAuthTest extends BaseTest { + + private static final String QNAME = "io.jans.agama.test.auth.uidOnly"; + + @BeforeClass + public void enableJS() { + client.getOptions().setJavaScriptEnabled(true); + } + + @Test + public void randUid() { + HtmlPage page = run("" + Math.random()); + validateFinishPage(page, false); + } + + private HtmlPage run(String uid) { + + HtmlPage page = launch(QNAME, Collections.singletonMap("uid", uid)); + //click on the "Continue" button + HtmlSubmitInput button = page.getForms().get(0).getInputByValue("Continue"); + return doClick(button); + + } + +} \ No newline at end of file diff --git a/agama/engine/src/test/resources/flows/io.jans.agama.test.auth.uidOnly b/agama/engine/src/test/resources/flows/io.jans.agama.test.auth.uidOnly new file mode 100644 index 00000000000..6397e9d13f3 --- /dev/null +++ b/agama/engine/src/test/resources/flows/io.jans.agama.test.auth.uidOnly @@ -0,0 +1,10 @@ +//This flow is based on the "hello world" flow found in Agama docs (quick-start quide) +Flow io.jans.agama.test.auth.uidOnly + Basepath "hello" + Inputs uid + +in = { name: uid } +RRF "index.ftlh" in + +Log "Done!" +Finish uid diff --git a/agama/engine/src/test/resources/flows/io.jans.agama.test.math b/agama/engine/src/test/resources/flows/io.jans.agama.test.math new file mode 100644 index 00000000000..22df7423929 --- /dev/null +++ b/agama/engine/src/test/resources/flows/io.jans.agama.test.math @@ -0,0 +1,54 @@ +//This flow is used to test some Java calls. It does not make use of idiomatic Agama. There is no UI either here +Flow io.jans.agama.test.math + Basepath "" + Inputs numbers //A non-empty list of positive integers + +// 1. Find the smallest +small = Call java.util.Collections#min numbers +Log "min element is" small + + +// 2. Concat them all in a string +strings = [ ] +Iterate over numbers using n + i = strings.length + strings[i] = Call java.lang.Integer#toString n + +cat = Call java.lang.String#join "" strings +Log "concatenation is" cat + + +// 3. Sumation (with Repeat) +s = 0 +Repeat numbers.length times max + i = idx[0] + s = Call java.lang.Math#addExact s numbers[i] + +Log "sumation is" s + + +// 4. Find if they are mutually relatively prime (no integer divides them all) +When numbers.length is 1 or small is 1 + Finish true + +divisor = 1 +small = Call java.lang.Math#decrementExact small + +Repeat small times max + divisor = Call java.lang.Math#incrementExact divisor + k = 0 + + //Try to divide the numbers by 2, 3, ... small+1 + Iterate over numbers using n + modulus = Call java.lang.Math#floorMod n divisor + Quit When modulus is 0 + k = Call java.lang.Math#incrementExact k + + Quit When k is numbers.length + +When k is numbers.length + Log "% are relative primes" numbers +Otherwise + Log "All numbers can be divided by" divisor + +Finish true diff --git a/agama/engine/src/test/resources/flows/io.jans.agama.test.showConfig b/agama/engine/src/test/resources/flows/io.jans.agama.test.showConfig new file mode 100644 index 00000000000..616d4dcf80c --- /dev/null +++ b/agama/engine/src/test/resources/flows/io.jans.agama.test.showConfig @@ -0,0 +1,8 @@ +Flow io.jans.agama.test.showConfig + Basepath "" + Timeout 10 seconds + Configs conf + +RRF "printConfigs.ftlh" conf + +Finish false \ No newline at end of file diff --git a/agama/engine/src/test/resources/flows/org.gluu.flow1 b/agama/engine/src/test/resources/flows/org.gluu.flow1 new file mode 100644 index 00000000000..206628a0085 --- /dev/null +++ b/agama/engine/src/test/resources/flows/org.gluu.flow1 @@ -0,0 +1,11 @@ +//This flow appeared originally in the demos of the authentication-trees project +Flow org.gluu.flow1 + Basepath "f1" + +data = RRF "index.ftl" + +data = Trigger org.gluu.flow2 data.secret[0] + +Log "@debug Subflow finished successfully?" data.success + +Finish data diff --git a/agama/engine/src/test/resources/flows/org.gluu.flow2 b/agama/engine/src/test/resources/flows/org.gluu.flow2 new file mode 100644 index 00000000000..e3bac09e4dd --- /dev/null +++ b/agama/engine/src/test/resources/flows/org.gluu.flow2 @@ -0,0 +1,14 @@ +//This flow appeared originally in the demos of the authentication-trees project +Flow org.gluu.flow2 + Basepath "f1" + Inputs val + +x = {value: val} +data = RRF "index2.ftl" x + +When data.something is "" + Log "There was a missing value" + ret = { success: false, error: "You forgot something!" } + Finish ret +Otherwise + Finish true diff --git a/agama/engine/src/test/resources/flows/org.gluu.flow3 b/agama/engine/src/test/resources/flows/org.gluu.flow3 new file mode 100644 index 00000000000..24d7e8e06c9 --- /dev/null +++ b/agama/engine/src/test/resources/flows/org.gluu.flow3 @@ -0,0 +1,7 @@ +Flow org.gluu.flow3 + Basepath "me" + +obj = Trigger org.gluu.flow1 + Override templates "f1/index.ftl" "myindex.ftlh" + +Finish obj diff --git a/agama/engine/src/test/resources/log4j2-test.xml b/agama/engine/src/test/resources/log4j2-test.xml new file mode 100644 index 00000000000..018859bed4c --- /dev/null +++ b/agama/engine/src/test/resources/log4j2-test.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/agama/engine/src/test/resources/templates/custom/printConfigs.ftlh b/agama/engine/src/test/resources/templates/custom/printConfigs.ftlh new file mode 100644 index 00000000000..5193bcbe4c9 --- /dev/null +++ b/agama/engine/src/test/resources/templates/custom/printConfigs.ftlh @@ -0,0 +1,14 @@ + + + + +<#!-- rendering this page crashes if neither joke nor phrase are defined --> +

${joke} +

${phrase} + +

+ +
+ + + diff --git a/agama/engine/src/test/resources/templates/f1/index.ftl b/agama/engine/src/test/resources/templates/f1/index.ftl new file mode 100644 index 00000000000..4ada4213bd3 --- /dev/null +++ b/agama/engine/src/test/resources/templates/f1/index.ftl @@ -0,0 +1,14 @@ +<#ftl output_format="HTML"> + + + +

Hi I'm Flow 1!

+ +
+ + + +
+ + + diff --git a/agama/engine/src/test/resources/templates/f1/index2.ftl b/agama/engine/src/test/resources/templates/f1/index2.ftl new file mode 100644 index 00000000000..3befc0da296 --- /dev/null +++ b/agama/engine/src/test/resources/templates/f1/index2.ftl @@ -0,0 +1,15 @@ +<#ftl output_format="HTML"> + + + +

Hi I'm Flow 2!

+

${value!""}

+ +
+