Page MenuHomePhabricator

D12598.id30252.diff
No OneTemporary

D12598.id30252.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -211,6 +211,11 @@
'ArcanistXMLLinterTestCase' => 'lint/linter/__tests__/ArcanistXMLLinterTestCase.php',
'ArcanistXUnitTestResultParser' => 'unit/parser/ArcanistXUnitTestResultParser.php',
'CSharpToolsTestEngine' => 'unit/engine/CSharpToolsTestEngine.php',
+ 'GoBaseTestEngine' => 'unit/engine/GoBaseTestEngine.php',
+ 'GoTestEngine' => 'unit/engine/GoTestEngine.php',
+ 'GoTestRaceEngine' => 'unit/engine/GoTestRaceEngine.php',
+ 'GodepGoTestEngine' => 'unit/engine/GodepGoTestEngine.php',
+ 'GodepGoTestRaceEngine' => 'unit/engine/GodepGoTestRaceEngine.php',
'NoseTestEngine' => 'unit/engine/NoseTestEngine.php',
'PhpunitTestEngine' => 'unit/engine/PhpunitTestEngine.php',
'PhpunitTestEngineTestCase' => 'unit/engine/__tests__/PhpunitTestEngineTestCase.php',
@@ -389,6 +394,11 @@
'ArcanistXMLLinter' => 'ArcanistLinter',
'ArcanistXMLLinterTestCase' => 'ArcanistLinterTestCase',
'CSharpToolsTestEngine' => 'XUnitTestEngine',
+ 'GoBaseTestEngine' => 'ArcanistUnitTestEngine',
+ 'GoTestEngine' => 'GoBaseTestEngine',
+ 'GoTestRaceEngine' => 'GoBaseTestEngine',
+ 'GodepGoTestEngine' => 'GoBaseTestEngine',
+ 'GodepGoTestRaceEngine' => 'GoBaseTestEngine',
'NoseTestEngine' => 'ArcanistUnitTestEngine',
'PhpunitTestEngine' => 'ArcanistUnitTestEngine',
'PhpunitTestEngineTestCase' => 'ArcanistTestCase',
diff --git a/src/unit/engine/GoBaseTestEngine.php b/src/unit/engine/GoBaseTestEngine.php
new file mode 100644
--- /dev/null
+++ b/src/unit/engine/GoBaseTestEngine.php
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * Go test Runner
+ */
+abstract class GoBaseTestEngine extends ArcanistUnitTestEngine {
+
+ /**
+ * testPackage must be defined by subclasses.
+ *
+ * @param $package The package path relative to the project root path
+ * @return command exit code
+ * @return stdout
+ * @return stderr
+ */
+ abstract protected function testPackage($package);
+
+ public function run() {
+ $this->affectedPackages = array();
+ foreach ($this->getPaths() as $path) {
+ // Must always test a package.
+ if (!is_dir($path)) {
+ // If it's a file but not a go file. Skip this test
+ if (substr($path, -3) != '.go') {
+ continue;
+ }
+
+ $path = dirname($path);
+ }
+
+ if (!array_key_exists($path, $this->affectedPackages)) {
+ $this->affectedPackages[] = $path;
+ }
+ }
+
+ if (empty($this->affectedPackages)) {
+ throw new ArcanistNoEffectException('No tests to run.');
+ }
+
+ $parser = new ArcanistGoTestResultParser();
+ $results = array();
+
+ foreach ($this->affectedPackages as $package) {
+ if ($package == '.') {
+ $package = '';
+ }
+ list($err, $stdout, $stderr) = $this->testPackage($package);
+ $r = $parser->parseTestResults(null, $stdout.$stderr);
+ $results = array_merge($results, $r);
+ }
+
+ return $results;
+ }
+}
diff --git a/src/unit/engine/GoTestEngine.php b/src/unit/engine/GoTestEngine.php
new file mode 100644
--- /dev/null
+++ b/src/unit/engine/GoTestEngine.php
@@ -0,0 +1,10 @@
+<?php
+
+/**
+ * Go test.
+ */
+final class GoTestEngine extends GoBaseTestEngine {
+ protected function testPackage($package) {
+ return exec_manual('go test -v ./%s', $package);
+ }
+}
diff --git a/src/unit/engine/GoTestRaceEngine.php b/src/unit/engine/GoTestRaceEngine.php
new file mode 100644
--- /dev/null
+++ b/src/unit/engine/GoTestRaceEngine.php
@@ -0,0 +1,10 @@
+<?php
+
+/**
+ * Go test with race detection enabled.
+ */
+final class GoTestRaceEngine extends GoBaseTestEngine {
+ protected function testPackage($package) {
+ return exec_manual('go test -race -v ./%s', $package);
+ }
+}
diff --git a/src/unit/engine/GodepGoTestEngine.php b/src/unit/engine/GodepGoTestEngine.php
new file mode 100644
--- /dev/null
+++ b/src/unit/engine/GodepGoTestEngine.php
@@ -0,0 +1,10 @@
+<?php
+
+/**
+ * Go test through Godep.
+ */
+final class GodepGoTestEngine extends GoBaseTestEngine {
+ protected function testPackage($package) {
+ return exec_manual('godep go test -v ./%s', $package);
+ }
+}
diff --git a/src/unit/engine/GodepGoTestRaceEngine.php b/src/unit/engine/GodepGoTestRaceEngine.php
new file mode 100644
--- /dev/null
+++ b/src/unit/engine/GodepGoTestRaceEngine.php
@@ -0,0 +1,10 @@
+<?php
+
+/**
+ * Go test through Godep with race detection enabled.
+ */
+final class GodepGoTestRaceEngine extends GoBaseTestEngine {
+ protected function testPackage($package) {
+ return exec_manual('godep go test -race -v ./%s', $package);
+ }
+}
diff --git a/src/unit/parser/ArcanistGoTestResultParser.php b/src/unit/parser/ArcanistGoTestResultParser.php
--- a/src/unit/parser/ArcanistGoTestResultParser.php
+++ b/src/unit/parser/ArcanistGoTestResultParser.php
@@ -25,7 +25,37 @@
// Temp store for test case results (in case we run multiple test cases)
$test_case_results = array();
- foreach ($test_results as $i => $line) {
+ for ($i = 0; $i < count($test_results); $i++) {
+ $line = $test_results[$i];
+
+ if (strncmp($line, '=== RUN', 6) === 0) {
+ $meta = array();
+ preg_match(
+ '/^=== RUN (?P<test_name>.+)/',
+ $line,
+ $meta);
+
+ if (strncmp($test_results[$i + 1], '==================', 19) === 0
+ && strncmp($test_results[$i + 2], 'WARNING: DATA RACE', 19) === 0) {
+ // We have a race condition
+ $i += 2; // Advance to the first goroutine
+ $reason = '';
+
+ // loop to collect all data and move to the === line
+ while (strncmp($test_results[$i], '==================', 19) !== 0) {
+ $reason .= $test_results[$i++]."\n";
+ }
+
+ $result = new ArcanistUnitTestResult();
+ $result->setName($meta['test_name']);
+ $result->setResult(ArcanistUnitTestResult::RESULT_FAIL);
+ $result->setUserData($reason);
+
+ $test_case_results[] = $result;
+
+ continue;
+ }
+ }
if (strncmp($line, '--- PASS', 8) === 0) {
// We have a passing test
diff --git a/src/unit/parser/__tests__/ArcanistGoTestResultParserTestCase.php b/src/unit/parser/__tests__/ArcanistGoTestResultParserTestCase.php
--- a/src/unit/parser/__tests__/ArcanistGoTestResultParserTestCase.php
+++ b/src/unit/parser/__tests__/ArcanistGoTestResultParserTestCase.php
@@ -39,6 +39,47 @@
$parsed_results[1]->getResult());
}
+ public function testRaceWarningTestCaseSuccess() {
+ $stubbed_results = Filesystem::readFile(
+ dirname(__FILE__).'/testresults/go.race-warning-test-case-success-go1.4');
+
+ $parsed_results = id(new ArcanistGoTestResultParser())
+ ->parseTestResults('racepackage_test.go', $stubbed_results);
+
+ $this->assertEqual(3, count($parsed_results));
+ $this->assertEqual(
+ ArcanistUnitTestResult::RESULT_PASS,
+ $parsed_results[0]->getResult());
+ $this->assertEqual(
+ ArcanistUnitTestResult::RESULT_FAIL,
+ $parsed_results[1]->getResult());
+ $this->assertEqual(
+ 'WARNING: DATA RACE',
+ idx(explode("\n", $parsed_results[1]->getUserData()), 0));
+ }
+
+ public function testRaceWarningTestCaseFailure() {
+ $stubbed_results = Filesystem::readFile(
+ dirname(__FILE__).'/testresults/go.race-warning-test-case-failure-go1.4');
+
+ $parsed_results = id(new ArcanistGoTestResultParser())
+ ->parseTestResults('racepackage_test.go', $stubbed_results);
+
+ $this->assertEqual(3, count($parsed_results));
+ $this->assertEqual(
+ ArcanistUnitTestResult::RESULT_PASS,
+ $parsed_results[0]->getResult());
+ $this->assertEqual(
+ ArcanistUnitTestResult::RESULT_FAIL,
+ $parsed_results[1]->getResult());
+ $this->assertEqual(
+ 'WARNING: DATA RACE',
+ idx(explode("\n", $parsed_results[1]->getUserData()), 0));
+ $this->assertEqual(
+ "racepackage_test.go:30: got: 2, want: 1\n",
+ $parsed_results[2]->getUserData());
+ }
+
public function testMultipleTestCasesSuccessful() {
$stubbed_results = Filesystem::readFile(
dirname(__FILE__).'/testresults/go.multiple-test-cases-successful');
diff --git a/src/unit/parser/__tests__/testresults/go.race-warning-test-case-failure-go1.4 b/src/unit/parser/__tests__/testresults/go.race-warning-test-case-failure-go1.4
new file mode 100644
--- /dev/null
+++ b/src/unit/parser/__tests__/testresults/go.race-warning-test-case-failure-go1.4
@@ -0,0 +1,29 @@
+=== RUN TestFoo
+--- PASS: TestFoo (0.03s)
+=== RUN TestBar
+==================
+WARNING: DATA RACE
+Write by goroutine 8:
+ racepackage.func~002()
+ /tmp/racepackage_test.go:21 +0x5d
+
+Previous write by goroutine 7:
+ racepackage.func~001()
+ /tmp/racepackage_test.go:17 +0x5d
+
+Goroutine 8 (running) created at:
+ racepackage.TestBar()
+ /tmp/racepackage_test.go:22 +0x1e8
+ testing.tRunner()
+ /usr/local/Cellar/go/1.4.2/libexec/src/testing/testing.go:447 +0x133
+
+Goroutine 7 (finished) created at:
+ racepackage.TestBar()
+ /tmp/racepackage_test.go:18 +0x13e
+ testing.tRunner()
+ /usr/local/Cellar/go/1.4.2/libexec/src/testing/testing.go:447 +0x133
+==================
+--- FAIL: TestBar (0.02s)
+ racepackage_test.go:30: got: 2, want: 1
+PASS
+ok package/racepackage 0.042s
diff --git a/src/unit/parser/__tests__/testresults/go.race-warning-test-case-success-go1.4 b/src/unit/parser/__tests__/testresults/go.race-warning-test-case-success-go1.4
new file mode 100644
--- /dev/null
+++ b/src/unit/parser/__tests__/testresults/go.race-warning-test-case-success-go1.4
@@ -0,0 +1,28 @@
+=== RUN TestFoo
+--- PASS: TestFoo (0.03s)
+=== RUN TestBar
+==================
+WARNING: DATA RACE
+Write by goroutine 8:
+ racepackage.func~002()
+ /tmp/racepackage_test.go:21 +0x5d
+
+Previous write by goroutine 7:
+ racepackage.func~001()
+ /tmp/racepackage_test.go:17 +0x5d
+
+Goroutine 8 (running) created at:
+ racepackage.TestBar()
+ /tmp/racepackage_test.go:22 +0x1e8
+ testing.tRunner()
+ /usr/local/Cellar/go/1.4.2/libexec/src/testing/testing.go:447 +0x133
+
+Goroutine 7 (finished) created at:
+ racepackage.TestBar()
+ /tmp/racepackage_test.go:18 +0x13e
+ testing.tRunner()
+ /usr/local/Cellar/go/1.4.2/libexec/src/testing/testing.go:447 +0x133
+==================
+--- PASS: TestBar (0.01s)
+PASS
+ok package/racepackage 0.042s

File Metadata

Mime Type
text/plain
Expires
Tue, Apr 22, 3:34 AM (4 d, 12 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7730790
Default Alt Text
D12598.id30252.diff (10 KB)

Event Timeline