Page MenuHomePhabricator

Add a Go unit test engine (through go and godep).
AbandonedPublic

Authored by eMxyzptlk on Apr 24 2015, 8:24 AM.
Tags
None
Referenced Files
F13089221: D12537.diff
Thu, Apr 25, 1:42 AM
Unknown Object (File)
Thu, Apr 11, 9:31 AM
Unknown Object (File)
Sun, Apr 7, 3:30 PM
Unknown Object (File)
Sat, Apr 6, 4:06 PM
Unknown Object (File)
Wed, Apr 3, 11:40 PM
Unknown Object (File)
Fri, Mar 29, 11:00 PM
Unknown Object (File)
Thu, Mar 28, 2:40 PM
Unknown Object (File)
Mar 5 2024, 9:34 AM

Details

Reviewers
None
Group Reviewers
Blessed Reviewers
Maniphest Tasks
T6867: Add linter and unit test engine for Go(lang)
Summary

This Differential adds two new unit engines both are for Golang and both uses
ArcanistGoTestResultParser to parse the result.

Test Plan

Test in https://github.com/julienschmidt/httprouter, must add the following arcconfig file

{
  "phabricator.uri" : "https://secure.phabricator.com/",
  "unit.engine": "GoTestEngine"
}

Then make a breaking change and run 'arc unit'.

Example output:

   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestPathClean
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestPathCleanMallocs
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestParams
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestRouter
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestRouterAPI
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestRouterRoot
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestRouterNotAllowed
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestRouterNotFound
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestRouterPanicHandler
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestRouterLookup
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestRouterServeFiles
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestCountParams
   FAIL  Go::Test::github.com::julienschmidt::httprouter::TestTreeAddAndGet
tree_test.go:100: maxParams mismatch for node 'ntact': is 0, should be 0

   FAIL  Go::Test::github.com::julienschmidt::httprouter::TestTreeWildcard
tree_test.go:100: maxParams mismatch for node ':query': is 1, should be 1

   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestTreeWildcardConflict
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestTreeChildConflict
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestTreeDupliatePath
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestEmptyWildcardName
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestTreeCatchAllConflict
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestTreeCatchAllConflictRoot
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestTreeDoubleWildcard
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestTreeTrailingSlashRedirect
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestTreeFindCaseInsensitivePath
   PASS   <1ms★  Go::Test::github.com::julienschmidt::httprouter::TestTreeInvalidNodeType

Diff Detail

Repository
rARC Arcanist
Branch
go-unit-engine
Lint
Lint Passed
Unit
Tests Passed
Build Status
Buildable 5500
Build 5519: [Placeholder Plan] Wait for 30 Seconds

Event Timeline

eMxyzptlk retitled this revision from to Add a Go unit test engine (through go and godep)..
eMxyzptlk updated this object.
eMxyzptlk edited the test plan for this revision. (Show Details)
eMxyzptlk added a reviewer: Blessed Reviewers.
eMxyzptlk added subscribers: ox, epriestley.
eMxyzptlk edited edge metadata.
  • remove an accidently left 'echo'
  • Fix GodepGoTestEngine by requiring an sprintf format

I have a version of this with coverage support if you're interested:

<?php

final class ConfigurableGolangTestEngine extends ArcanistUnitTestEngine {

  public function run() {
    $working_copy = $this->getWorkingCopy();
    $this->project_root = $working_copy->getProjectRoot();

    $cover_tmp = new TempFile();
    $junit_tmp = new TempFile();

    $future = $this->buildTestFuture($junit_tmp, $cover_tmp);
    $future->resolvex();

    return $this->parseTestResults($junit_tmp, $cover_tmp);
  }

  public function buildTestFuture($junit_tmp, $cover_tmp) {
    $paths = $this->getPaths();
    $config_manager = $this->getConfigurationManager();
    $coverage_command = $config_manager
      ->getConfigFromAnySource('unit.golang.command');
    $cmd_line = csprintf($coverage_command, $junit_tmp, $cover_tmp);

    return new ExecFuture('%C', $cmd_line);
  }

  public function parseTestResults($junit_tmp, $cover_tmp) {
    $parser = new ArcanistXUnitTestResultParser();
    $results = $parser->parseTestResults(
      Filesystem::readFile($junit_tmp));

    if ($this->getEnableCoverage() !== false) {
      $coverage_report = $this->readCoverage($cover_tmp);
      foreach ($results as $result) {
          $result->setCoverage($coverage_report);
      }
    }

    return $results;
  }

  public function readCoverage($path) {
    $coverage_data = Filesystem::readFile($path);
    if (empty($coverage_data)) {
       return array();
    }

    $coverage_dom = new DOMDocument();
    $coverage_dom->loadXML($coverage_data);

    $paths = $this->getPaths();
    $reports = array();
    $classes = $coverage_dom->getElementsByTagName('class');

    $cwd = getcwd();

    foreach ($classes as $class) {
      $absolute_path = $class->getAttribute('filename');
      $relative_path = str_replace($cwd.'/', '', $absolute_path);

      if (is_file($absolute_path.'.go')) {
        $relative_path .= '.go';
        $absolute_path .= '.go';
      }

      if (!file_exists($absolute_path)) {
        continue;
      }

      // get total line count in file
      $line_count = count(file($absolute_path));

      $coverage = '';
      $start_line = 1;
      $lines = $class->getElementsByTagName('line');
      for ($ii = 0; $ii < $lines->length; $ii++) {
        $line = $lines->item($ii);

        $next_line = intval($line->getAttribute('number'));
        for ($start_line; $start_line < $next_line; $start_line++) {
            $coverage .= 'N';
        }

        if (intval($line->getAttribute('hits')) == 0) {
            $coverage .= 'U';
        }
        else if (intval($line->getAttribute('hits')) > 0) {
            $coverage .= 'C';
        }

        $start_line++;
      }

      if ($start_line < $line_count) {
        foreach (range($start_line, $line_count) as $line_num) {
          $coverage .= 'N';
        }
      }

      $reports[$relative_path] = $coverage;
    }

    return $reports;
  }

}

I have a version of this with coverage support if you're interested:

That's perfect thank you!

public function buildTestFuture($junit_tmp, $cover_tmp) {
  $paths = $this->getPaths();
  $config_manager = $this->getConfigurationManager();
  $coverage_command = $config_manager
    ->getConfigFromAnySource('unit.golang.command');
  $cmd_line = csprintf($coverage_command, $junit_tmp, $cover_tmp);

Oh cool, I did not know that you can actually configure the engine as such! I'm going to combine D12598 D12546 and D12537 into one Differential that is configurable.