Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I run Test from within Docker? #11

Closed
Artem-Schander opened this issue Oct 25, 2022 · 38 comments
Closed

How do I run Test from within Docker? #11

Artem-Schander opened this issue Oct 25, 2022 · 38 comments

Comments

@Artem-Schander
Copy link

I would like to migrate from vim-test but it seems I'm missing something.
My development environment is running inside Docker, so the way to execute the tests is:

docker exec -it $(docker ps -n=-1 -q --filter name=cityoffer_phpfpm --format="{{.ID}}") vendor/bin/phpunit

but if I configure the phpunit_cmd like this

local neotest = require("neotest")
neotest.setup({
    adapters = {
        require('neotest-phpunit')({
            phpunit_cmd = function()
                return 'docker exec -it $(docker ps -n=-1 -q --filter name=phpfpm --format="{{.ID}}") vendor/bin/phpunit'
            end
        }),
    },
})

I'm getting this error

Invalid value for argument cmd: 'docker exec -it $(docker ps -n=-1 -q --filter name=phpfpm --format="{{.ID}}") vendor/bin/phpunit' is not executable

I also tried to substitute $(docker ps -n=-1 -q --filter name=phpfpm --format="{{.ID}}") with the real ID with no luck.
And also I tried to through a shell script and got high CPU usage without a running test (and without any errors)

So how do I execute tests inside Docker?

@olimorris
Copy link
Owner

No idea.

I'm not sure it's possible right now though: nvim-neotest/neotest#89

@Artem-Schander
Copy link
Author

Oh.. then I'll wait

@phaberest
Copy link

phaberest commented Apr 12, 2023

Would it make sense to make a bash script or an alias that calls phpunit from docker as a workaround?

@Artem-Schander
Copy link
Author

@phaberest
I tried.. did not work.

@phaberest
Copy link

phaberest commented Apr 12, 2023

I found a fork from @saifulapm (https://github.com/saifulapm/neotest-phpunit) that helped a bit, but I am not proficient in Lua so I'm not yet able to get to a point of success

I made my own fork https://github.com/phaberest/neotest-phpunit that is able to call phpunit from laravel sail (and it would be easy to add docker as well, we can just check if there's a Dockerfile or a docker-compose.yml in the project.

The problem so far is that I'm not able to remove my local path from the path of the file when launching a test. I don't even think it is necessary to remap to the path that the file has inside docker, because it is not necessary to use the full path if we use --filter.
The best scenario would be to be able to remove the result of pwd from the string of the path

This is basically what I tried to do with a goofy hardcoded string https://github.com/phaberest/neotest-phpunit/blame/1d09587961819d0fd5fe2847845d58323791c4e4/lua/neotest-phpunit/init.lua#L88

I'll give it another try in the next days and eventually submit a PR to this repo once it works, but as stated in #8 it would need to be generalised a bit using config parameters

@phaberest
Copy link

Another alternative could be to use https://github.com/nvim-neotest/neotest-vim-test instead, but I'm not sure it can work either

@olimorris
Copy link
Owner

I found a fork from @saifulapm (https://github.com/saifulapm/neotest-phpunit) that helped a bit, but I am not proficient in Lua so I'm not yet able to get to a point of success

I made my own fork https://github.com/phaberest/neotest-phpunit that is able to call phpunit from laravel sail (and it would be easy to add docker as well, we can just check if there's a Dockerfile or a docker-compose.yml in the project.

You don't need to fork the plugin to add that functionality. As per the readme, you can specify the phpunit command to run in a function.

@phaberest
Copy link

I found a fork from @saifulapm (https://github.com/saifulapm/neotest-phpunit) that helped a bit, but I am not proficient in Lua so I'm not yet able to get to a point of success
I made my own fork https://github.com/phaberest/neotest-phpunit that is able to call phpunit from laravel sail (and it would be easy to add docker as well, we can just check if there's a Dockerfile or a docker-compose.yml in the project.

You don't need to fork the plugin to add that functionality. As per the readme, you can specify the phpunit command to run in a function.

Doing it that way triggers the error mentioned in the first post of this issue

@phaberest
Copy link

phaberest commented May 29, 2023

cb4808c shuld be able to solve the issue, thank you @olimorris

@olimorris
Copy link
Owner

cb4808c shuld be able to solve the issue, thank you @olimorris

Happy to accept any PRs for more user configurable options btw

@Artem-Schander
Copy link
Author

sounds nice but how?
I'm not able to run a test neither like this: (still same error ...is not executable)

local neotest = require("neotest")
neotest.setup({
    adapters = {
        require('neotest-phpunit')({
            phpunit_cmd = function()
                return 'docker exec -it $(docker ps -n=-1 -q --filter name=phpfpm --format="{{.ID}}") vendor/bin/phpunit'
            end
        }),
    },
})

nor like this: (just runs forever. no errors)

local neotest = require("neotest")
neotest.setup({
    adapters = {
        require('neotest-phpunit')({
            phpunit_cmd = function()
                return "./run-tests.sh"
            end
        }),
    },
})

run-tests.sh

#!/bin/bash
docker exec -it $(docker ps -n=-1 -q --filter name=phpfpm --format="{{.ID}}") vendor/bin/phpunit

@olimorris olimorris reopened this May 30, 2023
@phaberest
Copy link

I'll give it a go tonight and give you an update 🙌🏻

@haringsrob
Copy link

haringsrob commented Jul 13, 2023

Tried briefly, couple of issues:

  1. I think we should be able to alter the path, or use a relative path to the test file.
  2. It would be nice if we could set/change the working directory.

@Artem-Schander your issue most likely is with the -it parameter, which makes the command interactive?

The command can be set like this, which works, except that the path wont work correctly:

        require('neotest-phpunit')({
            phpunit_cmd = function()
                path = vim.fn.getcwd()
                if (string.find(path, "someDir")) then
                    return {
                        "docker",
                        "exec",
                        "SOME-IMAGE-NAME",
                        "php",
                        "vendor/bin/phpunit",
                    }
                else
                    return "vendor/bin/phpunit"
                end
            end,
            quickfix = {
                open = false,
                enabled = false,
            },
        }),

@Artem-Schander
Copy link
Author

@haringsrob
thanks for the response. It's still not working, but im getting a different error.

Cannot open file ...

The path in which neotest tries to find the file ist my local path, not the one inside the container.
So it seems you're right regarding the working directory issue.

FYI
I' only get said error if i configure it like this:

local neotest = require("neotest")
neotest.setup({
    adapters = {
        require('neotest-phpunit')({
            phpunit_cmd = function()
                return {
                    "docker",
                    "exec",
                    "5a386e04b1f6", -- image ID
                    "php",
                    "vendor/bin/phpunit"
                }
            end,
        }),
    },
})

if i try it with the more dynamic approach $(docker ps -n=-1 -q --filter name=phpfpm) (which results in the image ID) i get

No tests found

@haringsrob
Copy link

Based on some information here: nvim-neotest/neotest#89 I played a bit and made the following runner script:

#!/bin/bash

# Customize the following:
# - escaped_path: absolute local path to your project
# - container: name of your docker container
escaped_path="\/Volumes\/Sites\/YOUR PROJECTPATH\/" # Be careful to properly escape this
containerName=REPLACE CONTAINER NAME

# WARN: This will break if flags other than -o and -f are added in neotest-rspec
while getopts o:f: flag; do
	# This deliberately does not handle all arguments
	# shellcheck disable=SC2220
	# shellcheck disable=SC2213
	case "${flag}" in
		o) output_path=${OPTARG} ;;
	esac
done

for i in "$@"; do
    case $i in
        --log-junit=*)
            localPath="${i#*=}"
            shift
            ;;
        *)
            ;;
    esac
done

replace="/var/folders"
replaceWith="/var/www/vendor/neotest-test-output"
replaceWithLocal="./vendor/neotest-test-output"

# Strip local path from test paths sent to container
args=("${@/$escaped_path/}")
args=${args/$replace/$replaceWith}

dockerPath=${localPath/$replace/$replaceWith}

container=$(docker ps -n=-1 --filter name=${containerName} --format="{{.ID}}")

# Run the tests
docker exec "$container" touch "${dockerPath}"
docker exec "$container" vendor/bin/phpunit "${args[@]}"

cp ${localPath/$replace/$replaceWithLocal} ${localPath}

While it does run the script perfectly, and it displays the output correctly, it does not mark the test as passed. Not sure why.

Screenshot 2023-07-14 at 09 14 04

@Artem-Schander
Copy link
Author

thank you @haringsrob, I'll give it a go later

@haringsrob
Copy link

#!/bin/bash

# Customize the following:
# - escaped_path: absolute local path to your project
# - container: name of your docker container
escaped_path="\/Volumes\/Sites\/YOUR PROJECTPATH\/" # Be careful to properly escape this
containerName=REPLACE CONTAINER NAME

argsCopy=${@}

for i in $argsCopy; do
    case $i in
        --log-junit=*)
            localPath="${i#*=}"
            ;;
        *)
            ;;
    esac
done

POSITIONAL_ARGS=()

while [[ $# -gt 0 ]]; do
  case $1 in
    --filter)
        filterVal="$2"
      shift # past argument
      shift # past value
      ;;
    *)
      POSITIONAL_ARGS+=("$1") # save positional arg
      shift # past argument
      ;;
  esac
done

set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters

replace="/var/folders"
replaceWith="/var/www/vendor/neotest-test-output"
replaceWithLocal="./vendor/neotest-test-output"

# Strip local path from test paths sent to container
args=${argsCopy/$escaped_path/"/var/www/"}
args=${args/$replace/$replaceWith}
args=${args/$filterVal/\'/$filterVal/\'}
args=${args/"--filter "/"--filter "}

dockerPath=${localPath/$replace/$replaceWith}

container=$(docker ps -n=-1 --filter name=${containerName} --format="{{.ID}}")

echo ${args}

# Run the tests
docker exec "$container" touch "${dockerPath}"
docker exec "$container" bash -c "vendor/bin/phpunit ${args[@]}"

cp ${localPath/$replace/$replaceWithLocal} ${localPath}

With fixes for filter and allow to run full suite.

@haringsrob
Copy link

@olimorris not sure why it is not parsing the result correctly. I double checked and the junit files are where it is expected to be (on the host system).

@olimorris
Copy link
Owner

@haringsrob - we recently added Docker support in my other Neotest adapter, here. I'd be open to any PR that could add this functionality.

@haringsrob
Copy link

For my own and others, the issue was that it did not have the correct path in the junit file. This I solved with:

sed -i '' "s|/var/www/|${escaped_path}|g" ${localPath}

As the last line in the script above.

@eerison
Copy link

eerison commented Nov 13, 2023

I am using docker-compose and I am facing this issue

PHPUnit 9.6.13 by Sebastian Bergmann and contributors.

Cannot open file "/Users/erisonsilva/Documents/projects/frontend/test/tests/unit/invoice/price/calculation/BaseMeterCostTest.php".

is there any way to replace /Users/erisonsilva/Documents/projects/frontend to /app (root path in my container)?

regarding with this sed -i '' "s|/var/www/|${escaped_path}|g" ${localPath}, I did not get where to put this 👀

@eerison eerison mentioned this issue Nov 14, 2023
@kilatib
Copy link

kilatib commented Jan 12, 2024

On that Base I have created one more script for random docker dir

Project Dir we take by .git folder
Docker dir by settings

So for use:
In neotest-phpunit configuration:

require("neotest").setup {
      adapters = {
        require "neotest-phpunit" {
          root_files = { "composer.json", "phpunit.xml", "phpunit.xml.dist", ".github" },
          filter_dirs = { "vendor" },
          env = {
            CONTAINER = "container_name",
            REMOTE_PHPUNIT_BIN = "bin/phpunit",
          },
          phpunit_cmd = function()
            return "/usr/local/bin/dphpunit"
          end,
        },
      },
    }

Where:

  • container_name your docker container name
  • bin/phpunit path to PHPUnit on docker
  • /usr/local/bin/dphpunit path to bash below (it should be executable and full path)

Run test bash /usr/local/bin/dphpunit:

#!/bin/sh

# Customize the following:
containerName=$CONTAINER
phpunitPath=$REMOTE_PHPUNIT_BIN

# detect local path and remove from args
argsInput=${@}
runFile=$(echo $argsInput| awk '{print $1}')
phpTestPath=$(dirname "$runFile")
pushd $phpTestPath > /dev/null
projectPath="$(git rev-parse --show-toplevel)"
pushd > /dev/null

## detect test result output
for i in $argsInput; do
   case $i in
       --log-junit=*)
           outputPath="${i#*=}"
           ;;
       *)
           ;;
   esac
done

# replace with local
args=("${argsInput/$projectPath\//}")

# replace strange line with (data set .*)
args=("${args//(*}")

# Detect path
container=$(docker ps -n=-1 --filter name=$containerName --format="{{.ID}}")
dockerPath=$(docker inspect --format {{.Config.WorkingDir}} $container)

## debug
# echo "Params: "${args[@]}
# echo "Docker: "$dockerPath
# echo "Local:  "$projectPath
# echo "Result: "$outputPath

# Run the tests
docker exec -i $container php -d memory_limit=-1 $phpunitPath ${args[@]}

# copy results
docker cp -a "$container:$outputPath" "$outputPath"|- &> /dev/null

# replace docker path to locals
sed -i '_' "s#$dockerPath#$projectPath#g" $outputPath

@eerison
Copy link

eerison commented Mar 20, 2024

just to say that I tested @kilatib code and it worked perfect.

in case someone is using lazyvim the config will be like this

  {
    "nvim-neotest/neotest",
    dependencies = {
      "olimorris/neotest-phpunit",
    },
    opts = {
      adapters = {
        ["neotest-phpunit"] = {
          env = {
            CONTAINER = "your_container_name",
            REMOTE_PHPUNIT_BIN = "bin/phpunit",
          },
          phpunit_cmd = function()
            return "the/bash/file/above"
          end,
        },
      },
    },
  },

thank you @kilatib <3

@olimorris olimorris pinned this issue Mar 31, 2024
@Artem-Schander
Copy link
Author

Hi everyone, I'm sorry to disturb the closed issue.
It took a while until i found some time to give neotest another try and i'm still struggling.

It seems that junit is not able to create a directory (which already exists). I dont believe it to be related to permissions.

PHPUnit 9.6.19 by Sebastian Bergmann and contributors.
Directory "/var/folders/k7/mpvywsws2y55tqb4x4mtym5h0000gn/T/nvim.artemschander/arWc8a" was not created
Error response from daemon: Could not find the file /var/folders/k7/mpvywsws2y55tqb4x4mtym5h0000gn/T/nvim.artemschander/arWc8a/77 in container d8e1cfc02e67
sed: /var/folders/k7/mpvywsws2y55tqb4x4mtym5h0000gn/T/nvim.artemschander/arWc8a/77: No such file or directory

I tinkered a bit and was able to work around this problem by replacing $outtputPath with phpunit-result.xml in $args. The only issue is that the summary is wrong

Here is my take on it:

#!/bin/sh

# Customize the following:
containerName=$CONTAINER
phpunitPath=$REMOTE_PHPUNIT_BIN

# detect local path and remove from args
argsInput=${@}
runFile=$(echo $argsInput| awk '{print $1}')
phpTestPath=$(dirname "$runFile")
pushd $phpTestPath > /dev/null
projectPath="$(git rev-parse --show-toplevel)"
pushd > /dev/null

## detect test result output
for i in $argsInput; do
   case $i in
       --log-junit=*)
           outputPath="${i#*=}"
           ;;
       *)
           ;;
   esac
done

# replace with local
args=("${argsInput/$projectPath\//}")

# replace strange line with (data set .*)
args=("${args//(*}")

# sed -i '' "s|${outputPath}|foo|g" ${args[@]}

# Detect path
container=$(docker ps -n=-1 --filter name=$containerName --format="{{.ID}}")
dockerPath=$(docker inspect --format {{.Config.WorkingDir}} $container)

# replace docker path to locals
result="phpunit-result.xml"
args=${args//$outputPath/$result}

## debug
# echo "Params: "${args[@]}
# echo "Docker: "$dockerPath
# echo "Local:  "$projectPath
# echo "Result: "$outputPath
# echo "docker exec -i "$container" php -d memory_limit=-1 "$phpunitPath" "${args[@]}

# Run the tests
docker exec -i $container php -d memory_limit=-1 $phpunitPath ${args[@]}

# copy results
# docker cp -a "$container:$outputPath" "$outputPath"|- &> /dev/null
docker cp -a "$container:$dockerPath/$result" "$projectPath/$result"|- &> /dev/null

# replace docker path to locals
# sed -i '_' "s#$dockerPath#$projectPath#g" $outputPath
sed -i '_' "s#$dockerPath#$projectPath#g" "$projectPath/$result"

I have no idea what the last two commands meant to do exactly, so i believe i have done something wrong there

@kilatib
Copy link

kilatib commented Jul 1, 2024

@Artem-Schander This error happens when the docker container where you run tests is down

@Artem-Schander
Copy link
Author

@kilatib strange, it was/is definitely not down.
I just tried it again and it seems to have issues writing in that direcory: /var/folders/k7/mpvywsws2y55tqb4x4mtym5h0000gn/T/nvim.artemschander..

If i change the shell script to make docker write the junit output into the project dir (on host) then the error disappears and the tests are running correctly. but then the Neotest status says that the tests have failed although they didn't

# copy results
# docker cp -a "$container:$outputPath" "$outputPath"|- &> /dev/null
docker cp -a "$container:$dockerPath/$result" "$projectPath/$result"|- &> /dev/null

# replace docker path to locals
# sed -i '_' "s#$dockerPath#$projectPath#g" $outputPath
sed -i '_' "s#$dockerPath#$projectPath#g" "$projectPath/$result"

Bildschirmfoto 2024-07-03 um 14 17 41

@kilatib
Copy link

kilatib commented Jul 3, 2024

@Artem-Schander Do you have permission to write into that directory inside your docker container?

@Artem-Schander
Copy link
Author

Yes. That was the first i checked. The permissions are the same for both directories.

That one works:

docker exec -i d8e1cfc02e67 php -d memory_limit=-1 vendor/bin/phpunit tests/CityOffer/Models/TagModelTest.php --log-junit=phpunit-result.xml

That one doesn't

docker exec -i d8e1cfc02e67 php -d memory_limit=-1 vendor/bin/phpunit tests/CityOffer/Models/TagModelTest.php --log-junit=/var/folders/k7/mpvywsws2y55tqb4x4mtym5h0000gn/T/nvim.artemschander/Tc3Aur/115

Also it's worth mentioning that the first one does not work if i use absolute paths. It says "Directory was not created" regardless that the directory already exists. It seems that the issue lays in absolute paths

@kilatib
Copy link

kilatib commented Jul 3, 2024

@Artem-Schander, please pay attention to that version of my script I did not post it here here I use a relative path inside container, also pay attention that I set path to PHPUnit inside the container dynamically

#!/bin/sh

# Customize the following:
phpunitPath=$REMOTE_PHPUNIT_BIN

# detect local path and remove from args
argsInput=${@}
runFile=$(echo $argsInput| awk '{print $1}')
phpTestPath=$(dirname "$runFile")
pushd $phpTestPath > /dev/null
projectPath="$(git rev-parse --show-toplevel)"
pushd > /dev/null

subPath=$(awk -F '/vendor/' '{print $1}' <<< $projectPath)
containerName=$(sed 's#.*/##' <<< $subPath | sed s/-/_/g)

## detect test result output
for i in $argsInput; do
    case $i in
        --log-junit=*)
            outputPath="${i#*=}"
            ;;
        *)
            ;;
    esac
done

# replace with local
args=("${argsInput/$subPath\//}")
args=("${args//(*}")

# Detect path
phpunitPath=$(docker exec -it $containerName /bin/bash -c "if [ -f vendor/bin/phpunit ]; then echo vendor/bin/phpunit; else echo bin/phpunit; fi" | tr -d '\r')
execPath=$(docker exec -it $containerName /bin/bash -c "if [ -f /bin/sh ]; then echo /bin/sh; else echo /bin/bash; fi" | tr -d '\r')
container=$(docker ps -n=-1 --filter name=$containerName --format="{{.ID}}")
dockerPath=$(docker inspect --format {{.Config.WorkingDir}} $container)

## debug
# echo "Raw ARGS: "${@}
# echo "Params:   "${args[@]}
# echo "Docker:   "$dockerPath
# echo "Local:    "$projectPath
# echo "Result:   "$outputPath

# Run the tests
docker exec -it $container $execPath -c "SYMFONY_DEPRECATIONS_HELPER=weak $phpunitPath -d memory_limit=-1 -d xdebug.idekey=project_debug_key ${args}"
# docker exec -it $container $phpunitPath -d memory_limit=-1 ${args[@]}

# copy results
docker cp -a "$container:$outputPath" "$outputPath"|- &> /dev/null

# replace the docker path with locals
sed -i '_' "s#$dockerPath#$projectPath#g" $outputPath

@Artem-Schander
Copy link
Author

sadly this does not solve my issue.
--log-junit= has still an abslute path and the error is the same

@kilatib
Copy link

kilatib commented Jul 3, 2024

It is because of the path out of a project that's why it not replaced.
So, I think you need for you:

  • replace the path somewhere where I save it outputPath
  • provide in your project the path inside your project
  • copy the result from that path to one stored in step 1.

It still seems to me that your docker container does not allow me to write to /var/folders ...
For the test, you could try to create their folder manually or mount into that folder some external folder.

@Artem-Schander
Copy link
Author

Artem-Schander commented Jul 3, 2024

I'm really sorry to bother you and every one subscribed to this issue. I feel dumb but I don't get at all what you mean.

because of the path out of a project

what does that mean? what path? /var/folders/k7/mpvywsws2y55tqb4x4m.. that path?

replace the path somewhere where I save it outputPath

every time i change the --log-junit to a path, no matter what path, it does not work. "Directory was not created"

provide in your project the path inside your project

what do you mean by that?

I'm at a point where it's about to get too much hustle. I think I will go back to vim-test yet another time. I don't get what I am making wrong and why it is such a pain to get it working. It's sad.


Maybe it would help to understand what exactly happens or need to happen.

I have the following sutuation.. the shell script results (among others) in the following command.

docker exec -i d8e1cfc02e67 php -d memory_limit=-1 vendor/bin/phpunit tests/CityOffer/Models/TagModelTest.php --log-junit=/var/folders/k7/mpvywsws2y55tqb4x4mtym5h0000gn/T/nvim.artemschander/Tc3Aur/115

this does not work on my machine, but seems to be not wrong. phpunit is advised to put a junit log file named 115 into the directory /var/folders/k7/mpvywsws2y55tqb4x4mtym5h0000gn/T/nvim.artemschander/Tc3Aur/

I assume that this is some kind of a temporary directory for nvim where neotest is looking into and getting the status data from. if that is the case. could i work around my Directory was not created issue by creating the output file in my project directory and move it afterwards into the right spot?

Somewhat like this:

docker exec -i d8e1cfc02e67 php -d memory_limit=-1 vendor/bin/phpunit tests/CityOffer/Models/TagModelTest.php --log-junit=phpunit-result.xml
mv phpunit-result.xml var/folders/k7/mpvywsws2y55tqb4x4mtym5h0000gn/T/nvim.artemschander/Tc3Aur/115

Or maybe there is even a way to tell neotest that the junit log file is somewhere else?

I mean the only issue I am left with is the wrong Neotest status output. Where does neotest gets its status information from?

@kilatib
Copy link

kilatib commented Jul 4, 2024

@Artem-Schander , My Idea was that probably into your container is not allowed to create any dirs out of your PHP project dir.
So that's why I think when PHPUnit tries to create XML of test execution for /var/folders it couldn't because it is out of project for PHP.

What is the difference in your example with what neotest is called - you create result XML inside your PHP project dir where you have permission to write data.

The problem with Neotest is that after result XML is created under your project it not appeared to dir where neotest is waiting for it.

So, the solution for you is create it locally as you do in your example and then to copy it into the path which is expected by neotest

For that script please update 3 variables:

  • phpunitPath: with a path to your PHPUnit for it is: vendor/bin/phpunit
  • container: please put your just for test, in a future set containerName and id will taken automatically
  • localPhpUnitResultPath: and finally this one is for result in your case, it will be phpunit-result.xml
#!/bin/sh

# Customize the following:
phpunitPath=$REMOTE_PHPUNIT_BIN

# detect local path and remove from args
localPhpUnitResultPath='/tmp/phpunit-result.xml'
argsInput=${@}
runFile=$(echo $argsInput| awk '{print $1}')
phpTestPath=$(dirname "$runFile")
pushd $phpTestPath > /dev/null
projectPath="$(git rev-parse --show-toplevel)"
pushd > /dev/null

subPath=$(awk -F '/vendor/' '{print $1}' <<< $projectPath)
containerName=$(sed 's#.*/##' <<< $subPath | sed s/-/_/g)

## detect test result output
for i in $argsInput; do
    case $i in
        --log-junit=*)
            outputPath="${i#*=}"
            ;;
        *)
            ;;
    esac
done

# replace with local
args=("${argsInput/$subPath\//}")
args=("${args//(*}")

# Detect path
phpunitPath=$(docker exec -it $containerName /bin/bash -c "if [ -f vendor/bin/phpunit ]; then echo vendor/bin/phpunit; else echo bin/phpunit; fi" | tr -d '\r')
execPath=$(docker exec -it $containerName /bin/bash -c "if [ -f /bin/sh ]; then echo /bin/sh; else echo /bin/bash; fi" | tr -d '\r')
container=$(docker ps -n=-1 --filter name=$containerName --format="{{.ID}}")
dockerPath=$(docker inspect --format {{.Config.WorkingDir}} $container)

## debug
# echo "Raw ARGS: "${@}
# echo "Params:   "${args[@]}
# echo "Docker:   "$dockerPath
# echo "Local:    "$projectPath
# echo "Result:   "$outputPath

# Run the tests
docker exec -it $container $execPath -c "SYMFONY_DEPRECATIONS_HELPER=weak $phpunitPath -d memory_limit=-1 -d xdebug.idekey=deliver-be ${args} --log-junit=${localPhpUnitResultPath}"
# docker exec -it $container $phpunitPath -d memory_limit=-1 ${args[@]}

# copy results
docker cp -a "$container:$localPhpUnitResultPath" "$outputPath"|- &> /dev/null

# replace docker path to locals
sed -i '_' "s#$dockerPath#$projectPath#g" $outputPath

@Artem-Schander
Copy link
Author

Nice. thank you for all the help. it works now. I had to make some adjustments though.

Here is the final /usr/local/bin/dphpunit

# Customize the following:
containerName=$CONTAINER
phpunitPath=$REMOTE_PHPUNIT_BIN

# detect local path and remove from args
localPhpUnitResultPath='/tmp/phpunit-result.xml'
argsInput=${@}
runFile=$(echo $argsInput| awk '{print $1}')
phpTestPath=$(dirname "$runFile")
pushd $phpTestPath > /dev/null
projectPath="$(git rev-parse --show-toplevel)"
pushd > /dev/null

subPath=$(awk -F '/vendor/' '{print $1}' <<< $projectPath)
# containerName=$(sed 's#.*/##' <<< $subPath | sed s/-/_/g)

## detect test result output
for i in $argsInput; do
    case $i in
        --log-junit=*)
            outputPath="${i#*=}"
            ;;
        *)
            ;;
    esac
done

# replace with local
args=("${argsInput/$subPath\//}")
args=("${args//(*}")

# Detect path
container=$(docker ps -n=-1 --filter name=$containerName --format="{{.ID}}")
phpunitPath=$(docker exec -it $container /bin/bash -c "if [ -f vendor/bin/phpunit ]; then echo vendor/bin/phpunit; else echo bin/phpunit; fi" | tr -d '\r')
execPath=$(docker exec -it $container /bin/bash -c "if [ -f /bin/sh ]; then echo /bin/sh; else echo /bin/bash; fi" | tr -d '\r')
dockerPath=$(docker inspect --format {{.Config.WorkingDir}} $container)

## debug
# echo "Raw ARGS: "${@}
# echo "Params:   "${args[@]}
# echo "Docker:   "$dockerPath
# echo "Local:    "$projectPath
# echo "Result:   "$outputPath
# echo "docker exec -i "$container" php -d memory_limit=-1 "$phpunitPath" "${args[@]}

# Run the tests
docker exec -it $container $execPath -c "SYMFONY_DEPRECATIONS_HELPER=weak $phpunitPath -d memory_limit=-1 -d xdebug.idekey=deliver-be ${args} --log-junit=${localPhpUnitResultPath}"
# docker exec -it $container $phpunitPath -d memory_limit=-1 ${args[@]}

# copy results
docker cp -a "$container:$localPhpUnitResultPath" "$outputPath"|- &> /dev/null

# replace docker path to locals
sed -i '_' "s#$dockerPath#$projectPath#g" $outputPath

@eerison
Copy link

eerison commented Sep 13, 2024

Hey @kilatib

I am trying to make this work with codeception, But unfurtunally it just generate inside of tests/_output/phpunit-report.xml

it is the output

<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
  <testsuite name="App\Tests.Unit" tests="1" assertions="1" errors="0" failures="0" skipped="0" useless="0" time="0.007705">
    <testsuite name="App\Tests\Unit\MeasurementValues\Domain\Mapper\MeasurementMapperTest" file="/app/tests/Unit/MeasurementValues/Domain/Mapper/MeasurementMapperTest.php" tests="1" assertions="1" errors="0" failures="0" skipped="0" useless="0" time="0.007705">
      <testcase name="testPassObjectToArray" class="App\Tests\Unit\MeasurementValues\Domain\Mapper\MeasurementMapperTest" file="/app/tests/Unit/MeasurementValues/Domain/Mapper/MeasurementMapperTest.php" time="0.007705" assertions="1"/>
    </testsuite>
  </testsuite>
</testsuites>

then I changed this line

docker cp -a "$container:/app/tests/_output/phpunit-report.xml" "$outputPath" | - &>/dev/null

But the icons keep red, do you have any idea?

Edit just to compare

codeception --phpunit-xml

<?xml version="1.0" encoding="utf-8"?>
<testsuites>
  <testsuite name="app\tests.unit" tests="1" assertions="2" errors="0" failures="0" skipped="0" useless="0" time="0.019728">
    <testsuite name="app\tests\unit\measurementvalues\infrastructure\queue\task\measurementarchivingtasktest" file="/app/tests/unit/measurementvalues/infrastructure/queue/task/measurementarchivingtasktest.php" tests="1" assertions="2" errors="0" failures="0" skipped="0" useless="0" time="0.019728">
      <testcase name="testcallmethodtogeneratefile" class="app\tests\unit\measurementvalues\infrastructure\queue\task\measurementarchivingtasktest" file="/app/tests/unit/measurementvalues/infrastructure/queue/task/measurementarchivingtasktest.php" time="0.019728" assertions="2"/>
    </testsuite>
  </testsuite>
</testsuites>

codeception --xml

<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
  <testsuite name="App\Tests.Unit" tests="1" assertions="2" errors="0" failures="0" skipped="0" useless="0" time="0.024393">
    <testcase name="testCallMethodToGenerateFile" class="App\Tests\Unit\MeasurementValues\Infrastructure\Queue\Task\MeasurementArchivingTaskTest" file="/app/tests/Unit/MeasurementValues/Infrastructure/Queue/Task/MeasurementArchivingTaskTest.php" time="0.024393" assertions="2"/>
  </testsuite>
</testsuites>

phpunit --log-junit

<?xml version="1.0" encoding="UTF-8"?>
<testsuites name="PHPUnit tests">
  <testsuite name="App\Tests\Unit\MeasurementValues\Infrastructure\Queue\Task\MeasurementArchivingTaskTest" file="/app/tests/Unit/MeasurementValues/Infrastructure/Queue/Task/MeasurementArchivingTaskTest.php" tests="1" assertions="2" errors="0" failures="0" skipped="0" time="0.018385">
    <testcase name="testCallMethodToGenerateFile" file="/app/tests/Unit/MeasurementValues/Infrastructure/Queue/Task/MeasurementArchivingTaskTest.php" line="16" class="App\Tests\Unit\MeasurementValues\Infrastructure\Queue\Task\MeasurementArchivingTaskTest" classname="App.Tests.Unit.MeasurementValues.Infrastructure.Queue.Task.MeasurementArchivingTaskTest" assertions="2" time="0.018385"/>
  </testsuite>
</testsuites>

@kilatib
Copy link

kilatib commented Sep 17, 2024

Dear @eerison
Your problem that test runner expect to have result XML in other place not in _output/phpunit-report.xml in script which I provide you we have a parameter called outputPath could you please check that that value is same with expected by you, I think it is absolute and look inside or outside docker container so that reason why it cannot see the test result, just copy in the end of script your result to correct place

@eerison
Copy link

eerison commented Sep 17, 2024

Dear @eerison Your problem that test runner expect to have result XML in other place not in _output/phpunit-report.xml in script which I provide you we have a parameter called outputPath could you please check that that value is same with expected by you, I think it is absolute and look inside or outside docker container so that reason why it cannot see the test result, just copy in the end of script your result to correct place

Hey @kilatib

in your script you have this like to copy from container to host

docker cp -a "$container:$outputPath" "$outputPath" | - &>/dev/null

I changed to this

docker cp -a "$container:/app/tests/_output/phpunit-report.xml" "$outputPath" | - &>/dev/null

shouldn't it be enough? copy phpunit-report.xml to $outputPath ?

@kilatib
Copy link

kilatib commented Sep 17, 2024

Yes, I think so

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants