diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000000..12066359728 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,113 @@ +version: 2 + +defaults: &defaults + working_directory: ~/ipfs/go-ipfs + shell: /bin/bash --login + environment: + TEST_NO_FUSE: 1 + GOPATH: $HOME/.go_workspace + CIRCLE_TEST_REPORTS: /tmp/circleci-test-results + CIRCLE: 1 + SERVICE: circle-ci + TEST_NO_DOCKER: 1 + CIRCLE_ARTIFACTS: /tmp/circleci-artifacts + TEST_VERBOSE: 1 + TRAVIS: 1 + IMPORT_PATH: github.com/ipfs/go-ipfs + + docker: + - image: circleci/build-image:ubuntu-14.04-XXL-upstart-1189-5614f37 + command: /sbin/init + +jobs: + gotest: + <<: *defaults + steps: + - checkout + - run: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS + - run: 'sudo docker info >/dev/null 2>&1 || sudo service docker start; ' + - run: sudo rm -rf /usr/local/go + - run: if [ ! -e go1.11.linux-amd64.tar.gz ]; then curl -o go1.11.linux-amd64.tar.gz https://storage.googleapis.com/golang/go1.11.linux-amd64.tar.gz; fi + - run: sudo tar -C /usr/local -xzf go1.11.linux-amd64.tar.gz + + - restore_cache: + keys: + - v1-dep-{{ .Branch }}- + - v1-dep-master- + + - run: sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=0 net.ipv6.conf.default.disable_ipv6=0 net.ipv6.conf.all.disable_ipv6=0 + - run: rm -rf "$HOME/.go_workspace/src/$IMPORT_PATH" + - run: mkdir -p "$HOME/.go_workspace/src/$IMPORT_PATH" + - run: cp -aT . "$HOME/.go_workspace/src/$IMPORT_PATH" + - run: cd "$HOME/.go_workspace/src/$IMPORT_PATH" && make deps + + - save_cache: + key: v1-dep-{{ .Branch }}-{{ epoch }} + paths: + - ~/.go_workspace + - ~/go1.11.linux-amd64.tar.gz + - ~/.go_workspace/src/gx/ipfs + - ./node_modules + + + - run: cd "$HOME/.go_workspace/src/$IMPORT_PATH" && curl -s https://codecov.io/bash > codecov + - run: cd "$HOME/.go_workspace/src/$IMPORT_PATH" && make -j 1 test/unit/gotest.junit.xml + - run: cd "$HOME/.go_workspace/src/$IMPORT_PATH" && bash codecov -cF unittests -X search -f coverage/unit_tests.coverprofile + - run: mv "$HOME/.go_workspace/src/${IMPORT_PATH}/test/unit/gotest.junit.xml" /tmp/circleci-test-results + - store_test_results: + path: /tmp/circleci-test-results + # Save artifacts + - store_artifacts: + path: /tmp/circleci-artifacts + - store_artifacts: + path: /tmp/circleci-test-results + sharness: + <<: *defaults + steps: + - checkout + - run: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS + - run: 'sudo docker info >/dev/null 2>&1 || sudo service docker start; ' + - run: sudo rm -rf /usr/local/go + - run: if [ ! -e go1.11.linux-amd64.tar.gz ]; then curl -o go1.11.linux-amd64.tar.gz https://storage.googleapis.com/golang/go1.11.linux-amd64.tar.gz; fi + - run: sudo tar -C /usr/local -xzf go1.11.linux-amd64.tar.gz + + - restore_cache: + keys: + - v1-dep-{{ .Branch }}- + - v1-dep-master- + + - run: sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=0 net.ipv6.conf.default.disable_ipv6=0 net.ipv6.conf.all.disable_ipv6=0 + - run: rm -rf "$HOME/.go_workspace/src/$IMPORT_PATH" + - run: mkdir -p "$HOME/.go_workspace/src/$IMPORT_PATH" + - run: cp -aT . "$HOME/.go_workspace/src/$IMPORT_PATH" + - run: cd "$HOME/.go_workspace/src/$IMPORT_PATH" && make deps + + - save_cache: + key: v1-dep-{{ .Branch }}-{{ epoch }} + paths: + - ~/.go_workspace + - ~/go1.11.linux-amd64.tar.gz + - ~/.go_workspace/src/gx/ipfs + - ./node_modules + + - run: cd "$HOME/.go_workspace/src/$IMPORT_PATH" && curl -s https://codecov.io/bash > codecov + - run: cd "$HOME/.go_workspace/src/$IMPORT_PATH" && make -j 10 coverage/sharness_tests.coverprofile test/sharness/test-results/sharness.xml TEST_GENERATE_JUNIT=1 CONTINUE_ON_S_FAILURE=1 + - run: cd "$HOME/.go_workspace/src/$IMPORT_PATH" && bash codecov -cF sharness -X search -f coverage/sharness_tests.coverprofile + - run: mv "$HOME/.go_workspace/src/${IMPORT_PATH}/test/sharness/test-results/sharness.xml" /tmp/circleci-test-results + + # make sure we fail if there are test failures + - run: cd "$HOME/.go_workspace/src/$IMPORT_PATH" && ls test/sharness/test-results/t*-*.sh.*.counts | test/sharness/lib/sharness/aggregate-results.sh | grep 'failed\s*0' + - store_test_results: + path: /tmp/circleci-test-results + # Save artifacts + - store_artifacts: + path: /tmp/circleci-artifacts + - store_artifacts: + path: /tmp/circleci-test-results + +workflows: + version: 2 + test: + jobs: + - gotest + - sharness diff --git a/Rules.mk b/Rules.mk index 8cb3a623f4d..70ea69e06aa 100644 --- a/Rules.mk +++ b/Rules.mk @@ -41,7 +41,7 @@ include $(dir)/Rules.mk # include this file only if coverage target is executed # it is quite expensive -ifneq ($(filter coverage% clean distclean,$(MAKECMDGOALS)),) +ifneq ($(filter coverage% clean distclean test/unit/gotest.junit.xml,$(MAKECMDGOALS)),) # has to be after cmd/ipfs due to PATH dir := coverage include $(dir)/Rules.mk diff --git a/bin/circle.sh b/bin/circle.sh deleted file mode 100755 index d7f13970031..00000000000 --- a/bin/circle.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -# the CircleCI build line got a bit out of hands -# thus we have sparate file for it - -curl -s https://codecov.io/bash > codecov - -case $CIRCLE_NODE_INDEX in - 0) make -j 1 coverage/unit_tests.coverprofile && - bash codecov -cF unittests -X search -f coverage/unit_tests.coverprofile - ;; - 1) make -j 1 coverage/sharness_tests.coverprofile && - bash codecov -cF sharness -X search -f coverage/sharness_tests.coverprofile - ;; -esac diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 75a31c1d6ff..00000000000 --- a/circle.yml +++ /dev/null @@ -1,40 +0,0 @@ -machine: - environment: - TEST_NO_FUSE: 1 - TEST_VERBOSE: 1 - TEST_NO_DOCKER: 1 - TRAVIS: 1 - CIRCLE: 1 - IMPORT_PATH: "github.com/ipfs/go-ipfs" - GOPATH: "$HOME/.go_workspace" - GOBIN: "$GOPATH/bin" - SERVICE: "circle-ci" - - post: - - sudo rm -rf /usr/local/go - - if [ ! -e go1.11.linux-amd64.tar.gz ]; then curl -o go1.11.linux-amd64.tar.gz https://storage.googleapis.com/golang/go1.11.linux-amd64.tar.gz; fi - - sudo tar -C /usr/local -xzf go1.11.linux-amd64.tar.gz - - services: - - docker - -dependencies: - pre: - # setup ipv6 - - sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=0 net.ipv6.conf.default.disable_ipv6=0 net.ipv6.conf.all.disable_ipv6=0 - - override: - - rm -rf "$HOME/.go_workspace/src/$IMPORT_PATH" - - mkdir -p "$HOME/.go_workspace/src/$IMPORT_PATH" - - cp -aT . "$HOME/.go_workspace/src/$IMPORT_PATH" - - cd "$HOME/.go_workspace/src/$IMPORT_PATH" && make deps - - cache_directories: - - ~/go1.11.linux-amd64.tar.gz - - ~/.go_workspace/src/gx/ipfs - -test: - override: - - bin/circle.sh: - pwd: "../.go_workspace/src/$IMPORT_PATH" - parallel: true diff --git a/coverage/Rules.mk b/coverage/Rules.mk index e9ee9369d68..012af7595c1 100644 --- a/coverage/Rules.mk +++ b/coverage/Rules.mk @@ -11,6 +11,7 @@ endif # unit tests coverage UTESTS_$(d) := $(shell go list -f '{{if (len .TestGoFiles)}}{{.ImportPath}}{{end}}' $(go-flags-with-tags) ./...) +UTESTS_$(d) += $(shell go list -f '{{if (len .XTestGoFiles)}}{{.ImportPath}}{{end}}' $(go-flags-with-tags) ./... | grep -v go-ipfs/vendor | grep -v go-ipfs/Godeps) UCOVER_$(d) := $(addsuffix .coverprofile,$(addprefix $(d)/unitcover/, $(subst /,_,$(UTESTS_$(d))))) @@ -18,7 +19,7 @@ $(UCOVER_$(d)): $(d)/coverage_deps ALWAYS $(eval TMP_PKG := $(subst _,/,$(basename $(@F)))) $(eval TMP_DEPS := $(shell go list -f '{{range .Deps}}{{.}} {{end}}' $(go-flags-with-tags) $(TMP_PKG) | sed 's/ /\n/g' | grep ipfs/go-ipfs) $(TMP_PKG)) $(eval TMP_DEPS_LIST := $(call join-with,$(comma),$(TMP_DEPS))) - go test $(go-flags-with-tags) $(GOTFLAGS) -covermode=atomic -coverpkg=$(TMP_DEPS_LIST) -coverprofile=$@ $(TMP_PKG) + go test $(go-flags-with-tags) $(GOTFLAGS) -v -covermode=atomic -json -coverpkg=$(TMP_DEPS_LIST) -coverprofile=$@ $(TMP_PKG) | tee -a test/unit/gotest.json $(d)/unit_tests.coverprofile: $(UCOVER_$(d)) @@ -26,6 +27,7 @@ $(d)/unit_tests.coverprofile: $(UCOVER_$(d)) TGTS_$(d) := $(d)/unit_tests.coverprofile +.PHONY: $(d)/unit_tests.coverprofile # sharness tests coverage $(d)/ipfs: GOTAGS += testrunmain diff --git a/test/Rules.mk b/test/Rules.mk index e596dfd55a2..264652fe906 100644 --- a/test/Rules.mk +++ b/test/Rules.mk @@ -6,4 +6,7 @@ include $(dir)/Rules.mk dir := $(d)/sharness include $(dir)/Rules.mk +dir := $(d)/unit +include $(dir)/Rules.mk + include mk/footer.mk diff --git a/test/bin/Rules.mk b/test/bin/Rules.mk index 086197b55e2..7d0bc3f8e0a 100644 --- a/test/bin/Rules.mk +++ b/test/bin/Rules.mk @@ -18,6 +18,10 @@ $(d)/ma-pipe-unidir: test/dependencies/ma-pipe-unidir $(go-build) TGTS_$(d) += $(d)/ma-pipe-unidir +$(d)/json-to-junit: test/dependencies/json-to-junit + $(go-build) +TGTS_$(d) += $(d)/json-to-junit + TGTS_GX_$(d) := hang-fds iptb TGTS_GX_$(d) := $(addprefix $(d)/,$(TGTS_GX_$(d))) diff --git a/test/dependencies/json-to-junit/main.go b/test/dependencies/json-to-junit/main.go new file mode 100644 index 00000000000..40f80737398 --- /dev/null +++ b/test/dependencies/json-to-junit/main.go @@ -0,0 +1,135 @@ +package main + +import ( + "bufio" + "encoding/json" + "encoding/xml" + "log" + "os" +) + +type testMsg struct { + Time string + Action string + Package string + Test string + Output string + Elapsed float64 +} + +type testsuites struct { + XMLName xml.Name `xml:"testsuites"` + Name string `xml:"name,attr"` + Testsuites []testsuite +} + +type testsuite struct { + XMLName xml.Name `xml:"testsuite"` + Package string `xml:"package,attr"` + Errors int `xml:"errors,attr"` + Failures int `xml:"failures,attr"` + Tests int `xml:"tests,attr"` + Time float64 `xml:"time,attr"` + Testcases []testcase +} + +type testcase struct { + XMLName xml.Name `xml:"testcase"` + Name string `xml:"name,attr"` + Classname string `xml:"classname,attr"` + Time float64 `xml:"time,attr"` + Sout string `xml:"system-out"` + Serr string `xml:"system-err"` + Skipped string `xml:"skipped,omitempty"` + Failure string `xml:"failure,omitempty"` +} + +func main() { + scanner := bufio.NewScanner(os.Stdin) + tests := make(map[string]map[string]testcase) + var fails int + var packages []testsuite + for scanner.Scan() { + msg := testMsg{} + if err := json.Unmarshal(scanner.Bytes(), &msg); err != nil { + log.Fatal(err) + } + + switch { + case msg.Action == "run": + if tests[msg.Package] == nil { + tests[msg.Package] = make(map[string]testcase) + } + + tests[msg.Package][msg.Test] = testcase{ + Name: msg.Test, + Classname: msg.Package, + } + case msg.Action == "output": + if msg.Test == "" { + continue + } + + test := tests[msg.Package][msg.Test] + test.Sout = test.Sout + msg.Output + "\n" + tests[msg.Package][msg.Test] = test + case msg.Action == "skip": + fallthrough + case msg.Action == "fail": + fallthrough + case msg.Action == "pass": + if msg.Test != "" { + test := tests[msg.Package][msg.Test] + test.Time = msg.Elapsed + + if msg.Action == "skip" { + test.Skipped = "skipped" + } + + if msg.Action == "fail" { + fails++ + test.Failure = "failed" + } + + tests[msg.Package][msg.Test] = test + continue + } + + ts := testsuite{ + Package: msg.Package, + Time: msg.Elapsed, + } + + for _, test := range tests[msg.Package] { + ts.Testcases = append(ts.Testcases, test) + ts.Tests++ + if test.Failure != "" { + ts.Failures++ + } + } + packages = append(packages, ts) + case msg.Action == "cont": + case msg.Action == "pause": + // ?? + default: + log.Fatalf("unknown action %s", msg.Action) + } + } + + if err := scanner.Err(); err != nil { + log.Fatal(err) + } + + out := testsuites{ + Name: "go test", + Testsuites: packages, + } + + output, err := xml.MarshalIndent(&out, " ", " ") + if err != nil { + log.Fatalf("error: %v\n", err) + } + + os.Stdout.Write(output) + os.Exit(fails) +} diff --git a/test/unit/.gitignore b/test/unit/.gitignore new file mode 100644 index 00000000000..fdb9a985e4a --- /dev/null +++ b/test/unit/.gitignore @@ -0,0 +1,2 @@ +gotest.json +gotest.junit.xml diff --git a/test/unit/Rules.mk b/test/unit/Rules.mk new file mode 100644 index 00000000000..7300aabd28c --- /dev/null +++ b/test/unit/Rules.mk @@ -0,0 +1,8 @@ +include mk/header.mk + +CLEAN += $(d)/gotest.json $(d)/gotest.junit.xml + +$(d)/gotest.junit.xml: clean test/bin/json-to-junit coverage/unit_tests.coverprofile + cat $(@D)/gotest.json | json-to-junit > $(@D)/gotest.junit.xml + +include mk/footer.mk