Skip to content

Commit

Permalink
Merge pull request #20179 from smarterclayton/update_tools
Browse files Browse the repository at this point in the history
Switch origin to use gotest2junit
  • Loading branch information
openshift-merge-robot authored Jul 4, 2018
2 parents ef616a7 + 5bd42aa commit 73171de
Show file tree
Hide file tree
Showing 16 changed files with 690 additions and 48 deletions.
2 changes: 0 additions & 2 deletions hack/lib/build/environment.sh
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,6 @@ function os::build::environment::cleanup() {
local container=$1
local volume=$2
local tmp_volume=$3
os::log::debug "Recording container information to ${LOG_DIR}/${container}.json"
docker inspect "${container}" > "${LOG_DIR}/${container}.json"
os::log::debug "Stopping container ${container}"
docker stop --time=0 "${container}" > /dev/null || true
if [[ -z "${OS_BUILD_ENV_LEAVE_CONTAINER:-}" ]]; then
Expand Down
2 changes: 1 addition & 1 deletion hack/lib/cmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ readonly -f os::cmd::try_until_text

# In order to harvest stderr and stdout at the same time into different buckets, we need to stick them into files
# in an intermediate step
os_cmd_internal_tmpdir="${TMPDIR:-"/tmp"}/openshift"
os_cmd_internal_tmpdir="${TMPDIR:-"/tmp"}/cmd"
os_cmd_internal_tmpout="${os_cmd_internal_tmpdir}/tmp_stdout.log"
os_cmd_internal_tmperr="${os_cmd_internal_tmpdir}/tmp_stderr.log"

Expand Down
10 changes: 3 additions & 7 deletions hack/lib/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,10 @@ os::log::stacktrace::install
os::util::environment::update_path_var

if [[ -z "${OS_TMP_ENV_SET-}" ]]; then
if [[ "${0}" =~ .*\.sh ]]; then
os::util::environment::setup_tmpdir_vars "$( basename "${0}" ".sh" )"
else
os::util::environment::setup_tmpdir_vars "shell"
fi
os::util::environment::setup_tmpdir_vars "$( basename "$0" ".sh" )"
fi

# Allow setting $JUNIT_REPORT to toggle output behavior
if [[ -n "${JUNIT_REPORT:-}" ]]; then
export JUNIT_REPORT_OUTPUT="${LOG_DIR}/raw_test_output.log"
fi
export JUNIT_REPORT_OUTPUT="${LOG_DIR}/raw_test_output.log"
fi
10 changes: 5 additions & 5 deletions hack/lib/log/output.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# Arguments:
# - all: message to write
function os::log::info() {
local message; message="$( os::log::internal::prefix_lines "[INFO] [$( date +%H:%M:%S%z )]" "$*" )"
local message; message="$( os::log::internal::prefix_lines "[INFO]" "$*" )"
os::log::internal::to_logfile "${message}"
echo "${message}"
}
Expand All @@ -21,7 +21,7 @@ readonly -f os::log::info
# Arguments:
# - all: message to write
function os::log::warning() {
local message; message="$( os::log::internal::prefix_lines "[WARNING] [$( date +%H:%M:%S%z )]" "$*" )"
local message; message="$( os::log::internal::prefix_lines "[WARNING]" "$*" )"
os::log::internal::to_logfile "${message}"
os::text::print_yellow "${message}" 1>&2
}
Expand All @@ -34,7 +34,7 @@ readonly -f os::log::warning
# Arguments:
# - all: message to write
function os::log::error() {
local message; message="$( os::log::internal::prefix_lines "[ERROR] [$( date +%H:%M:%S%z )]" "$*" )"
local message; message="$( os::log::internal::prefix_lines "[ERROR]" "$*" )"
os::log::internal::to_logfile "${message}"
os::text::print_red "${message}" 1>&2
}
Expand All @@ -48,7 +48,7 @@ readonly -f os::log::error
# Arguments:
# - all: message to write
function os::log::fatal() {
local message; message="$( os::log::internal::prefix_lines "[FATAL] [$( date +%H:%M:%S%z )]" "$*" )"
local message; message="$( os::log::internal::prefix_lines "[FATAL]" "$*" )"
os::log::internal::to_logfile "${message}"
os::text::print_red "${message}" 1>&2
exit 1
Expand All @@ -63,7 +63,7 @@ readonly -f os::log::fatal
# Arguments:
# - all: message to write
function os::log::debug() {
local message; message="$( os::log::internal::prefix_lines "[DEBUG] [$( date +%H:%M:%S%z )]" "$*" )"
local message; message="$( os::log::internal::prefix_lines "[DEBUG]" "$*" )"
os::log::internal::to_logfile "${message}"
if [[ -n "${OS_DEBUG:-}" ]]; then
os::text::print_blue "${message}" 1>&2
Expand Down
2 changes: 0 additions & 2 deletions hack/lib/test/junit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,6 @@ function os::test::junit::generate_report() {
os::test::junit::reconcile_output
os::test::junit::check_test_counters
os::test::junit::internal::generate_report "oscmd"
else
os::test::junit::internal::generate_report "gotest"
fi
}

Expand Down
14 changes: 0 additions & 14 deletions hack/push-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,6 @@ if [[ "${OS_PUSH_BASE_REGISTRY-}" != "" || "${tag}" != "" ]]; then
docker tag "openshift/${image}:${source_tag}" "${OS_PUSH_BASE_REGISTRY-}${OS_PUSH_BASE_REPO}${image}${tag}"
done
done
# TODO: remove in 3.11
for tag in "${tags[@]}"; do
docker tag "openshift/origin-control-plane:${source_tag}" "${OS_PUSH_BASE_REGISTRY-}${OS_PUSH_BASE_REPO}origin${tag}"
docker tag "openshift/origin-node:${source_tag}" "${OS_PUSH_BASE_REGISTRY-}${OS_PUSH_BASE_REPO}node${tag}"
done
fi

for image in "${images[@]}"; do
Expand All @@ -83,14 +78,5 @@ for image in "${images[@]}"; do
docker push ${PUSH_OPTS} "${OS_PUSH_BASE_REGISTRY-}${OS_PUSH_BASE_REPO}${image}${tag}"
done
done
# TODO: remove in 3.11
for tag in "${tags[@]}"; do
os::log::info "Pushing ${OS_PUSH_BASE_REGISTRY-}${OS_PUSH_BASE_REPO}origin${tag}..."
docker push ${PUSH_OPTS} "${OS_PUSH_BASE_REGISTRY-}${OS_PUSH_BASE_REPO}origin${tag}"
done
for tag in "${tags[@]}"; do
os::log::info "Pushing ${OS_PUSH_BASE_REGISTRY-}${OS_PUSH_BASE_REPO}node${tag}..."
docker push ${PUSH_OPTS} "${OS_PUSH_BASE_REGISTRY-}${OS_PUSH_BASE_REPO}node${tag}"
done

ret=$?; ENDTIME=$(date +%s); echo "$0 took $(($ENDTIME - $STARTTIME)) seconds"; exit "$ret"
16 changes: 4 additions & 12 deletions hack/test-go.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,6 @@
function cleanup() {
return_code=$?

os::test::junit::generate_report
if [[ "${JUNIT_REPORT_NUM_FAILED:-}" == "0 failed" ]]; then
if [[ "${return_code}" -ne "0" ]]; then
os::log::warning "While the jUnit report found no failed tests, the \`go test\` process failed."
os::log::warning "This usually means that the unit test suite failed to compile."
fi
fi

os::util::describe_return_code "${return_code}"
exit "${return_code}"
}
Expand Down Expand Up @@ -136,8 +128,10 @@ if [[ -n "${junit_report}" ]]; then
# we don't care if the `go test` fails in this pipe, as we want to generate the report and summarize the output anyway
set +o pipefail

go test -i ${gotest_flags} ${test_packages}
go test ${gotest_flags} ${test_packages} 2>"${test_error_file}" | tee "${JUNIT_REPORT_OUTPUT}"
os::util::ensure::built_binary_exists 'gotest2junit'
report_file="$( mktemp "${ARTIFACT_DIR}/unit_report_XXXXX" ).xml"

go test -json ${gotest_flags} ${test_packages} 2>"${test_error_file}" | tee "${JUNIT_REPORT_OUTPUT}" | gotest2junit > "${report_file}"

test_return_code="${PIPESTATUS[0]}"

Expand All @@ -163,7 +157,6 @@ $( cat "${test_error_file}") "

elif [[ -n "${coverage_output_dir}" ]]; then
# we need to generate coverage reports
go test -i ${gotest_flags} ${test_packages}
for test_package in ${test_packages}; do
mkdir -p "${coverage_output_dir}/${test_package}"
local_gotest_flags="${gotest_flags} -coverprofile=${coverage_output_dir}/${test_package}/profile.out"
Expand All @@ -188,6 +181,5 @@ elif [[ -n "${dlv_debug}" ]]; then
dlv test ${test_packages}
else
# we need to generate neither jUnit XML nor coverage reports
go test -i ${gotest_flags} ${test_packages}
go test ${gotest_flags} ${test_packages}
fi
211 changes: 211 additions & 0 deletions tools/gotest2junit/gotest2junit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
package main

import (
"bufio"
"encoding/json"
"encoding/xml"
"flag"
"fmt"
"io"
"os"
"sort"
"strings"
"time"

"github.com/openshift/origin/tools/gotest2junit/pkg/api"
)

type Record struct {
Package string
Test string

Time time.Time
Action string
Output string
Elapsed float64
}

type testSuite struct {
suite *api.TestSuite
tests map[string]*api.TestCase
}

func main() {
summarize := false
verbose := false
flag.BoolVar(&summarize, "summary", true, "display a summary as items are processed")
flag.BoolVar(&verbose, "v", false, "display passing results")
flag.Parse()

if err := process(os.Stdin, summarize, verbose); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
}

func process(r io.Reader, summarize, verbose bool) error {
suites, err := stream(r, summarize, verbose)
if err != nil {
return err
}
obj := newTestSuites(suites)
out, err := xml.MarshalIndent(obj, "", " ")
if err != nil {
return err
}
fmt.Fprintf(os.Stdout, "%s\n", string(out))
return nil
}

func newTestSuites(suites map[string]*testSuite) *api.TestSuites {
all := &api.TestSuites{}
for _, suite := range suites {
for _, test := range suite.suite.TestCases {
suite.suite.NumTests++
if test.SkipMessage != nil {
suite.suite.NumSkipped++
continue
}
if test.FailureOutput != nil {
suite.suite.NumFailed++
continue
}
}
// suites with no tests are usually empty packages, ignore them
if suite.suite.NumTests == 0 {
continue
}
// always return the test cases in consistent order
sort.Slice(suite.suite.TestCases, func(i, j int) bool {
return suite.suite.TestCases[i].Name < suite.suite.TestCases[j].Name
})
all.Suites = append(all.Suites, suite.suite)
}
// always return the test suites in consistent order
sort.Slice(all.Suites, func(i, j int) bool {
return all.Suites[i].Name < all.Suites[j].Name
})
return all
}

func stream(r io.Reader, summarize, verbose bool) (map[string]*testSuite, error) {
suites := make(map[string]*testSuite)
defaultTest := &api.TestCase{
Name: "build and execution",
}
defaultSuite := &testSuite{
suite: &api.TestSuite{Name: "go test", TestCases: []*api.TestCase{defaultTest}},
}
suites[""] = defaultSuite

rdr := bufio.NewReader(r)
for {
// some output from go test -json is not valid JSON - read the line to see whether it
// starts with { - if not, just mirror it to stderr and continue.
line, err := rdr.ReadString('\n')
if err != nil {
if err != io.EOF {
return suites, err
}
break
}
if len(line) == 0 || line[0] != '{' {
defaultTest.SystemOut += line
if strings.HasPrefix(line, "FAIL") {
defaultTest.FailureOutput = &api.FailureOutput{}
}
fmt.Fprint(os.Stderr, line)
continue
}
var r Record
if err := json.Unmarshal([]byte(line), &r); err != nil {
if err == io.EOF {
return suites, nil
}
fmt.Fprintf(os.Stderr, "error: Unable to parse remainder of output %v\n", err)
return suites, nil
}

suite, ok := suites[r.Package]
if !ok {
suite = &testSuite{
suite: &api.TestSuite{
Name: r.Package,
},
tests: make(map[string]*api.TestCase),
}
suites[r.Package] = suite
}

// if this is package level output, we only care about pass/fail duration
if len(r.Test) == 0 {
switch r.Action {
case "pass", "fail":
suite.suite.Duration = r.Elapsed
}
continue
}

test, ok := suite.tests[r.Test]
if !ok {
test = &api.TestCase{
Name: r.Test,
}
suite.suite.TestCases = append(suite.suite.TestCases, test)
suite.tests[r.Test] = test
}

switch r.Action {
case "run":
case "pause":
case "cont":
case "bench":
case "skip":
if summarize {
fmt.Fprintf(os.Stderr, "SKIP: %s %s\n", r.Package, r.Test)
}
test.SkipMessage = &api.SkipMessage{
Message: r.Output,
}
case "pass":
if summarize && verbose {
fmt.Fprintf(os.Stderr, "PASS: %s %s %s\n", r.Package, r.Test, time.Duration(r.Elapsed*float64(time.Second)))
}
test.SystemOut = ""
test.Duration = r.Elapsed
case "fail":
if summarize {
fmt.Fprintf(os.Stderr, "FAIL: %s %s %s\n", r.Package, r.Test, time.Duration(r.Elapsed*float64(time.Second)))
}
test.Duration = r.Elapsed
if len(r.Output) == 0 {
r.Output = test.SystemOut
if len(r.Output) > 50 {
r.Output = r.Output[:50] + " ..."
}
}
test.FailureOutput = &api.FailureOutput{
Message: r.Output,
Output: r.Output,
}
case "output":
test.SystemOut += r.Output
default:
// usually a bug in go test -json
out := fmt.Sprintf("error: Unrecognized go test action %s: %#v\n", r.Action, r)
defaultTest.SystemOut += line
defaultTest.SystemOut += out
defaultTest.FailureOutput = &api.FailureOutput{}
fmt.Fprintf(os.Stderr, out)
}
}

// if we recorded any failure output
if defaultTest.FailureOutput != nil {
defaultTest.FailureOutput.Message = "Some packages failed during test execution"
defaultTest.FailureOutput.Output = defaultTest.SystemOut
defaultTest.SystemOut = ""
}

return suites, nil
}
Loading

0 comments on commit 73171de

Please sign in to comment.