Docker - What is the easiest way to launch phpunit testsuite - php

Is there any good way (faster) to launch phpunit on docker? Here what I used to do :
docker-compose build
docker-compose up
docker ps
docker exec <container_id> phpunit --configuration /myproject/src/Tests/phpunit.xml --testsuite testAllSuites
Note: I don't want to use Volume to sync files, so right now everytime I have to rebuild the project .. and I am trying to figure out how to launch test on a specific container without specifing the containe_id .. is it possible to launch it using the build name instead ?

No need to do a complicated lookup of the container id, here's an example of how you can do it within docker-compose:
$ cat docker-compose.yml
version: '2'
volumes:
testvol:
driver: local
services:
testapp:
image: busybox
entrypoint: "top"
volumes:
- testvol:/data
testapp2:
image: busybox
entrypoint: "top"
volumes:
- testvol:/data
$ ../bin/docker-compose up -d
Creating test_testapp_1
Creating test_testapp2_1
$ ../bin/docker-compose ps
Name Command State Ports
-----------------------------------------
test_testapp2_1 top Up
test_testapp_1 top Up
$ ../bin/docker-compose exec testapp ls -l
total 40
drwxr-xr-x 2 root root 12288 Mar 18 16:39 bin
drwxr-xr-x 2 root root 4096 Jun 11 11:07 data
drwxr-xr-x 5 root root 360 Jun 13 11:50 dev
drwxr-xr-x 2 root root 4096 Jun 13 11:50 etc
drwxr-xr-x 2 nobody nogroup 4096 Mar 18 16:38 home
dr-xr-xr-x 224 root root 0 Jun 13 11:50 proc
drwxr-xr-x 2 root root 4096 Mar 18 16:38 root
dr-xr-xr-x 13 root root 0 Jun 13 11:50 sys
drwxrwxrwt 2 root root 4096 Mar 18 16:38 tmp
drwxr-xr-x 3 root root 4096 Mar 18 16:39 usr
drwxr-xr-x 4 root root 4096 Mar 18 16:39 var
You can also take advantage of the consistent container naming by docker-compose (it prepends the directory name and appends a number for scaling) to run the exec on the individual containers with docker exec:
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
069d40e3b6c7 busybox "top" 2 minutes ago Up 2 minutes test_testapp2_1
60e6d34d3b5a busybox "top" 2 minutes ago Up 2 minutes test_testapp_1
$ docker exec test_testapp_1 ls -l
total 40
drwxr-xr-x 2 root root 12288 Mar 18 16:39 bin
drwxr-xr-x 2 root root 4096 Jun 11 11:07 data
drwxr-xr-x 5 root root 360 Jun 13 11:50 dev
drwxr-xr-x 2 root root 4096 Jun 13 11:50 etc
drwxr-xr-x 2 nobody nogroup 4096 Mar 18 16:38 home
dr-xr-xr-x 226 root root 0 Jun 13 11:50 proc
drwxr-xr-x 2 root root 4096 Mar 18 16:38 root
dr-xr-xr-x 13 root root 0 Jun 13 11:50 sys
drwxrwxrwt 2 root root 4096 Mar 18 16:38 tmp
drwxr-xr-x 3 root root 4096 Mar 18 16:39 usr
drwxr-xr-x 4 root root 4096 Mar 18 16:39 var

I just figure out an easiest way to launch phpunit tests on my php-fpm container, here the command :
docker exec -it $(docker ps -n=-1 -q --filter name=my_php_container_name --format="{{.ID}}") phpunit --configuration /myproject/src/Tests/phpunit.xml --testsuite testAllSuites
so now whenever I change anything on my code here what I do :
docker-compose build
docker-compose up
docker exec -it $(docker ps -n=-1 -q --filter name=my_php_container_name --format="{{.ID}}") phpunit --configuration /myproject/src/Tests/phpunit.xml --testsuite testAllSuites
So this means I don't have to display all docker containers (docker ps) to get the id and update the command manually to launch phpunit on the new container id.
Runing this command wil return only the container_id :
docker ps -n=-1 -q --filter name=my_php_container_name --format="{{.ID}}"
here some explanations :
-n=-1 : show n last ceated containers
-q : only display numeric IDs
for more details about options here the docker documentation
Note: Just for instance, if we move phpunit.xml file just under /myproject/ root the phpunit command can be even smaller and if we run phpunit it will automatically load phpunit.xml and run all tests under your /Tests/... folder and the command will be :
docker exec -it $(docker ps -n=-1 -q --filter name=my_php_container_name --format="{{.ID}}") phpunit
Hope this can help someone ...

Related

Laravel 8.4 - "file_put_contents(/var/www/html/app/bootstrap/cache/packages.phpknHefj): Failed to open stream: Permission denied"

There are a lot of articles about this, I read them but none of the solutions worked.
I have laravel mounted via docker-compose in the folder /var/www/html/app
I am using this docker image https://github.com/khromov/alpine-nginx-php8/blob/master/Dockerfile
Logged into the container as root user with docker-compose exec -u root web sh, I can gave 777 permission to all under bootstrap folder, then I ls and result as below
/var/www/html/app # ls -ln bootstrap/
total 20
-rwxrwxrwx 1 1000 1000 1396 Oct 4 2019 app.php
-rwxrwxrwx 1 1000 1000 1079 Sep 11 2019 autoload.php
drwxrwxrwx 1 1000 1000 96 Jul 8 2021 cache
-rwxrwxrwx 1 1000 1000 2918 May 26 16:01 container.php
-rwxrwxrwx 1 1000 1000 120 Sep 11 2019 testing-container.php
-rwxrwxrwx 1 1000 1000 713 Feb 3 16:08 testing.php
I did the same in host user (where docker runs), gave 777 and chown to nobody:nobody
ls -l bootstrap
total 40
-rwxrwxrwx 1 nobody nobody 1396 Oct 4 2019 app.php
-rwxrwxrwx 1 nobody nobody 1079 Sep 11 2019 autoload.php
drwxrwxrwx 42 nobody nobody 1344 Jul 8 10:51 cache
-rwxrwxrwx 1 nobody nobody 2918 May 26 18:01 container.php
-rwxrwxrwx 1 nobody nobody 120 Sep 11 2019 testing-container.php
-rwxrwxrwx 1 nobody nobody 713 Feb 3 17:08 testing.php
Still laravel gives me the error permission denied..
I also gave chmod -R 777 bootstrap from guest host the one running docker not inside docker itself then docker-compose restart web, still nothing changed.
The service in docker-compose looks like
web:
user: nobody:nobody
build:
context: .
dockerfile: ./web/Dockerfile
args:
- DOMAIN=${DOMAIN}
restart: on-failure
environment:
DOMAIN: ${DOMAIN}
volumes:
- ${WEB_PATH}:/var/www/html/app
- ./web/default.conf:/etc/nginx/sites-available/${DOMAIN}
expose:
- 8080
container_name: web
Above I even tried to use user nobody as that one is used by nginx but no success
Laravel is running as nobody user from the error logs:
Server/Request Data
PATH
"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
HOSTNAME
"956b41d4651a"
HOME
"/"
SUPERVISOR_ENABLED
"1"
SUPERVISOR_PROCESS_NAME
"php-fpm"
SUPERVISOR_GROUP_NAME
"php-fpm"
USER
"nobody"
In addition to give 777, i also tried chown -R nobody:nobody bootstrap inside container itself but still did not work
So is there some way to mount in docker-compose and give ownership to nobody:nobody ? or some other solution

Trying to execute tests in Jenkins, but vendor dir is not there

I don't know what I am missing. I have a docker image, and a docker compose file.
My goal is to execute PHP Unit tests in Jenkins
I guess this
volumes:
- .:/var/www/html
is the source of the problems, but shouldn't the container last image have already the vendor directory?
Dockerfile
FROM quay/php-base:7.2.
COPY . /var/www/html
RUN curl -sS https://getcomposer.org/installer | php
RUN php composer.phar install
RUN rm composer.phar
EXPOSE 9000
CMD ["php-fpm"]
build.testing.yml
version: "3"
services:
phpfpm:
build:
context: .
dockerfile: Dockerfile
image: xxx-phpfpm:${GIT_COMMIT}
environment:
- APP_ENV=testing
volumes:
- .:/var/www/html
Jenkins build shell command
printenv
echo $GIT_BRANCH
echo $GIT_COMMIT
docker-compose -f build.testing.yml up -d --build --remove-orphans
docker-compose -f build.testing.yml exec -T phpfpm bash build/phpunit.sh
phpunit.sh
#!/usr/bin/env bash
cd /var/www/html;
ls -la;
ls -la vendor;
ls -la vendor/bin;
php vendor/bin/phpunit;
exit $?
Build log (last lines)
phpunit/php-code-coverage suggests installing ext-xdebug (^2.6.0)
phpunit/phpunit suggests installing ext-soap (*)
phpunit/phpunit suggests installing ext-xdebug (*)
phpunit/phpunit suggests installing phpunit/php-invoker (^2.0)
Generating optimized autoload files
Removing intermediate container 56245736b26b
---> 818e587ac18a
Step 6/8 : RUN rm composer.phar
---> Running in 5ccbffc37e05
Removing intermediate container 5ccbffc37e05
---> 086e88f369fc
Step 7/8 : EXPOSE 9000
---> Running in 1c10e32ba134
Removing intermediate container 1c10e32ba134
---> 84eb9cbc3477
Step 8/8 : CMD ["php-fpm"]
---> Running in b6381d9b0f9a
Removing intermediate container b6381d9b0f9a
---> 40b32fa81d5f
Successfully built 40b32fa81d5f
Successfully tagged xxx-phpfpm:aa01355d1e8ab6d0f3daf87fb8f1f3b1be3e45be
Recreating xxxmicroservicetesting_phpfpm_1 ...
Recreating xxxmicroservicetesting_phpfpm_1 ... done
+ docker-compose -f build.testing.yml exec -T phpfpm bash build/phpunit.sh
total 224
drwxrwxr-x 13 1002 1002 4096 Jul 29 19:35 .
drwxr-xr-x 1 root root 18 May 5 2018 ..
-rw-rw-r-- 1 1002 1002 213 Jul 26 15:38 .editorconfig
-rw-rw-r-- 1 1002 1002 388 Jul 26 15:38 .env.example
drwxrwxr-x 8 1002 1002 162 Jul 29 19:41 .git
-rw-rw-r-- 1 1002 1002 55 Jul 26 15:38 .gitignore
-rw-rw-r-- 1 1002 1002 71 Jul 26 15:38 .styleci.yml
-rw-rw-r-- 1 1002 1002 232 Jul 26 15:38 Dockerfile
-rw-rw-r-- 1 1002 1002 895 Jul 29 18:25 Jenkinsfile
drwxrwxr-x 16 1002 1002 240 Jul 26 15:38 app
-rw-rw-r-- 1 1002 1002 1094 Jul 26 15:38 artisan
drwxrwxr-x 2 1002 1002 21 Jul 26 15:38 bootstrap
drwxrwxr-x 2 1002 1002 24 Jul 29 19:41 build
-rw-rw-r-- 1 1002 1002 250 Jul 29 19:35 build.testing.yml
-rw-rw-r-- 1 1002 1002 1256 Jul 26 15:38 composer.json
-rw-rw-r-- 1 1002 1002 179335 Jul 26 15:38 composer.lock
drwxrwxr-x 2 1002 1002 45 Jul 26 15:38 config
drwxrwxr-x 5 1002 1002 54 Jul 26 15:38 database
-rw-rw-r-- 1 1002 1002 193 Jul 26 15:38 phpcs.xml
-rw-rw-r-- 1 1002 1002 924 Jul 26 15:38 phpunit.xml
drwxrwxr-x 2 1002 1002 40 Jul 26 15:38 public
drwxrwxr-x 3 1002 1002 19 Jul 26 15:38 resources
drwxrwxr-x 2 1002 1002 40 Jul 26 15:38 routes
drwxrwxr-x 5 1002 1002 46 Jul 26 15:38 storage
drwxrwxr-x 4 1002 1002 113 Jul 26 15:38 tests
ls: vendor: No such file or directory
ls: vendor/bin: No such file or directory
Could not open input file: vendor/bin/phpunit
Build step 'Execute shell' marked build as failure
Finished: FAILURE
When you have a volumes: directive in a docker-compose.yml like you show, it tells Docker to completely ignore the contents of the Docker image and use whatever's in the local filesystem. You should remove that.
If you're running this in Jenkins or another continuous integration (CI) system, this behavior would mean that the image that comes out of the build system hasn't actually been tested. You've run tests on whatever local source tree Jenkins has checked out, glued over the top of the built image. If the host system and the image have any sort of incompatibility around library versions or a vendored library tree, you can easily wind up in a situation where you're shipping a completely broken image, that happens to pass this artificial test environment.
In this context I'd suggest a sequence like this:
Check out your source tree.
Run any build steps and unit-test steps. Jenkins has a path to run these inside a Docker container, which can be more convenient than maintaining a Jenkins image with the language runtime you need, but this isn't "building and running the image". You can do this totally without Docker too.
Actually build the Docker image. I'd do this with the Jenkins Docker workflow plugin, or a manual sh "docker build" step.
Run integration tests against the built image. This could use a docker-compose.yml file like you show above, but without the build: or volumes: blocks. The test itself wouldn't be built into the image, but it would make external calls into the image's published API.
Push the built image to a registry. Trigger an automated deployment sequence, if that's appropriate.

Laravel Dusk - can't make it run on GitLab CI

Did anyone get to make Laravel Dusk to work on GitLab CI?
I'm using this docker image, which is amazing, but I simply can't execute ./vendor/laravel/dusk/bin/chromedriver-linux, it says:
/bin/bash: line 102: ./vendor/laravel/dusk/bin/chromedriver-linux: No such file or directory
When I enter at ./vendor/laravel/dusk/bin I can see that chromedriver-linux is there and it's executable, but can't make it run.
By now, the script lines that compose this phase are:
- mv .env.testing .env
- php artisan key:generate
- ./vendor/bin/phpunit --colors=never
- php artisan dusk:install
- chmod -R 0755 vendor/laravel/dusk/bin
- ./vendor/laravel/dusk/bin/chromedriver-linux
- php artisan dusk
I've also tried the approaches on documentation, even though they're not for GitLab CI, but none of them worked.
Update:
Running ls -l ./vendor/laravel/dusk/bin returns:
total 33560
-rwxr-xr-x 1 root root 10885776 Jun 26 13:10 chromedriver-linux
-rwxr-xr-x 1 root root 14994520 Jun 26 13:10 chromedriver-mac
-rwxr-xr-x 1 root root 8393728 Jun 26 13:10 chromedriver-win.exe
-rwxr-xr-x 1 root root 69309 Jun 25 22:59 jquery.js
I've tried to copy the file to the machine's current PATH but didn't work either:
Testing the $PATH variable
$ echo $PATH
./vendor/bin:/composer/vendor/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Copying the binary to /usr/local/bin
$ CHROME_DRIVER_PATH_BIN=./vendor/laravel/dusk/bin/chromedriver-linux
$ cp $CHROME_DRIVER_PATH_BIN /usr/local/bin
Testing if the file is really there
$ ls -lha /usr/local/bin
total 56564
drwxr-xr-x 1 root root 4.0K Jun 26 17:33 .
drwxr-xr-x 1 root root 4.0K Feb 21 23:08 ..
-rwxr-xr-x 1 root root 10.4M Jun 26 17:33 chromedriver-linux
-rwxr-xr-x 1 root root 1.8M Feb 22 06:40 composer
-rwxrwxr-x 1 root root 118 Feb 21 23:02 docker-php-entrypoint
-rwxrwxr-x 1 root root 1.4K Feb 21 23:02 docker-php-ext-configure
-rwxrwxr-x 1 root root 2.4K Feb 21 23:02 docker-php-ext-enable
-rwxrwxr-x 1 root root 2.3K Feb 21 23:02 docker-php-ext-install
-rwxrwxr-x 1 root root 587 Feb 9 01:57 docker-php-source
lrwxrwxrwx 1 root root 32 Jun 26 17:33 heroku -> /usr/local/lib/heroku/bin/heroku
-rwxr-xr-x 1 root root 817 Feb 21 23:08 pear
-rwxr-xr-x 1 root root 838 Feb 21 23:08 peardev
-rwxr-xr-x 1 root root 751 Feb 21 23:08 pecl
lrwxrwxrwx 1 root root 9 Feb 21 23:08 phar -> phar.phar
-rwxr-xr-x 1 root root 14.5K Feb 21 23:08 phar.phar
-rwxr-xr-x 1 root root 14.3M Feb 21 23:08 php
-rwxr-xr-x 1 root root 14.2M Feb 21 23:08 php-cgi
-rwxr-xr-x 1 root root 2.6K Feb 21 23:08 php-config
-rwxr-xr-x 1 root root 14.4M Feb 21 23:08 phpdbg
-rwxr-xr-x 1 root root 4.5K Feb 21 23:08 phpize
Either way, running chromedriver-linux does not work, I got the error
nohup: can't execute 'chromedriver-linux': No such file or directory
I've tested the same concept on my macOS: created an executable, put it into a folder which is on my PATH variable using a symlink and it works perfectly.
I could solve that installing chromium and chromium-chromedriver packages since they are available on Alpine Linux.
Below is the relevant part of my .gitlab-ci.yml file:
image: lorisleiva/laravel-docker
before_script:
- apk add chromium-chromedriver -y
- apk add chromium -y
phptest:
stage: test
script:
- mv .env.testing .env
- php artisan key:generate
- ./vendor/bin/phpunit --colors=never
- chromedriver 2>&1 &
- sleep 5
- nohup php artisan serve &
- php artisan dusk
Also, a really important part is to add --no-sandbox argument when creating the RemoteWebDriver. This can be done changing the function driver on tests/DuskTestCase.php file:
<?php
// tests/DuskTestCase.php
protected function driver()
{
$options = (new ChromeOptions)->addArguments([
'--disable-gpu',
'--headless',
'--no-sandbox', // # Add this # //
'--window-size=1920,1080',
]);
return RemoteWebDriver::create(
'http://localhost:9515',
DesiredCapabilities::chrome()->setCapability(
ChromeOptions::CAPABILITY,
$options
)
);
}
Just this solved my problem and now I can test with Dusk on GitLab CI using lorisleiva/laravel-docker Docker image.
The Dockerfile for that lorisleiva/laravel-docker image does:
ENV PATH ./vendor/bin:/composer/vendor/bin:$PATH
...
WORKDIR /var/www
So when your script does execute, the '.' in './vendor' might not reference the current working directory you expect.
Since PATH is set, it would be best if chromedriver-linux was in ./vendor/bin instead.
That way, your script can simply call chromedriver-linux (no leading path)

webhook php file work from terminal but not from bitbucket

I'm using bitbucket to host my git repository, the repo holds a test website at the moment, I have created a bitbucket webhook, so when I push to the bitbucket repo, the changes show up as live on the digitalOcean VPS, in other words.. when bitbucket receives a push, it calls the webhook php file, and that php file has a shell script that pulls from github..
the hook file
Hook path : /var/www/html/hook.php
the site folder
Site path : /var/www/html/webhooks/
the hook.php file looks like so
<?php
echo "________PHP_AUTO_PULL________";
$output = shell_exec('git -C ./webhooks/ pull https://userName:password#bitbucket.org/userName/repo.git master');
echo "<pre>$output</pre>";
?>
when I do this in terminal
php hook.php
it does the job normally, and it pulls..
but the problem is, webhooks only shows this reply
________PHP_AUTO_PULL________
indicating that it does no pull, yes I have checked, no pull occured, how to make the hook execute the file normally?
permissions and owners are provided in these listings
listing for /var/www/html/
drwxrwxr-x 3 www-data www-data 4096 Mar 28 09:21 ./
drwxrwxr-x 3 www-data www-data 4096 Mar 3 16:49 ../
-rwxrwxrwx 1 www-data root 200 Mar 28 09:05 hook.php*
-rw-rw-r-- 1 www-data www-data 20 Mar 3 16:49 info.php
drwxr-xr-x 3 root root 4096 Mar 28 09:03 webhooks/
listing for /var/www/html/webhooks/
drwxr-xr-x 3 root root 4096 Mar 28 09:03 ./
drwxrwxr-x 3 www-data www-data 4096 Mar 28 09:21 ../
-rw-r--r-- 1 root root 295 Mar 27 15:13 content.html
drwxr-xr-x 8 root root 4096 Mar 28 09:03 .git/
-rw-r--r-- 1 root root 444 Mar 27 15:13 index.html
-rw-r--r-- 1 root root 963 Mar 27 15:13 menu_1.html
-rw-r--r-- 1 root root 13 Mar 28 09:03 number.txt
my webserver is nginx
any idea why it works from terminal, but bitbucket can't have it to work?
I have managed to solve it, using :
echo shell_exec("/usr/bin/git pull https://userName:password#bitbucket.org/userName/repo.git master 2>&1");
the 2>&1 part was helping me to see errors about permissions of folders, I used
chown -R www-data .git/
and it's working fine.

"assets:install" command fails with error "The target directory "web" does not exist", why?

I am running a Symfony3 application inside a Docker container. I have created a CommonBundle with all the resources (js, css, images). This resources are symlinked to another path as shown below:
$ docker exec -u www-data -it dockeramp_php_1 ls -la oneview_symfony/src/CommonBundle/Resources/public
total 8
drwxrwsr-x 2 www-data www-data 4096 Feb 23 21:09 .
drwxr-sr-x 5 www-data www-data 4096 Feb 23 20:54 ..
lrwxrwxrwx 1 root www-data 32 Feb 23 21:09 css -> /var/www/html/public_html/styles
lrwxrwxrwx 1 root www-data 32 Feb 23 21:09 images -> /var/www/html/public_html/images
lrwxrwxrwx 1 root www-data 28 Feb 23 21:08 js -> /var/www/html/public_html/js
The directory oneview_symfony/web does exists and it's writable by www-data as shown below:
$ docker exec -u www-data -it dockeramp_php_1 ls -la oneview_symfony/web
total 64
drwxrwsr-x 3 www-data www-data 4096 Feb 23 20:50 .
drwxrwsr-x 9 www-data www-data 4096 Feb 23 21:16 ..
-rwxrwxr-x 1 www-data www-data 3319 Feb 23 16:45 .htaccess
-rwxrwxr-x 1 www-data www-data 631 Feb 23 16:45 app.php
-rwxrwxr-x 1 www-data www-data 843 Feb 23 16:45 app_dev.php
-rwxrwxr-x 1 www-data www-data 2092 Feb 23 16:45 apple-touch-icon.png
drwxr-sr-x 2 www-data www-data 4096 Feb 23 20:50 bundles
-rw-rw-rw- 1 www-data www-data 21486 Feb 23 20:50 config.php
-rwxrwxr-x 1 www-data www-data 6518 Feb 23 16:45 favicon.ico
-rwxrwxr-x 1 www-data www-data 116 Feb 23 16:45 robots.tx
I am trying to install the assets relative or symlink switching values on the composer.json file:
{
...
"extra": {
...
"symfony-web-dir": "web",
"symfony-assets-install": "relative",
}
}
I am trying to publish the assets running the following command and ending up with the error below:
$ docker exec -u www-data -it dockeramp_php_1 php oneview_symfony/bin/console assets:install
[InvalidArgumentException]
The target directory "web" does not exist.
What I am missing here?
There is a similar issue here but without answer so far.
Can you try this command instead:
$ docker exec -u www-data -it dockeramp_php_1 php oneview_symfony/bin/console assets:install web
If that doesn't work, try the full path to the web directory.
Let us know if that works. Not sure if that will fix the problem, but please try it.
Configure variable for assets command.
Add public-dir to composer.json
"extra": {
"symfony-web-dir": "web",
"public-dir": "web",
...
},
Because assets command relies on it (view code on github)
Look:
$defaultPublicDir = 'public';
// ...
if (isset($composerConfig['extra']['public-dir'])) {
return $composerConfig['extra']['public-dir'];
}
return $defaultPublicDir;
For anyone trying to install assets in Symfony 4 with the old Symfony3 directory structure getting:
Error thrown while running command "assets:install". Message: "The target directory "public" does not exist."
The same fix Alvin Bunk provided works:
$ bin/console assets:install web
Just manually provide the old target path
You need to run the exact line
app/console assets:install or bin/console assets:install
(depends on your version) since it takes the path of the command as reference.

Categories