This is Code Defenders, a mutation testing game. Publicly available at code-defenders.org.
Code Defenders requires a
config.properties file for initial setup, building and deployment. All necessary configuration properties are listed. The file needs to be in the project root directory.
config.properties can hold confidential configuration data, so please do not include it into the repository.
Following properties are required:
# The main Code Defenders folder. E.g. /var/lib/codefenders data.dir=... # Location of Ant command ant.home=... # MySQL database URL and credential to access it db.url=... db.username=... db.password=... # Tomcat credentials with <manager-script> role. tomcat.username=... tomcat.password=... # Deployment URL ,looks like http://<domain>:<port>/manager/text tomcat.url=... # Path to Tomcat executable tomcat.path=...
config.properties requires a URL to an existing database. The database needs to be created before installation.
To install Code Defenders automatically, execute the
setup.sh script under the
installation folder passing the
config.properties file as input.
cd installation ./setup.sh ../config.properties
The script performs a basic availability check of required software. The data directory folder structure and database schema are created. All the required dependencies and files are automatically downloaded.
If any installation step fails, the installation process aborts and prints an error message.
Note: Depending on the chosen data directory and Tomcat installation in place, root access may be necessary to create required folders. Similarly, additional configurations might be needed. For example, if Tomcat runs under a different user, data directory accesses and ownership might be need to be adjusted.
Note: Code Defenders also requires that its MySQL user owns specific privileges to create databases and tables. Additionally, it requires INDEX privileges, otherwise the installation fails with an error message similar to:
ERROR 1142 (42000) at line 183: INDEX command denied to user
For deployment, Tomcat requires a user with
manager-script role, which be be configured in
CATALINA_HOME is the Tomcat installation directory).
<role rolename="manager-script"/> <user username="<MY_USER>" password="<MY_USER_PASSWORD>" roles="manager-script"/>
Code Defenders relies on the Tomcat authentication system to identify admin users, who can access protected pages and customize Code Defenders settings.
Access control is enforced through Tomcat using Basic Authentication in the browser.
Adding a tomcat admin can be done by applying the
manager-gui role to a user.
<role rolename="manager-gui"/> <user username="<MY_ADMIN_USER>" password="<MY_ADMIN_PWD>" roles="manager-gui"/>
All system configuration and privileged features are accessible for admin users under the
/admin page. Configurations are organized in three groups:
For successful deployment, both Tomcat and MySQL services must be running. Code Defenders is built and deployed with Maven using the following commands.
To deploy Code Defenders the first time, execute:
mvn clean compile package install war:war tomcat7:deploy -DskipTests
To redeploy instead use:
mvn clean compile package install war:war tomcat7:redeploy -DskipTests
System tests work by deploying Code Defenders inside disposable Docker containers and interacting with it by means of Selenium, which is again, running inside a Docker container. This means that the DATA inside the DB are lost after the tests end.
Since we use Docker containers which are not (yet) registered in any Docker public repository, we need to manually build them. Once those are in place, system tests can be run from maven as follows (note that we use the System Test profile
mvn clean compile package war:war integration-test -PST
This command rebuilds and repackages the application using the
[email protected] file. Then, it copies the resulting
.war file in the right folder (
src/test/resources/systemtests/frontend). Finally, it runs all tests, which are annotated with
@Category(SystemTest.class). Each test starts two docker instances for Code Defenders (one for the backend and on one for the front-end) and one docker instance for Selenium.
When containers are ready, the test code send the commands to the Selenium instance which must necessarily run on port 4444. When a test ends, all containers are disposed.
There's few catches. Since we use selenium-standalone we can run ONLY one system test at the time. The alternative (not in place) is to start a selenium-hub.
docker-compose-debug.yml file under
src/test/resources/systemtests. This file contains the configuration to run the debug-enabled selenium container, which opens a VNC port 5900 to which you can connect to (using any VNC client).
Assuming that you have
cd src/test/resources/systemtests/tomcat9-jdk8 docker build -t codedefenders/tomcat:9 . cd ../frontend ./setup-filesystem.sh ./config.properties docker build -t codedefenders/frontend .
Code Defenders can be run as a set of docker containers using the provided docker-compose.yml file. To build and run the HEAD VERSION of Code Defenders which is stored in the Git Hub repo, you can run the following commands:
cd docker docker-compose up
This command will build the required containers by cloning the git repo and by invoking the expected maven commands. As a consequence, the first time you run docker-compose it might take a while.
Note On the console, you will see outputs like:
db_1: mbind: Operation not allowed
You can ignore them.
After all components are started, you can access the application at:
To shutdown the entire application, Ctrl-C the docker-compose process.
Gracefully stopping... (press Ctrl+C again to force) Stopping systemtests_frontend_1 ... done Stopping systemtests_db_1 ... done
We enable scalability by replicating the front-end component of the application and by using a custom nginx load balancer to handle sticky sessions. Currently, the system supports up to 8 concurrent instances of the front-end. Use the scale parameter of docker run to spin off multiple front ends. The following command starts 4 front-end instances:
cd docker docker-compose up --scale=frontend=4
Persistency is achieved using docker volumes. You can see which volumes are available, use the command:
docker volume ls
As long as the docker_datavolume and the docker_dbvolume (names might change) are there, the content of the mysql db and the data folder are persisted. So if you have stopped, and even destroyed, the containers by using the same docker-compose file the data are preserved.
Note If you want to access the content of those volumes, e.g., to backup them, you must spin off a docker container which mounts them.
A minimum of reliability is guaranteed by automatically restarting the container if the fail or are manually stopped (by mistake). Therefore, unless you stop the docker-compose, containers will automatically restart.
Note Restarting the containers might not preserve the user sessions, that is, you users might have to re-login in the system after a crash/restart.
If you need more instances or if you need to customize the deployment, you must update the Docker and various configurations files under the
/docker folder. But at that point your are on your own.
Code Defenders and most of its dependencies are handled via Maven. Code Defenders can also be imported into common IDEs (e.g., IntelliJ and Eclipse).
Code Defenders requires Java 1.8 also to compile the JSP. This is not the default options in many tomcat versions, despite you run tomcat on Java 1.8+.
To enable this feature, you must update the main tomcat's
web.xml file, which is under
Locate the following XML tags:
<servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> ... <load-on-startup>3</load-on-startup> </servlet>
And add the following inside the XML tag `
<init-param> <param-name>compiler</param-name> <param-value>modern</param-value> </init-param> <init-param> <param-name>compilerSourceVM</param-name> <param-value>1.8</param-value> </init-param> <init-param> <param-name>compilerTargetVM</param-name> <param-value>1.8</param-value> </init-param> <init-param> <param-name>suppressSmap</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>fork</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>xpoweredBy</param-name> <param-value>false</param-value> </init-param>
This solution is inspired by and adapted from this solution presented on StackOverflow.
If you are running MySQL 5.7 and the SQL exception reads as follows:
java.sql.SQLException: Cannot create PoolableConnectionFactory (The server time zone value 'CEST' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specific time zone value if you want to utilize time zone support.)
This happens because the newest versions of mysql-connector perform some extra check on your DB and won't let you establish a connection unless everything is correct.
Run the following command to resolve it (until you restart mysql):
mysql -uroot -p SET GLOBAL time_zone = '+1:00';
Use whatever matches your local time zone instead of
You can also fix it for good by updating your mysql configuration.