{"id":19398690,"url":"https://github.com/arquillian/arquillian-cube-q","last_synced_at":"2025-08-20T17:17:32.240Z","repository":{"id":49239101,"uuid":"47149635","full_name":"arquillian/arquillian-cube-q","owner":"arquillian","description":"Fault injection and chaos testing all in one, sweet DSL.","archived":false,"fork":false,"pushed_at":"2021-06-22T11:15:21.000Z","size":269,"stargazers_count":12,"open_issues_count":17,"forks_count":6,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-04-03T00:32:10.259Z","etag":null,"topics":["chaos-monkey","docker","java","jvm","testing"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arquillian.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-11-30T22:20:28.000Z","updated_at":"2024-08-27T15:59:25.000Z","dependencies_parsed_at":"2022-09-05T11:41:41.173Z","dependency_job_id":null,"html_url":"https://github.com/arquillian/arquillian-cube-q","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arquillian%2Farquillian-cube-q","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arquillian%2Farquillian-cube-q/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arquillian%2Farquillian-cube-q/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arquillian%2Farquillian-cube-q/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arquillian","download_url":"https://codeload.github.com/arquillian/arquillian-cube-q/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250578097,"owners_count":21453240,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chaos-monkey","docker","java","jvm","testing"],"created_at":"2024-11-10T11:06:49.291Z","updated_at":"2025-04-24T06:31:30.614Z","avatar_url":"https://github.com/arquillian.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"= Introduction\n:numbered:\n:sectlink:\n:sectanchors:\n:sectid:\n:source-language: java\n:source-highlighter: coderay\n:sectnums:\n:icons: font\n:toc: left\n:toclevels: 3\n\nimage:https://travis-ci.org/arquillian/arquillian-cube-q.svg?branch=master[\"Build Status\", link=\"https://travis-ci.org/arquillian/arquillian-cube-q\"]\n\nUsually when we talk about writing tests, the first thing that comes to your mind is some kind of static test where you send an input and you expect an output.\nFor example you send a wrong parameter to a REST service, and you expect that it returns an error message/status code.\n\nBut usually applications runs more time than the amount of time it takes to execute all tests. Probably days or months until you update it.\nAnd during this time, things happen, for example network starts to go slow, a unknown process eats all CPU or if you are using Docker, a container dies.\nSo you can see that when you run your application for a long time some kind of *chaos* might appear.\n\nThe question is, are you sure your application deals correctly with these situations?\nYou can test it manually, but if you want to apply CI/CD approach then you need some automatic way to execute them.\n\nAnd this is where Arquillian Cube Q helps you.\nArquillian Cube Q is an extension of Arquillian Cube (https://github.com/arquillian/arquillian-cube) that allows you to write chaos tests.\nSince Arquillian Cube Q is an extension of Cube, it relies on Docker to execute them.\n\n== Chaos\n\nimage::http://www.starshipnivan.com/blog/wp-content/uploads/2010/10/De-Lancie-crop.jpg[]\n\nThere are several level of chaos that you might test, from network chaos (latency, bandwidth limitation, ...) to operative system chaos (cpu burn, io burn, dill disk, ...).\n\nArquillian Q as all the Arquillian project, it reuses existing chaos frameworks by integrating them into Arquillian philosophy.\nLet's see what is supported:\n\n=== Network Chaos\n\nTo do *network chaos* Arquillian Q integrates with Toxiproxy project (https://github.com/Shopify/toxiproxy).\nToxiproxy is a framework for simulating network conditions.\nIt is a TCP proxy that intercepts communication between two endpoints and adds some chaos before reaching the real endpoint.\n\nToxiproxy supports next toxics:\n\nlatency:: Add a delay to all data going through the proxy. The delay is equal to latency +/- jitter.\ndown:: Bringing a service down\nbandwidth:: Limit a connection to a maximum number of kilobytes per second.\nslow close:: Delay the TCP socket from closing until delay has elapsed.\ntimeout:: Stops all data from getting through, and closes the connection after timeout. If timeout is 0, the connection won't close, and data will be delayed until the toxic is removed.\nslicer:: Slices TCP data up into small bits, optionally adding a delay between each sliced \"packet\".\n\nArquillian Q supports Toxiproxy by registering as docker container toxiproxy and then inspecting the cube definitions (in _cube_ format or _docker-compose_ format) and automatically redirect links to toxiproxy.\n\nAs an example:\n\nContainerA -link-\u003e ContainerB\n\nis converted to:\n\nContainerA -link-\u003e ToxiproxyContainer -link-\u003e ContainerB\n\nAfter this you are able to program some toxics to Toxiproxy and execute the test.\n\n==== Adding Dependency\n\nArquillian Q Toxiproxy is only a jar deployed to Maven central:\n\n[source, xml]\n.pom.xml\n----\n\u003cdependencyManagement\u003e\n  \u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003eorg.jboss.arquillian\u003c/groupId\u003e\n      \u003cartifactId\u003earquillian-bom\u003c/artifactId\u003e\n      \u003cversion\u003e${version.arquillian_core}\u003c/version\u003e\n      \u003ctype\u003epom\u003c/type\u003e\n      \u003cscope\u003eimport\u003c/scope\u003e\n    \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n\u003c/dependencyManagement\u003e\n\n\u003cdependencies\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.arquillian.cube.q\u003c/groupId\u003e\n    \u003cartifactId\u003earquillian-cube-q-toxic\u003c/artifactId\u003e\n    \u003cscope\u003etest\u003c/scope\u003e\n    \u003cversion\u003e${version.arquillian_q}\u003c/version\u003e\n  \u003c/dependency\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.jboss.arquillian.junit\u003c/groupId\u003e\n    \u003cartifactId\u003earquillian-junit-standalone\u003c/artifactId\u003e\n    \u003cscope\u003etest\u003c/scope\u003e\n  \u003c/dependency\u003e\n  \u003cdependency\u003e\n      \u003cgroupId\u003ejunit\u003c/groupId\u003e\n      \u003cartifactId\u003ejunit\u003c/artifactId\u003e\n  \u003c/dependency\u003e\n\u003c/dependencies\u003e\n----\n\nIMPORTANT: Notice that instead of registering `arquillian-junit-container` as you usually do in Arquillian test, you are using `arquillian-junit-standalone`. This is because it has no sense to use in these kind of tests microdeployments feature (method annotated with `@Deployment`).\n\n==== Configuration\n\nYou don't need to configure anything else from the point of view of Q apart from Cube configuration file.\n\n[source, xml]\n.arquillian.xml\n----\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003carquillian xmlns=\"http://jboss.org/schema/arquillian\"\n            xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n            xsi:schemaLocation=\"\n        http://jboss.org/schema/arquillian\n        http://jboss.org/schema/arquillian/arquillian_1_0.xsd\"\u003e\n\n  \u003cextension qualifier=\"docker\"\u003e\n    \u003cproperty name=\"machineName\"\u003edev\u003c/property\u003e\n    \u003cproperty name=\"dockerContainers\"\u003e\n        hw:\n          image: lordofthejars/helloworld\n          env: [\"CATALINA_OPTS=-Djava.security.egd=file:/dev/./urandom\"]\n          portBindings: [8081-\u003e8080/tcp]\n          links:\n            - pingpong:pingpong\n\n        pingpong:\n          image: jonmorehouse/ping-pong\n          exposedPorts: [8080/tcp]\n    \u003c/property\u003e\n  \u003c/extension\u003e\n\n\u003c/arquillian\u003e\n----\n\nIn this case container `helloworld` is connecting to `pingpong` container.\n\n==== Test\n\nThen the test looks like:\n\n[source, java]\n----\n@RunWith(Arquillian.class)\npublic class ToxicFuntionalTestCase {\n\n  @ArquillianResource\n  private NetworkChaos networkChaos; // \u003c1\u003e\n\n  @HostIp\n  private String ip;\n\n  @Test\n  public void shouldAddLatency() throws Exception {\n    networkChaos.on(\"pingpong\", 8080).latency(latencyInMillis(4000)) // \u003c2\u003e\n      .exec(() -\u003e { // \u003c3\u003e\n\n        URL url = new URL(\"http://\" + ip + \":\" + 8081 + \"/hw/HelloWorld\");\n        final long l = System.currentTimeMillis();\n        String response = IOUtil.asString(url.openStream());\n        System.out.println(response);\n        System.out.println(\"Time:\" + (System.currentTimeMillis() - l));\n        // assertions\n\n    }); // \u003c4\u003e\n  }\n}\n----\n\u003c1\u003e Enrich the test with `NetworkChaos` instance to communicate with _Toxiproxy_.\n\u003c2\u003e Adds a latency of 4 seconds when communication is done to `pingpong` container through port _8080_.\n\u003c3\u003e Executes test logic. Notice that the execution time will be greater than 4 seconds.\n\u003c4\u003e After callback executions, toxics are reseted.\n\nTIP: `exec` method also supports you pass how many times do you want to execute the test: `networkChaos.on(\"pingpong\", 8080).latency(latencyInMillis(4000)).exec(times(2), () -\u003e {}` or for example the amount of time you want to keep executing the test `Q.on(\"pingpong\", 8080).exec(during(15, TimeUnit.SECONDS), () -\u003e {}`.\n\nYou can see full example at: https://github.com/arquillian/arquillian-cube-q/tree/master/ftest-toxic\n\n==== Adding some randomness\n\nSome of the discrete values set in toxics such as `slowClose`, `bandwidth`, `timeout` or `slice` can be randomized using mathematical distributions.\nAt this time two distributions are supported:\n\n* Uniform Distribution: Distribution that returns values uniformally distributed across a range. You can read about this distribution at https://en.wikipedia.org/wiki/Discrete_uniform_distribution\n* LogNormal Distribution: Returns log normally distributed values. You can use this website https://www.wolframalpha.com/input/?i=lognormaldistribution%28log%2890%29%2C+0.1%29 to play with the values.\nYou can read more about this distribution at https://en.wikipedia.org/wiki/Log-normal_distribution\n\nFor example, this is how you can randomize the latency:\n\n[source, java]\n----\nnetworkChaos.on(\"pingpong\", 8080)\n            .latency(logNormalLatencyInMillis(2000, 0.3))\n            .exec(times(2), () -\u003e {\n\n     URL url = new URL(\"http://\" + ip + \":\" + 8081 + \"/hw/HelloWorld\");\n     final long l = System.currentTimeMillis();\n     String response = IOUtil.asString(url.openStream());\n     System.out.println(response);\n     System.out.println(\"Time:\" + (System.currentTimeMillis() - l));\n\n});\n----\n\nIn the configuration above, latency times are distributed in using a log normal distribution with median of 2 seconds and 0.3 as sigma value.\nThen for each iteration of the test, a new value is calculated and send to toxiproxy.\n\n==== Binding Ports Chaos\n\nSometimes you don't want to add chaos between containers but in binding ports.\nThat is adding chaos to the communication between host and containers.\nThis is really useful in cases when you want to test what's happening to your frontend application (javascript) when there is some chaos.\n\nAssuming that A has a port binding, something like:\n\nA -\u003e B\n\nis converted to:\n\nProxy -\u003e A -\u003e B\n\nWhere A has no port binding anymore but only exposed ports and it is the Proxy who has the port binding.\n\nTo use this just configure next parameter in `arquillian.xml` file:\n\n[source, xml]\n.arquillian.xml\n----\n\u003cextension qualifier=\"networkChaos\"\u003e\n    \u003cproperty name=\"toxifyPortBinding\"\u003etrue\u003c/property\u003e\n\u003c/extension\u003e\n----\n\nIMPORTANT: By defult this flag is false, if you set to true then no chaos can be done between containers, only between host and containers.\n\nYou can see an example at: https://github.com/arquillian/arquillian-cube-q/tree/master/ftest-toxic-frontend\n\n=== Container Chaos\n\nTo do *container chaos* Arquillian Q integrates with Pumba project (https://github.com/Shopify/toxiproxy).\nPumba is an application that you run it on every Docker host, in your cluster and it, once in a while, will \"randomly\" stop running containers, matching specified name/s or name patterns.\nYou can even specify the signal, that will be sent to “kill” the container.\n\nIt supports:\n\n* Stop a container.\n* Remove a container.\n* Kill a container process with signal.\n\nArquillian Q will register a Pumba container inside the configured docker host you set in Arquillian Q.\n\n==== Adding Dependency\n\nArquillian Q Pumba is only a jar file deployed in Maven central.\n\n[source, xml]\n.pom.xml\n----\n\u003cdependencyManagement\u003e\n  \u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003eorg.jboss.arquillian\u003c/groupId\u003e\n      \u003cartifactId\u003earquillian-bom\u003c/artifactId\u003e\n      \u003cversion\u003e${version.arquillian_core}\u003c/version\u003e\n      \u003ctype\u003epom\u003c/type\u003e\n      \u003cscope\u003eimport\u003c/scope\u003e\n    \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n\u003c/dependencyManagement\u003e\n\n\u003cdependencies\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.arquillian.cube.q\u003c/groupId\u003e\n    \u003cartifactId\u003earquillian-cube-q-pumba\u003c/artifactId\u003e\n    \u003cscope\u003etest\u003c/scope\u003e\n    \u003cversion\u003e${version.arquillian_q}\u003c/version\u003e\n  \u003c/dependency\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.jboss.arquillian.junit\u003c/groupId\u003e\n    \u003cartifactId\u003earquillian-junit-standalone\u003c/artifactId\u003e\n    \u003cscope\u003etest\u003c/scope\u003e\n  \u003c/dependency\u003e\n  \u003cdependency\u003e\n      \u003cgroupId\u003ejunit\u003c/groupId\u003e\n      \u003cartifactId\u003ejunit\u003c/artifactId\u003e\n  \u003c/dependency\u003e\n\u003c/dependencies\u003e\n----\n\nIMPORTANT: Notice that instead of registering `arquillian-junit-container` as you usually do in Arquillian test, you are using `arquillian-junit-standalone`. This is because it has no sense to use in these kind of tests microdeployments feature (method annotated with `@Deployment`).\n\n==== Configuration\n\nYou don't need to configure anything else from the point of view of Q apart from Cube configuration file.\n\n[source, xml]\n.arquillian.xml\n----\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003carquillian xmlns=\"http://jboss.org/schema/arquillian\"\n            xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n            xsi:schemaLocation=\"\n        http://jboss.org/schema/arquillian\n        http://jboss.org/schema/arquillian/arquillian_1_0.xsd\"\u003e\n\n  \u003cextension qualifier=\"docker\"\u003e\n    \u003cproperty name=\"machineName\"\u003edev\u003c/property\u003e\n    \u003cproperty name=\"dockerContainers\"\u003e\n      pingpong:\n        image: jonmorehouse/ping-pong\n        exposedPorts: [8080/tcp]\n\n      pingpong2:\n        image: jonmorehouse/ping-pong\n        exposedPorts: [8080/tcp]\n    \u003c/property\u003e\n  \u003c/extension\u003e\n\n\u003c/arquillian\u003e\n----\n\nIn this case we are defining two instances of same image.\n\n==== Test\n\nThen the test looks like:\n\n[source, java]\n----\n@RunWith(Arquillian.class)\npublic class PumbaFunctionalTestCase {\n\n  @ArquillianResource // \u003c1\u003e\n  ContainerChaos containerChaos;\n\n  @ArquillianResource\n  DockerClient dockerClient; // \u003c2\u003e\n\n  @Test\n  public void shouldKillContainers() throws Exception {\n    containerChaos\n            .onCubeDockerHost()\n                .killRandomly( // \u003c3\u003e\n                        ContainerChaos.ContainersType.regularExpression(\"^pingpong\"), // \u003c4\u003e\n                        ContainerChaos.IntervalType.intervalInSeconds(4), // \u003c5\u003e\n                        ContainerChaos.KillSignal.SIGTERM\n                )\n            .exec(); // \u003c6\u003e\n\n        final List\u003cContainer\u003e containers = dockerClient.listContainersCmd().exec();\n        //Pumba container is not killed by itself\n        assertThat(containers).hasSize(1);\n\n    }\n\n}\n----\n\u003c1\u003e Enrich test with container chaos\n\u003c2\u003e Enrich test with `DockerClient` class to communicate with DockerHost in test\n\u003c3\u003e Kills randomly one by one containers\n\u003c4\u003e Kills only containers with name starting with _pingpong_\n\u003c5\u003e Time to wait between kill another container\n\u003c6\u003e Starts Pumba. In this case no callback used.\n\nAs happens in *Network Chaos* you can also specify test as callback and specify times to execute the test or the duration.\n\nYou can see full example at: https://github.com/arquillian/arquillian-cube-q/tree/master/ftest-pumba\n\n=== Operative System Chaos\n\n\nTo do *operative system chaos* Arquillian Q uses some modified version scripts of Netflix Simian Army project ().\nSome scripts have been modified to have sense into Docker world instead of AWS world.\n\n\nIt supports:\n\n* Block a port using `iptables` command.\n* Burn CPU using `dd` command. That is putting CPU to 100%.\n* Burn IO using `dd` comomand.\n* Fill disk with `dd` command.\n* Kill process using `pkill` command.\n* Null Route using `ip` command.\n\nIMPORTANT: Scripts are executed inside the container. This means that the command used in the script must be installed inside the container. Some images might contain them, others not.\n\nTIP: Making chaos with scripts means a whole new kind of possibilities since the only barrier is the commands you need to execute them. Please feel free to contribute with your own scripts.\n\n==== Adding Dependency\n\nArquillian Simian Army is only a jar file deployed in Maven central.\n\n[source, xml]\n.pom.xml\n----\n\u003cdependencyManagement\u003e\n  \u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003eorg.jboss.arquillian\u003c/groupId\u003e\n      \u003cartifactId\u003earquillian-bom\u003c/artifactId\u003e\n      \u003cversion\u003e${version.arquillian_core}\u003c/version\u003e\n      \u003ctype\u003epom\u003c/type\u003e\n      \u003cscope\u003eimport\u003c/scope\u003e\n    \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n\u003c/dependencyManagement\u003e\n\n\u003cdependencies\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.arquillian.cube.q\u003c/groupId\u003e\n    \u003cartifactId\u003earquillian-cube-q-simianarmy\u003c/artifactId\u003e\n    \u003cscope\u003etest\u003c/scope\u003e\n    \u003cversion\u003e${version.arquillian_q}\u003c/version\u003e\n  \u003c/dependency\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.jboss.arquillian.junit\u003c/groupId\u003e\n    \u003cartifactId\u003earquillian-junit-standalone\u003c/artifactId\u003e\n    \u003cscope\u003etest\u003c/scope\u003e\n  \u003c/dependency\u003e\n  \u003cdependency\u003e\n      \u003cgroupId\u003ejunit\u003c/groupId\u003e\n      \u003cartifactId\u003ejunit\u003c/artifactId\u003e\n  \u003c/dependency\u003e\n\u003c/dependencies\u003e\n----\n\nIMPORTANT: Notice that instead of registering `arquillian-junit-container` as you usually do in Arquillian test, you are using `arquillian-junit-standalone`. This is because it has no sense to use in these kind of tests microdeployments feature (method annotated with `@Deployment`).\n\n==== Test\n\nThen the test looks like:\n\n[source, java]\n----\n@RunWith(Arquillian.class)\npublic class SimianArmyFunctionalTestCase {\n\n    @ArquillianResource // \u003c1\u003e\n    OperativeSystemChaos operativeSystemChaos;\n\n    @HostIp\n    String dockerHost;\n\n    @HostPort(containerName = \"pingpong \", value = 8080)\n    int port;\n\n    @Test(expected = Exception.class) @Ignore //Running this test in same machine makes everything screwed\n    public void shouldExecuteBurnCpuChaos() throws Exception {\n        operativeSystemChaos.on(\"pingpong\") // \u003c2\u003e\n            .burnCpu(singleCpu()) // \u003c3\u003e\n            .exec(); // \u003c4\u003e\n\n        //.....\n\n    }\n----\n\u003c1\u003e Enrich test with operative system chaos\n\u003c2\u003e Sets the container to set the chaos\n\u003c3\u003e Sets burn cpu chaos as if the system had only one cpu\n\u003c4\u003e Starts the burn cpu script. In this case no callback used\n\nAs happens in *Network Chaos* you can also specify test as callback and specify times to execute the test or the duration.\n\nYou can see full example at: https://github.com/arquillian/arquillian-cube-q/tree/master/ftest-simianarmy\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farquillian%2Farquillian-cube-q","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farquillian%2Farquillian-cube-q","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farquillian%2Farquillian-cube-q/lists"}