madsem's avatar

Test passes locally, but fails during CI (GH actions)

I'm having a curious case of a feature test here.

During an import of a large csv file, a temporary mysql table is created. The csv file is loaded into the tmp table using LOAD DATA LOCAL INFILE.

Then, using a raw Insert ON DUPLICATE KEY UPDATE query, the data from the temporary table is written into the final models table.

The tests are passing local (funnily though only when I'm using the DatabaseMigrations trait, it fails also locally when I use RefreshDatabase).

On Github Actions during my CI flow, it always fails though... I honestly have no more idea why this happens, hope someone can point me in the right direction here :)

Here is the code:

The part in my importer class that triggers the above mentioned process:

       //  load csv into tmp table.
        $tmpTable = $this->load($this->pending->file, self::Columns);

        // insert from temporary table into criteria_performance_reports, update duplicate keys.
        $target = with(new CriteriaPerformanceSummaryReport)->getTable();
        $this->query->execute($target, $tmpTable, self::Columns);

first, the tmp table is created, then loadData executes the LOAD DATA... query.

public function load(string $file, array $columns): string
    {
        $table = $this->createTemporaryTable($columns);
        $this->loadData($file, $table, $columns);

        return $table;
    }
private function createTemporaryTable($columns)
    {
        $now = Carbon::now();
        $table = 'temporary_'
            .strtolower(Str::random(10))
            .'_'
            .$now->microsecond
            .'_'
            .$now->format('Y_M_d');

        Schema::connection($this->connection)
              ->create($table, function ($table) use ($columns) {
                  foreach ($columns as $column) {
                      $table->string($column)->nullable();
                  }

                  $table->temporary();
              });

        return $table;
    }
public function execute(string $targetTable, string $fromTable, array $columns): bool
    {
        $targetColumns = implode(',', $columns);
        $values = 't.'.implode(',t.', $columns);

        $update = array_combine(
            explode(',', $targetColumns),
            explode(',', $values)
        );
        $update = http_build_query($update, '', ',');

        $sql = "INSERT INTO $targetTable ($targetColumns) ".
            "SELECT $values ".
            "FROM $fromTable t ".
            "ON DUPLICATE KEY UPDATE $update";

        return DB::statement($sql);
    }

The code works, it's all imported etc. The problem really is that this test fails (Locally it only fails if used with RefreshDatabase trait), on GH actions it always fails:

public function it_imports_keyword_performance_report()
    {
        $file = $this->remoteService->get('KeywordPerformanceTest.csv');

        PendingFile::factory()->create([
            'file' => $file,
            'importable' => CriteriaPerformanceSummaryReportImportable::class,
        ]);

        $this->artisan('import-pending-files')
             ->assertExitCode(0)
             ->run();

        $this->assertNotNull(CriteriaPerformanceSummaryReport::first());
    }

Result:

There was 1 failure:
17

18
1) Tests\Feature\Console\Commands\ImportPendingFilesCommandTest::it_imports_keyword_performance_report
19
Failed asserting that null is not null.
0 likes
1 reply
madsem's avatar

So this happens (I think), because phpunit (When refreshing database), and also GH actions workflow somehow have a different db session when trying to select from the temporary table. As these tables only exist during a session and are then destroyed.

Is there any way to force phpunit to keep using the same session?

Please or to participate in this conversation.