How to configure PhpStorm, Codeception and Docker to reliably get code coverage - docker

I can not figure out how to reliably configure the parts of my project to get code coverage displayed in PhpStorm.
I am using PhpStorm (EAP), docker (19.03.5-rc1) and docker-compose (1.24.1). I set up my project with a docker-compose.yml that includes a php service (Docker image in2code/php-dev:7.3-fpm which includes xdebug and is based on the official php:7.3-fpm image)
I created a new project with composer and required codeception (3.1.2). I ran the codecption bootstrap, added the coverage settings, created a unit test and ran the while tests suite with coverage. The coverage does not appear in PhpStorm or it does show 0% everywhere. I can not figure out how to configure PhpStorm/Codeception to show the coverage. There are Projects where this works but they are configured to use a Docker image instead of a running docker-compose container.
I tried following remote PHP interpreters:
Remote PHP Interpreter -> Docker -> Image (in2code/php-dev:7.3-fpm)
Remote PHP Interpreter -> Docker -> Image built by docker-compose for this project (cct_php:latest)
Remote PHP Interpreter -> Docker Compose -> service php -> docker-compose exec
Remote PHP Interpreter -> Docker Compose -> service php -> docker-compose run
I created a PHP Test Framework for each interpreter i created above.
I created a Codeception run confgiguration for each Test Framework configuration.
I executed all Codeception run configurations with any combination of (Project Default) PHP CLI Interpreter and other remote interpreters.
The Testing Framework is configured with the correct path to codeception (codeception version is detected by phpstorm) and it holds the path to the codeception.yml file as default configuration file. All run configurations are using the default configuration file from the test framework configuration.
I also tried to enable coverage in the root codeception.yml file, tried work_dir: /app and remote: false.
None of these attempts generated a code coverage that was displayed in PhpStorm.
Projects where code coverage works are configured with PHP Remote Interpreter Docker Image (docker-compose built image for that project)
Edit: The CLI Interpreter for the project must be the image built by docker-compose build. Setting different Command Line interpreters in the Codeception run configuration does not have any effects
docker-compose.yml
version: '3.7'
services:
php:
image: in2code/php-dev:7.3-fpm
volumes:
- ./:/app/
- $HOME/.composer/auth.json:/tmp/composer/auth.json
- $HOME/.composer/cache/:/tmp/composer/cache/
tests/unit.suite.yml
actor: UnitTester
modules:
enabled:
- Asserts
- \App\Tests\Helper\Unit
step_decorators: ~
coverage:
enable: true
remote: true
include:
- src/*
tests/unit/App/Controller/AirplaneControllerTest.php
<?php
declare(strict_types=1);
namespace App\Tests\App\Controller;
use App\Controller\AirplaneController;
class AirplaneControllerTest extends \Codeception\Test\Unit
{
/**
* #covers \App\Controller\AirplaneController::start
*/
public function testSomeFeature()
{
$airplaneController = new AirplaneController();
$airplaneController->start();
}
}
Did i miss something in my configuration?
The best solution would be a valid configuration using docker-compose exec for the remote interpreter, so other services like mysql or ldap are available for functional tests.

Unfortunately, it's hopelessly broken at the moment: https://youtrack.jetbrains.com/issue/WI-32625

I've noticed that PHPStorm calls codeception with this option
--coverage-xml /opt/phpstorm-coverage/admin_service$unit_tests.xml
but when testing is done I get this message
XML report generated in /opt/phpstorm-coverage/admin_service$$unit_tests.xml
Notice the filename is different. So I've created a link using this command
ln admin_service\$\$unit_tests.xml admin_service\$unit_tests.xml
and restarted the test coverage. The coverage window showed up.

Related

How to run PHPUnit test inside a running container

I use PhpStorm in development. To run a test I do below 3 commands:
docker-compose exec app bash
cd app/
vendor/bin/phpunit unitTest/Sample.php
I want to be able to run the test just by clicking the "Run" button inside PhpStorm.
I tried to accomplish it using docs from IntelliJ but they overwhelmed me.
I thought I just need to change the interpreter path but couldn't understand how to attach to a running docker.
First you need to add your Docker-compose based interpreter. See this guide.
Second, add a PHPUnit configuration based on this interpreter, see "Integrate PHPUnit with a PhpStorm project".
After that you should be able to simply Run the tests using IDE UI.

Install Keycloak adapter on WILDFLY that depends on ENVs in standalone.xml

I am trying to install the Keycloak Adapter to my WILDFLY Application Server that runs as Docker Container. I am using the image jboss/wildfly:17.0.0.Final as base image. I am having a big trouble while building my actual own image.
My Dockerfile:
FROM jboss/wildfly:17.0.0.Final
ENV $WILDFLY_HOME /opt/jboss/wildfly
COPY keycloak-adapter.zip $WILDFLY_HOME
RUN unzip $WILDFLY_HOME/keycloak-adapter.zip -d $WILDFLY_HOME
# My standalone.xml that contains ENVs
COPY standalone.xml $WILDFLY_HOME/standalone/configuration/
# Here it crashes!
RUN $WILDFLY_HOME/bin/jboss-cli.sh --file=$WILDFLY_HOME/bin/adapter-elytron-install-offline.cli
The official documentation says:
Unzip the adapter zip file in $WILDFLY_HOME (/opt/jboss/wildfly) - I've done this, works.
In order to install the adapter (when server is offline) you need to execute ./bin/jboss-cli.sh --file=bin/adapter-elytron-install-offline.cli which basically starts the server (which is needed as you cant modify the configuration otherwise) and modifies the standalone.xml.
Here is the problem. My standalone.xml is parametrized with environment variables that are only set during runtime as it runs in multiple different environments. When the ENVs are not set, the server crashes and so does the command above.
The error during docker build at the last step:
Cannot start embedded server WFLYEMB0021: Cannot start embedded process: JBTHR00005: Operation failed WFLYSRV0056: Server boot has fialed in an unrecoverable manner.
The cause
Despite of the not very precise error message I have clearly identified the unset ENVs as the cause by running the container with bash, setting the required ENVs with some random values and executing the jboss-cli command again - and it worked.
I know that the docs say its also possible to configure when the server is running but this is not an option for me, i need this configured at docker build stage.
So the problem here is they provide an offline installation that fails if the standalone.xml depends on environment variables which are usually not set during docker build. Unfortunately, i could not find a way to tell the jboss cli to ignore unset environment variables.
Do you know any workaround?

Need to know how to use Groovy to automate a Docker build & runtime

I have a task to containerize a Spring & React web-app so that non-technical staff can make use of the container to demo the app to clients. Currently we develop on OSX & deploy to Tomcat on AWS managed by a 3rd party firm, and the non-technical staff use Windows laptops for their stuff.
So far I have bash scripts in OSX which will create a Packager container that has a Java 8 SDK & maven installed, & which will compile the app into a war file. A second script creates and initializes a mongodb container & gives it a name, and the third script creates a Tomcat/Java 8 container, loads the war file into it, links it to the mongodb container & sets it running. In bash on OSX this works fine, but I found it didn't work if I tried it in cygwin on Windows 10, and my CMD/Powershell-fu is too weak to script it in a Windows native fashion.
So, I'm trying to do the script in something that'll run on both OSX, an AWS linux server & Windows 10, & being a Java developer myself I thought of Groovy. This is my first time scripting Docker using Groovy so I've ended up resorting to structures like:
println "docker build -f Dockerfile.packager -t mycontainer .".execute().text
I wonder if Docker has a Java or Groovy API that I could plug into & do things like:
docker.build("Dockerfile.packager").tag("mycontainer")
Currently my script is determining the location of the project root & building up the Docker run command as a string, like:
File emToo = new File(System.getProperty("user.dir")+"/.m2")
String currentDirectory = new File(".").getCanonicalPath()
String projectRoot = new File(currentDirectory+"/../").getCanonicalPath()
I get an option string from the user via a command line prompt, "Do you want QA or Dev?" & then:
String dockerRunCmd = "docker run -it -v $projectRoot/:/usr/local/build/myproject:cached -v ${emToo.getCanonicalPath()}:/root/.m2:cached mycontainer $option"
println dockerRunCmd.execute().text
Currently it doesn't seem to do anything after asking for the option - it's kinda bombing out. I get the run command output to screen, & if I copy/paste that into a command line in the scripts directory it falls over saying that the parent pom can't be found. Remember though that if I run the OSX bash script to do this, it works just fine. The bash script is basically:
#! /usr/bin/env bash
CWD=`pwd`
options=$1
docker run -it -v $CWD/../:/usr/local/build/myproject:cached -v ~/.m2:/root/.m2:cached --rm mycontainer $options
...which I think amounts to the same thing, right? Where's it going wrong?
UPDATE: I've found a bug - I should have been setting emToo to
new File(System.getProperty("user.home")+"/.m2"). user.dir just picks up the current directory, & the maven .m2 directory is in the user's home, usually. Currently though, the script gives me a run command that works if I cut/paste into a command line, but which doesn't allow me to call .execute() on the string in Groovy. If I can get that to work, there'll be no need for the docker-client projects suggested.
There are different ways to communicate with docker from groovy or java (sdk's are listed there https://docs.docker.com/engine/api/sdks/#other-languages):
Groovy (https://github.com/gesellix/docker-client)
Java (https://github.com/docker-java/docker-java)
Many others can be also found on github.
But as I see you are using maven so probably it will be easier for you to use awesome docker maven plugin (https://dmp.fabric8.io) which can build, push images, run containers etc.

How to specify different .dockerignore files for different builds in the same project?

I used to list the tests directory in .dockerignore so that it wouldn't get included in the image, which I used to run a web service.
Now I'm trying to use Docker to run my unit tests, and in this case I want the tests directory included.
I've checked docker build -h and found no option related.
How can I do this?
Docker 19.03 shipped a solution for this.
The Docker client tries to load <dockerfile-name>.dockerignore first and then falls back to .dockerignore if it can't be found. So docker build -f Dockerfile.foo . first tries to load Dockerfile.foo.dockerignore.
Setting the DOCKER_BUILDKIT=1 environment variable is currently required to use this feature. This flag can be used with docker compose since 1.25.0-rc3 by also specifying COMPOSE_DOCKER_CLI_BUILD=1.
See also comment0, comment1, comment2
from Mugen comment, please note
the custom dockerignore should be in the same directory as the Dockerfile and not in root context directory like the original .dockerignore
i.e.
when calling
DOCKER_BUILDKIT=1
docker build -f /path/to/custom.Dockerfile ...
your .dockerignore file should be at
/path/to/custom.Dockerfile.dockerignore
At the moment, there is no way to do this. There is a lengthy discussion about adding an --ignore flag to Docker to provide the ignore file to use - please see here.
The options you have at the moment are mostly ugly:
Split your project into subdirectories that each have their own Dockerfile and .dockerignore, which might not work in your case.
Create a script that copies the relevant files into a temporary directory and run the Docker build there.
Adding the cleaned tests as a volume mount to the container could be an option here. After you build the image, if running it for testing, mount the source code containing the tests on top of the cleaned up code.
services:
tests:
image: my-clean-image
volumes:
- '../app:/opt/app' # Add removed tests
I've tried activating the DOCKER_BUILDKIT as suggested by #thisismydesign, but I ran into other problems (outside the scope of this question).
As an alternative, I'm creating an intermediary tar by using the -T flag which takes a txt file containing the files to be included in my tar, so it's not so different than a whitelist .dockerignore.
I export this tar and pipe it to the docker build command, and specify my docker file, which can live anywhere in my file hierarchy. In the end it looks like this:
tar -czh -T files-to-include.txt | docker build -f path/to/Dockerfile -
Another option is to have a further build process that includes the tests. The way I do it is this:
If the tests are unit tests then I create a new Docker image that is derived from the main project image; I just stick a FROM at the top, and then ADD the tests, plus any required tools (in my case, mocha, chai and so on). This new 'testing' image now contains both the tests and the original source to be tested. It can then simply be run as is or it can be run in 'watch mode' with volumes mapped to your source and test directories on the host.
If the tests are integration tests--for example the primary image might be a GraphQL server--then the image I create is self-contained, i.e., is not derived from the primary image (it still contains the tests and tools, of course). My tests use environment variables to tell them where to find the endpoint that needs testing, and it's easy enough to get Docker Compose to bring up both a container using the primary image, and another container using the integration testing image, and set the environment variables so that the test suite knows what to test.
Sadly it isn't currently possible to point to a specific file to use for .dockerignore, so we generate it in our build script based on the target/platform/image. As a docker enthusiast it's a sad and embarrassing workaround.

Docker hub automated build fails but locally does not

I have setup an automated build on Docker hub here (the sources are here).
The build goes well locally. I have also tried to rebuild it with --no-cache option:
docker build --no-cache .
And the process completes successfully
Successfully built 68b34a5f493a
However, the automated build fails on Docker hub with this error log:
...
Cloning into 'nerdtree'...
[91mVim: Warning: Output is not to a terminal
[0m
[91mVim: Warning: Input is not from a terminal
[0m
[m[m[0m[H[2J[24;1HError detected while processing command line:
E492: Not an editor command: PluginInstall
E492: Not an editor command: GoInstallBinaries
[91mmv: cannot stat `/go/bin/*': No such file or directory
[0m
This build apparently fails on the following vim command:
vim +PluginInstall +GoInstallBinaries +qall
Note that the warnings Output is not to a terminal and Input is not to a terminal appears also in the local build.
I cannot understand how this can happen. I am using a standard Ubuntu 14.04 system.
I finally figured it out. The issue was related to this one.
I am using Docker 1.0 in my host machine, however a later version is in production in Docker Hub. Without the explicit ENV HOME=... line in the Dockerfile, version 1.0 uses / as home directory, while /root is used by the later version. The result is that vim was not able to find its .vimrc file, since it was copied in / instead of /root. The solution I used is to explicitly define ENV HOME=/root in my Dockerfile, so there are no differences between the two versions.

Resources