orchestral/testbench

Unable to run tests using Github Actions Runner

Closed this issue ยท 8 comments

  • Testbench Version: v5+ (5, 6 and 7 for laravel versions 7-9)
  • Laravel Version: 7+ (7, 8 and 9)
  • PHP Version: 7.4+ (7.4, 8.0, and 8.1)
  • Database Driver & Version: N/A

Description:

Running unit tests with Github Actions renders errors for every test, complaining about an un-writable directory:

Exception: The /home/runner/work/<repository>/vendor/orchestra/testbench-core/laravel/bootstrap/cache directory must be present and writable.

Steps To Reproduce:

Any PHP version 7.4+ should work, this package is being written for all laravel versions 7+, and therefore supports PHP 7.4, 8.0 and 8.1. Each version of Laravel, PHP and Orchestra is failing with the same issue.

Create a new laravel package using orchestra/testbench and setup any test case (can be unit, doesn't need to use a DB). Use the following GH workflow yaml and run it. It will fail.

name: Test
on:
  push:

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        php: ["7.4", "8.0", "8.1"]
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Composer
        uses: php-actions/composer@v5
        with:
          php_version: ${{ matrix.php }}
      - name: Run Tests
        run: vendor/bin/phpunit --no-coverage

I found this issue that I hoped would help solve my problem. It did not, as one cannot change ownership of GH action runner directories.

Not sure why Laravel project tests can run but Orchestra cannot. Please advise.

Unable to replicate, Testbench own repository uses GitHub Actions without issue.

thanks for the help!

As you can see I run my tests with vendor/bin/phpunit, same as this repository. However, this does not work and I'm not sure why.

I've had to do a chown as sudo which, while alarming, does solve the problem.

I fail to see how this isn't an issue with testbench that should at least be investigated. Apologies for excluding links initially, the repository in question was private at the time. But the links show a very simple laravel package testing setup - no frills or anything out of the ordinary - and yet the test suite fails out of the box.

coming back almost 1y later. whipped up a fresh laravel package, installed testbench, same issue in GH actions.

chown'ing fixes it yet again

still not seeing how this isn't a testbench issue :)

still not seeing how this isn't a testbench issue :)

My response was I am not able to replicate the issue, therefore I am not able to fix something that I can't reproduce. Same as you I do create new packages from time to time using Testbench and GitHub Actions and never came across this issue.

P/S: Also did you notice that no one else report anything similar to your issue?

"works on my machine"

better ship it ๐Ÿ˜„

"works on my machine"

Nope, work on my GitHub Actions, I guess yours is different?

not substantially.

Started having this issue now as well. I don't know when it started for me, just got the error after not having run tests for quite a few months on a package.

1) GeneaLabs\LaravelModelCaching\Tests\Feature\Nova\BelongsToManyTest::testAttachRelationFlushesCache
Exception: The /workspaces/laravel-model-caching/vendor/orchestra/testbench-core/laravel/bootstrap/cache directory must be present and writable.

/workspaces/laravel-model-caching/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php:188
/workspaces/laravel-model-caching/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php:163
/workspaces/laravel-model-caching/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php:61
/workspaces/laravel-model-caching/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:745
/workspaces/laravel-model-caching/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/RegisterProviders.php:17
/workspaces/laravel-model-caching/vendor/orchestra/testbench-core/src/Concerns/CreatesApplication.php:359
/workspaces/laravel-model-caching/vendor/orchestra/testbench-core/src/Concerns/CreatesApplication.php:228
/workspaces/laravel-model-caching/vendor/orchestra/testbench-browser-kit/src/TestCase.php:105
/workspaces/laravel-model-caching/vendor/orchestra/testbench-core/src/Concerns/Testing.php:86
/workspaces/laravel-model-caching/vendor/orchestra/testbench-browser-kit/src/TestCase.php:37
/workspaces/laravel-model-caching/tests/CreatesApplication.php:30
/workspaces/laravel-model-caching/tests/NovaTestCase.php:21

Here is my NovaTestCase:

<?php

namespace GeneaLabs\LaravelModelCaching\Tests;

use GeneaLabs\LaravelModelCaching\Tests\Fixtures\Nova\AuthorResource;
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\Nova\BookResource;
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\Nova\StoreResource;
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\Providers\NovaServiceProvider;
use Illuminate\Contracts\Auth\Authenticatable;
use Laravel\Nova\Nova;
use Laravel\Nova\NovaCoreServiceProvider;

abstract class NovaTestCase extends FeatureTestCase
{
    protected $response;

    protected $authenticatedAs;

    public function setUp(): void
    {
        parent::setUp();

        Nova::$tools = [];
        Nova::$resources = [];

        Nova::resources([
            AuthorResource::class,
            BookResource::class,
            StoreResource::class,
        ]);

        Nova::auth(function () {
            return true;
        });

        $this->authenticate();
    }

    protected function authenticate()
    {
        $this->actingAs($this->authenticatedAs = \Mockery::mock(Authenticatable::class));

        $this->authenticatedAs->shouldReceive('getAuthIdentifier')->andReturn(1);
        $this->authenticatedAs->shouldReceive('getKey')->andReturn(1);

        return $this;
    }

    protected function getPackageProviders($app)
    {
        return array_merge(
            parent::getPackageProviders($app),
            [
                NovaCoreServiceProvider::class,
                \Laravel\Nova\NovaServiceProvider::class,
                NovaServiceProvider::class,
            ]
        );
    }
}

CreatesApplication:

<?php namespace GeneaLabs\LaravelModelCaching\Tests;

use GeneaLabs\LaravelModelCaching\Providers\Service as LaravelModelCachingService;
use Illuminate\Auth\Middleware\Authenticate;
use Illuminate\Support\Facades\Artisan;
use Laravel\Nova\Http\Middleware\Authorize;
use Laravel\Nova\Http\Middleware\BootTools;
use Laravel\Nova\Http\Middleware\DispatchServingNovaEvent;

trait CreatesApplication
{
    private static $baseLineDatabaseMigrated = false;

    protected $cache;
    protected $testingSqlitePath;

    protected function cache()
    {
        $cache = app('cache');

        if (config('laravel-model-caching.store')) {
            $cache = $cache->store(config('laravel-model-caching.store'));
        }

        return $cache;
    }

    public function setUp() : void
    {
        parent::setUp();

        $this->setUpBaseLineSqlLiteDatabase();

        $databasePath = __DIR__ . "/database";
        $this->testingSqlitePath = "{$databasePath}/";
        $baselinePath = "{$databasePath}/baseline.sqlite";
        $testingPath = "{$databasePath}/testing.sqlite";

        ! file_exists($testingPath)
            ?: unlink($testingPath);
        copy($baselinePath, $testingPath);

        require(__DIR__ . '/routes/web.php');

        $this->withFactories(__DIR__ . '/database/factories');

        view()->addLocation(__DIR__ . '/resources/views', 'laravel-model-caching');

        if (! file_exists(base_path("bootstrap/cache"))) {
            mkdir(base_path("bootstrap/cache"), 0777, true);
        }

        $this->cache = app('cache')
            ->store(config('laravel-model-caching.store'));
        $this->cache()->flush();
    }

    /**
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    protected function getPackageProviders($app)
    {
        return [
            LaravelModelCachingService::class,
        ];
    }

    public function setUpBaseLineSqlLiteDatabase()
    {
        if (self::$baseLineDatabaseMigrated) {
            return;
        }

        self::$baseLineDatabaseMigrated = true;

        $file = __DIR__ . '/database/baseline.sqlite';
        $this->app['config']->set('database.default', 'baseline');
        $this->app['config']->set('database.connections.baseline', [
            'driver' => 'sqlite',
            "url" => null,
            'database' => $file,
            'prefix' => '',
            "foreign_key_constraints" => false,
        ]);

        ! file_exists($file)
            ?: unlink($file);
        touch($file);

        $this->withFactories(__DIR__ . '/database/factories');
        $this->loadMigrationsFrom(__DIR__ . '/database/migrations');

        Artisan::call('db:seed', [
            '--class' => 'DatabaseSeeder',
            '--database' => 'baseline',
        ]);

        $this->app['config']->set('database.default', 'testing');
    }

    protected function getEnvironmentSetUp($app)
    {
        $app['config']->set('database.default', 'testing');
        $app['config']->set('database.connections.testing', [
            'driver' => 'sqlite',
            'database' => __DIR__ . '/database/testing.sqlite',
            'prefix' => '',
            "foreign_key_constraints" => false,
        ]);
        $app['config']->set('database.redis.client', "phpredis");
        $app['config']->set('database.redis.cache', [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'port' => env('REDIS_PORT', 6379),
        ]);
        $app['config']->set('database.redis.default', [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'port' => env('REDIS_PORT', 6379),
        ]);
        $app['config']->set('database.redis.model-cache', [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 1,
        ]);
        $app['config']->set('cache.stores.model', [
            'driver' => 'redis',
            'connection' => 'model-cache',
        ]);
        $app['config']->set('laravel-model-caching.store', 'model');
        $app['config']->set("nova", [
            'name' => 'Nova Site',
            'url' => env('APP_URL', '/'),
            'path' => '/nova',
            'guard' => env('NOVA_GUARD', null),
            'middleware' => [
                'web',
                Authenticate::class,
                DispatchServingNovaEvent::class,
                BootTools::class,
                Authorize::class,
            ],
            'pagination' => 'simple',
        ]);
    }

    public function appVersionEightAndUp(): bool
    {
        return version_compare(app()->version(), '8.0.0', '>=');
    }

    public function appVersionFiveBetweenSeven(): bool
    {
        return version_compare(app()->version(), '5.6.0', '>=') && version_compare(app()->version(), '8.0.0', '<');
    }

    public function appVersionOld(): bool
    {
        return version_compare(app()->version(), '5.4.0', '>=') && version_compare(app()->version(), '5.6.0', '<');
    }
}

I was only able to get my tests running in my Codespace after running the following:

sudo chmod -R 0777 vendor/orchestra/testbench-core/laravel/bootstrap/*
sudo chmod -R 0777 vendor/orchestra/testbench-core/laravel/storage/*