olimorris / neotest-phpunit

๐Ÿงช Neotest adapter for PHPUnit
MIT License
29 stars 22 forks source link

How do I run Test from within Docker? #11

Closed Artem-Schander closed 5 months ago

Artem-Schander commented 1 year ago

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 commented 1 year ago

No idea.

I'm not sure it's possible right now though: https://github.com/nvim-neotest/neotest/issues/89

Artem-Schander commented 1 year ago

Oh.. then I'll wait

phaberest commented 1 year ago

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

Artem-Schander commented 1 year ago

@phaberest I tried.. did not work.

phaberest commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

https://github.com/olimorris/neotest-phpunit/commit/cb4808cb3ad96ffa6f515a04857b9e068348a6df shuld be able to solve the issue, thank you @olimorris

olimorris commented 1 year ago

https://github.com/olimorris/neotest-phpunit/commit/cb4808cb3ad96ffa6f515a04857b9e068348a6df shuld be able to solve the issue, thank you @olimorris

Happy to accept any PRs for more user configurable options btw

Artem-Schander commented 1 year ago

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
phaberest commented 1 year ago

I'll give it a go tonight and give you an update ๐Ÿ™Œ๐Ÿป

haringsrob commented 1 year ago

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 commented 1 year ago

@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 commented 1 year ago

Based on some information here: https://github.com/nvim-neotest/neotest/issues/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 commented 1 year ago

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

haringsrob commented 1 year ago

#!/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 commented 1 year ago

@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 commented 1 year ago

@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 commented 11 months ago

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 commented 10 months ago

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 ๐Ÿ‘€

kilatib commented 8 months ago

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:

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 commented 5 months ago

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

Artem-Schander commented 2 months ago

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 commented 2 months ago

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

Artem-Schander commented 2 months ago

@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 commented 2 months ago

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

Artem-Schander commented 2 months ago

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 commented 2 months ago

@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 commented 2 months ago

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

kilatib commented 2 months ago

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

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 commented 2 months ago

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 commented 2 months ago

@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:

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 commented 2 months ago

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 commented 8 hours ago

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>