diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 31bc239135a..eb4053bc094 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,7 +30,7 @@ available through your OS package manager) - Install [Docker](https://docs.docker.com/install/) and [Docker Compose](https://docs.docker.com/compose/install/). -- [Install Go 1.13 or above](https://golang.org/doc/install). +- [Install Go 1.22.7 or above](https://golang.org/doc/install). ### Setup Dgraph from source repo @@ -94,23 +94,29 @@ You can build Dgraph using `make dgraph` or `make install` which add the version binary. - `make dgraph`: Creates a `dgraph` binary at `./dgraph/dgraph` -- `make install`: Creates a `dgraph` binary at `$GOPATH/bin/dgraph`. You can add `$GOPATH/bin` to - your `$PATH`. +- `make install`: Creates a `dgraph` binary at `$GOPATH/bin/dgraph`. You should add `$GOPATH/bin` to + your `$PATH` if it isn't there already. -```text +```sh $ make install -$ dgraph version -[Decoder]: Using assembly version of decoder - -Dgraph version : v1.1.1 -Dgraph SHA-256 : 97326c9328aff93851290b12d846da81a7da5b843e97d7c63f5d79091b9063c1 -Commit SHA-1 : 8994a57 -Commit timestamp : 2019-12-16 18:24:50 -0800 -Branch : HEAD -Go version : go1.13.5 +Installing Dgraph... +Commit SHA256: 15839b156e9920ca2c4ab718e1e73b6637b8ecec +Old SHA256: 596e362ede7466a2569d19ded91241e457e665ada785d05a902af2c6f2cea508 +Installed dgraph to /Users//go/bin/dgraph -For Dgraph official documentation, visit https://dgraph.io/docs/. +$ dgraph version +Dgraph version : v24.0.2-103-g15839b156 +Dgraph codename : dgraph +Dgraph SHA-256 : 9ce738cd055dfebdef5d68b2a49ea4e062e597799498607dbd1bb618d48861a6 +Commit SHA-1 : 15839b156 +Commit timestamp : 2025-01-10 17:56:49 -0500 +Branch : username/some-branch-that-im-on +Go version : go1.22.7 +jemalloc enabled : true + +For Dgraph official documentation, visit https://dgraph.io/docs. For discussions about Dgraph , visit https://discuss.dgraph.io. +For fully-managed Dgraph Cloud , visit https://dgraph.io/cloud. Licensed variously under the Apache Public License 2.0 and Dgraph Community License. Copyright 2015-2025 Hypermode Inc. @@ -119,73 +125,32 @@ Copyright 2015-2025 Hypermode Inc. ### Build Docker Image ```sh -make image +make image-local ``` -To build a test Docker image from source, use `make image`. This builds a Dgraph binary using -`make dgraph` and creates a Docker image named `dgraph/dgraph` tagged as the current branch name. -The image only contains the `dgraph` binary. - -Example: - -```bash -$ git rev-parse --abbrev-ref HEAD # current branch -main -$ make image -Successfully built c74d564d911f -Successfully tagged dgraph/dgraph:main -$ $ docker run --rm -it dgraph/dgraph:main dgraph version -[Decoder]: Using assembly version of decoder - -Dgraph version : v1.1.1-1-g5fa139a0e -Dgraph SHA-256 : 31f8c9324eb90a6f4659066937fcebc67bbca251c20b9da0461c2fd148187689 -Commit SHA-1 : 5fa139a0e -Commit timestamp : 2019-12-16 20:52:06 -0800 -Branch : main -Go version : go1.13.5 - -For Dgraph official documentation, visit https://dgraph.io/docs/. -For discussions about Dgraph , visit https://discuss.dgraph.io. - -Licensed variously under the Apache Public License 2.0 and Dgraph Community License. -Copyright 2015-2025 Hypermode Inc. -``` +To build a test Docker image from source, use `make image-local`. This builds a linux-compatible +Dgraph binary using `make dgraph` and creates a Docker image tagged `dgraph/dgraph:local`. You can +then use this local image to test Dgraph in your local Docker setup. ### Testing -#### Dgraph - -1. Change directory to t directory. -2. If all packages need to be tested, run make test If only a specific package needs to be tested, - run make test args="--pkg=desired_package_name" - - example 1: make test args="--pkg=tok" example 2: make test args="--pkg=tlstest/acl" - - The first example will run all the tests in the 'tok' directory (if there are any) The second one - will run all the test in the acl subfolder of the tlstest directory. Note: running make test - args="--pkg=tlstest" will return an error saying no packages found because all the tests in the - tlstest package are in subdirectories of the package. So the subdirectories must be specified as - shown in example 2. +Dgraph employs a ~~complex~~ sophisticated testing framework that includes extensive test coverage. +Due to the comprehensive nature of these tests, a complete test run can take several hours, +depending on your hardware. To manage this complex testing process efficiently, we've developed a +custom test framework implemented in Go, which resides in the [./t](/t) directory. This specialized +framework provides enhanced control and flexibility beyond what's available through standard Go +testing framework. -Tests should be written in Go and use the Dgraph cluster set up in `dgraph/docker-compose.yml` -whenever possible. If the functionality being tested requires a different cluster setup (e.g. -different commandline options), the `*_test.go` files should be put in a separate directory that -also contains a `docker-compose.yml` to set up the cluster as needed. +For dependencies, runner flags and instructions for running tests on non-Linux machines, see the +[README](t/README.md) in the [_t_](t) folder. -**IMPORTANT:** All containers should be labeled with `cluster: test` so they may be correctly -restarted and cleaned up by the test script. +Other integration tests do not use the testing framework located in the `t` folder. Consult the +[github actions definitions](.github) folder to discover the tests we run as part of our continuous +delivery process. -#### Badger - -Run `go test` in the root folder. - -```bash -$ go test ./... -ok github.com/dgraph-io/badger 24.853s -ok github.com/dgraph-io/badger/skl 0.027s -ok github.com/dgraph-io/badger/table 0.478s -ok github.com/dgraph-io/badger/y 0.004s -``` +Non-integration unit tests exist for many core packages that can be exercised without invoking the +testing framework. For instance, to unit test the core DQL parsing package: +`go test github.com/hypermodeinc/dgraph/v24/dql`. ## Contributing diff --git a/dgraph/Makefile b/dgraph/Makefile index ad535691d58..9e486d96a49 100644 --- a/dgraph/Makefile +++ b/dgraph/Makefile @@ -29,6 +29,7 @@ BUILD_VERSION := $(shell echo ${DGRAPH_VERSION} | sed -e 's/-amd64//' -e 's/-arm endif GOOS ?= $(shell go env GOOS) +GOARCH ?= $(shell go env GOARCH) # Only build with jemalloc on Linux, mac ifeq ($(GOOS),$(filter $(GOOS),linux darwin)) BUILD_TAGS ?= jemalloc @@ -72,6 +73,9 @@ INSTALL_TARGET = $(GOPATH)/bin/$(BIN) ifneq ($(strip $(shell go env GOBIN)),) INSTALL_TARGET = $(shell go env GOBIN)/$(BIN) endif +ifneq ($(GOOS)_$(GOARCH),$(shell go env GOHOSTOS)_$(shell go env GOHOSTARCH)) + INSTALL_TARGET = $(GOPATH)/bin/$(GOOS)_$(GOARCH)/$(BIN) +endif .PHONY: all $(BIN) all: $(BIN) diff --git a/dgraphtest/image.go b/dgraphtest/image.go index a7c0cf8c20c..1b680dd691d 100644 --- a/dgraphtest/image.go +++ b/dgraphtest/image.go @@ -182,32 +182,64 @@ func copyBinary(fromDir, toDir, version string) error { } func copy(src, dst string) error { + // Validate inputs + if src == "" || dst == "" { + return errors.New("source or destination paths cannot be empty") + } + + // Check source file sourceFileStat, err := os.Stat(src) if err != nil { - return err + return errors.Wrapf(err, "failed to stat source file: %s", src) } if !sourceFileStat.Mode().IsRegular() { - return errors.Wrap(err, fmt.Sprintf("%s is not a regular file", src)) + return errors.Errorf("%s is not a regular file", src) } + // Open source file source, err := os.Open(src) - srcStat, _ := source.Stat() if err != nil { - return errors.Wrap(err, fmt.Sprintf("error while opening file [%s]", src)) + return errors.Wrapf(err, "failed to open source file: %s", src) } defer source.Close() - destination, err := os.Create(dst) + // Create destination directory if it doesn't exist + if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { + return errors.Wrapf(err, "failed to create destination directory: %s", filepath.Dir(dst)) + } + + // Create destination file + destination, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, sourceFileStat.Mode()) if err != nil { - return err + return errors.Wrapf(err, "failed to create destination file: %s", dst) } - defer destination.Close() - if err := os.Chmod(dst, srcStat.Mode()); err != nil { - return err + // Copy the file + if _, err := io.Copy(destination, source); err != nil { + return errors.Wrap(err, "failed to copy file contents") + } + + // Ensure data is flushed to disk + if err := destination.Sync(); err != nil { + return errors.Wrap(err, "failed to sync destination file") } - _, err = io.Copy(destination, source) - return err + + // Close the destination file + if err := destination.Close(); err != nil { + return errors.Wrap(err, "failed to close destination file") + } + + // Stat the new file to check file size match + destStat, err := os.Stat(dst) + if err != nil { + return errors.Wrapf(err, "failed to stat destination file: %s", dst) + } + if destStat.Size() != sourceFileStat.Size() { + log.Printf("[WARNING] size mismatch after copy of %s to %s: source=%d bytes, destination=%d bytes", + src, dst, sourceFileStat.Size(), destStat.Size()) + } + + return nil } // IsHigherVersion checks whether "higher" is the higher version compared to "lower" diff --git a/dgraphtest/local_cluster.go b/dgraphtest/local_cluster.go index 7e463d74279..133a0de010f 100644 --- a/dgraphtest/local_cluster.go +++ b/dgraphtest/local_cluster.go @@ -550,7 +550,7 @@ func (c *LocalCluster) HealthCheck(zeroOnly bool) error { func (c *LocalCluster) containerHealthCheck(url func(c *LocalCluster) (string, error)) error { endpoint, err := url(c) if err != nil { - return errors.Wrap(err, "error getting health URL") + return errors.Wrapf(err, "error getting health URL %v", endpoint) } for range 60 { @@ -764,17 +764,31 @@ func (c *LocalCluster) recreateContainers() error { // Client returns a grpc client that can talk to any Alpha in the cluster func (c *LocalCluster) Client() (*dgraphapi.GrpcClient, func(), error) { // TODO(aman): can we cache the connections? + retryPolicy := `{ + "methodConfig": [{ + "retryPolicy": { + "MaxAttempts": 4, + "InitialBackoff": ".01s", + "MaxBackoff": ".01s", + "BackoffMultiplier": 1.0, + "RetryableStatusCodes": [ "UNAVAILABLE" ] + } + }] + }` var apiClients []api.DgraphClient var conns []*grpc.ClientConn for _, aa := range c.alphas { if !aa.isRunning { + // QUESTIONS(shivaji): Should this be 'continue' instead of a break from the loop break } url, err := aa.alphaURL(c) if err != nil { return nil, nil, errors.Wrap(err, "error getting health URL") } - conn, err := grpc.Dial(url, grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err := grpc.Dial(url, + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithDefaultServiceConfig(retryPolicy)) if err != nil { return nil, nil, errors.Wrap(err, "error connecting to alpha") } @@ -782,6 +796,9 @@ func (c *LocalCluster) Client() (*dgraphapi.GrpcClient, func(), error) { apiClients = append(apiClients, api.NewDgraphClient(conn)) } + if len(apiClients) == 0 { + return nil, nil, errors.New("no alphas running") + } client := dgo.NewDgraphClient(apiClients...) cleanup := func() { for _, conn := range conns { diff --git a/ee/acl/acl_curl_test.go b/ee/acl/acl_curl_test.go index ecadfe9643b..8e3452cba80 100644 --- a/ee/acl/acl_curl_test.go +++ b/ee/acl/acl_curl_test.go @@ -52,6 +52,7 @@ func (asuite *AclTestSuite) TestCurlAuthorization() { // alter and mutate should fail. queryArgs := func(jwt string) []string { return []string{"-H", fmt.Sprintf("X-Dgraph-AccessToken:%s", jwt), + "--ipv4", "-H", "Content-Type: application/dql", "-d", query, testutil.SockAddrHttp + "/query"} } diff --git a/protos/protos_test.go b/protos/protos_test.go index 41023055228..a03b53e992b 100644 --- a/protos/protos_test.go +++ b/protos/protos_test.go @@ -19,6 +19,7 @@ package protos import ( "path/filepath" + "runtime" "testing" "github.com/stretchr/testify/require" @@ -27,6 +28,10 @@ import ( ) func TestProtosRegenerate(t *testing.T) { + if runtime.GOOS != "linux" { + t.Skip("Skipping test on non-Linux platform") + } + err := testutil.Exec("make", "regenerate") require.NoError(t, err, "Got error while regenerating protos: %v\n", err) diff --git a/systest/audit/audit_test.go b/systest/audit/audit_test.go index b8e664217fa..882a5948582 100644 --- a/systest/audit/audit_test.go +++ b/systest/audit/audit_test.go @@ -36,11 +36,11 @@ func TestZeroAudit(t *testing.T) { nId := state.Zeros["1"].Id defer os.RemoveAll(fmt.Sprintf("audit_dir/za/zero_audit_0_%s.log", nId)) zeroCmd := map[string][]string{ - "/removeNode": {`--location`, "--request", "GET", + "/removeNode": {`--location`, "--request", "GET", "--ipv4", fmt.Sprintf("%s/removeNode?id=3&group=1", testutil.SockAddrZeroHttp)}, - "/assign": {"--location", "--request", "GET", + "/assign": {"--location", "--request", "GET", "--ipv4", fmt.Sprintf("%s/assign?what=uids&num=100", testutil.SockAddrZeroHttp)}, - "/moveTablet": {"--location", "--request", "GET", + "/moveTablet": {"--location", "--request", "GET", "--ipv4", fmt.Sprintf("%s/moveTablet?tablet=name&group=2", testutil.SockAddrZeroHttp)}} msgs := make([]string, 0) @@ -67,22 +67,22 @@ func TestAlphaAudit(t *testing.T) { } defer os.Remove(fmt.Sprintf("audit_dir/aa/alpha_audit_1_%s.log", nId)) testCommand := map[string][]string{ - "/admin": {"--location", "--request", "POST", + "/admin": {"--location", "--request", "POST", "--ipv4", fmt.Sprintf("%s/admin", testutil.SockAddrHttp), "--header", "Content-Type: application/json", "--data-raw", `'{"query":"mutation {\n backup( input: {destination: \"/Users/sankalanparajuli/work/backup\"}) {\n response {\n message\n code\n }\n }\n}\n","variables":{}}'`}, //nolint:lll - "/graphql": {"--location", "--request", "POST", fmt.Sprintf("%s/graphql", testutil.SockAddrHttp), + "/graphql": {"--location", "--request", "POST", "--ipv4", fmt.Sprintf("%s/graphql", testutil.SockAddrHttp), "--header", "Content-Type: application/json", "--data-raw", `'{"query":"query {\n __schema {\n __typename\n }\n}","variables":{}}'`}, - "/alter": {"-X", "POST", fmt.Sprintf("%s/alter", testutil.SockAddrHttp), "-d", + "/alter": {"-X", "POST", "--ipv4", fmt.Sprintf("%s/alter", testutil.SockAddrHttp), "-d", `name: string @index(term) . type Person { name }`}, - "/query": {"-H", "'Content-Type: application/dql'", "-X", "POST", fmt.Sprintf("%s/query", testutil.SockAddrHttp), + "/query": {"-H", "'Content-Type: application/dql'", "-X", "POST", "--ipv4", fmt.Sprintf("%s/query", testutil.SockAddrHttp), "-d", `$' { balances(func: anyofterms(name, "Alice Bob")) { @@ -92,7 +92,7 @@ input: {destination: \"/Users/sankalanparajuli/work/backup\"}) {\n response { } }'`}, "/mutate": {"-H", "'Content-Type: application/rdf'", "-X", - "POST", fmt.Sprintf("%s/mutate?startTs=4", testutil.SockAddrHttp), "-d", `$' + "POST", "--ipv4", fmt.Sprintf("%s/mutate?startTs=4", testutil.SockAddrHttp), "-d", `$' { set { <0x1> "110" . diff --git a/systest/audit_encrypted/audit_test.go b/systest/audit_encrypted/audit_test.go index 9911022726c..55e2977f4fd 100644 --- a/systest/audit_encrypted/audit_test.go +++ b/systest/audit_encrypted/audit_test.go @@ -37,11 +37,11 @@ func TestZeroAuditEncrypted(t *testing.T) { defer os.RemoveAll(fmt.Sprintf("audit_dir/za/zero_audit_0_%s.log", nId)) defer os.RemoveAll(fmt.Sprintf("audit_dir/za/zero_audit_0_%s.log.enc", nId)) zeroCmd := map[string][]string{ - "/removeNode": {`--location`, "--request", "GET", + "/removeNode": {`--location`, "--request", "GET", "--ipv4", fmt.Sprintf("%s/removeNode?id=3&group=1", testutil.SockAddrZeroHttp)}, - "/assign": {"--location", "--request", "GET", + "/assign": {"--location", "--request", "GET", "--ipv4", fmt.Sprintf("%s/assign?what=uids&num=100", testutil.SockAddrZeroHttp)}, - "/moveTablet": {"--location", "--request", "GET", + "/moveTablet": {"--location", "--request", "GET", "--ipv4", fmt.Sprintf("%s/moveTablet?tablet=name&group=2", testutil.SockAddrZeroHttp)}} msgs := make([]string, 0) @@ -87,22 +87,22 @@ func TestAlphaAuditEncrypted(t *testing.T) { defer os.Remove(fmt.Sprintf("audit_dir/aa/alpha_audit_1_%s.log", nId)) defer os.Remove(fmt.Sprintf("audit_dir/aa/alpha_audit_1_%s.log.enc", nId)) testCommand := map[string][]string{ - "/admin": {"--location", "--request", "POST", + "/admin": {"--location", "--request", "POST", "--ipv4", fmt.Sprintf("%s/admin", testutil.SockAddrHttp), "--header", "Content-Type: application/json", "--data-raw", `'{"query":"mutation {\n backup( input: {destination: \"/Users/sankalanparajuli/work/backup\"}) {\n response {\n message\n code\n }\n }\n}\n","variables":{}}'`}, //nolint:lll - "/graphql": {"--location", "--request", "POST", fmt.Sprintf("%s/graphql", testutil.SockAddrHttp), + "/graphql": {"--location", "--request", "POST", "--ipv4", fmt.Sprintf("%s/graphql", testutil.SockAddrHttp), "--header", "Content-Type: application/json", "--data-raw", `'{"query":"query {\n __schema {\n __typename\n }\n}","variables":{}}'`}, - "/alter": {"-X", "POST", fmt.Sprintf("%s/alter", testutil.SockAddrHttp), "-d", + "/alter": {"-X", "POST", "--ipv4", fmt.Sprintf("%s/alter", testutil.SockAddrHttp), "-d", `name: string @index(term) . type Person { name }`}, - "/query": {"-H", "'Content-Type: application/dql'", "-X", "POST", fmt.Sprintf("%s/query", testutil.SockAddrHttp), + "/query": {"-H", "'Content-Type: application/dql'", "--ipv4", "-X", "POST", fmt.Sprintf("%s/query", testutil.SockAddrHttp), "-d", `$' { balances(func: anyofterms(name, "Alice Bob")) { @@ -111,7 +111,7 @@ input: {destination: \"/Users/sankalanparajuli/work/backup\"}) {\n response { balance } }'`}, - "/mutate": {"-H", "'Content-Type: application/rdf'", "-X", + "/mutate": {"-H", "'Content-Type: application/rdf'", "--ipv4", "-X", "POST", fmt.Sprintf("%s/mutate?startTs=4", testutil.SockAddrHttp), "-d", `$' { set { diff --git a/systest/loader/loader_test.go b/systest/loader/loader_test.go index 7aa21fcd866..f3b675fb328 100644 --- a/systest/loader/loader_test.go +++ b/systest/loader/loader_test.go @@ -21,6 +21,7 @@ package main import ( "context" "fmt" + "os" "path/filepath" "testing" @@ -34,6 +35,12 @@ import ( // TestLoaderXidmap checks that live loader re-uses xidmap on loading data from two different files func TestLoaderXidmap(t *testing.T) { + + // test that the cert exists and is valid + certPath := "../../tlstest/mtls_internal/tls/live/ca.crt" + _, err := os.Stat(certPath) + require.NoError(t, err, "CA certificate file not found") + conf := viper.GetViper() conf.Set("tls", fmt.Sprintf("ca-cert=%s; server-name=%s; internal-port=%v;", // ca-cert diff --git a/t/Makefile b/t/Makefile index ccc27a87ade..925731f505e 100644 --- a/t/Makefile +++ b/t/Makefile @@ -17,12 +17,30 @@ # linux || darwin GOOS ?= $(shell go env GOOS) GOPATH ?= $(shell go env GOPATH) - -.PHONY: test +MIN_GO_VERSION = "1.22.7" all: test -test: +.PHONY: check +check: + @which go > /dev/null 2>&1 || (echo "Error: Go is not installed or not in PATH" && exit 1) + @go version | awk '{split($$3,v,"go"); if(v[2] < $(MIN_GO_VERSION)) {print "Error: Go version must be $(MIN_GO_VERSION) or higher"; exit 1}}' + @which docker > /dev/null 2>&1 || (echo "Error: Docker is not installed or not in PATH" && exit 1) + @which gotestsum > /dev/null 2>&1 || (echo "Error: gotestsum is not installed or not in PATH" && exit 1) + @if [ "$(GOOS)" = "linux" ]; then \ + which protoc > /dev/null 2>&1 || (echo "Error: protoc is not installed or not in PATH" && exit 1); \ + fi + @echo "All dependencies are installed" + @if [ -f "$(GOPATH)/bin/dgraph" ]; then \ + file $(GOPATH)/bin/dgraph | grep -q "ELF.*executable" || (echo "Error: dgraph binary is not a Linux executable" && exit 1); \ + else \ + echo "Error: dgraph binary not found in $(GOPATH)/bin" && exit 1; \ + fi + @echo "The dgraph binary is a Linux executable (as required)" + + +.PHONY: test +test: check # build the t.go binary @go build . # clean go testcache diff --git a/t/README.md b/t/README.md index 8d13537d398..ce151c5d4d6 100644 --- a/t/README.md +++ b/t/README.md @@ -1,20 +1,163 @@ -This is a Go script to run Dgraph tests. It works by creating N clusters of Dgraph, where N is -defined by the concurrency flag. It picks up packages and runs each package against one of these N -clusters. It passes the information about the endpoints via environment variables. +# Dgraph Testing Framework -The script can be run like this: +Dgraph employs a ~~complex~~ sophisticated testing framework that includes extensive test coverage. +Due to the comprehensive nature of these tests, a complete test run can take several hours, +depending on your hardware. To manage this complex testing process efficiently, we've developed a +custom test framework implemented in Go: [t.go](t.go). This specialized runner provides enhanced +control and flexibility beyond what's available through the standard Go testing framework. -```bash -$ go build . && ./t -# ./t --help to see the flags. -``` +**Note:** This testing framework was built with Linux in mind. Non-Linux testing _can_ be +achieved—see [Running tests on OSX](#running-tests-on-osx) below. + +## Requirements + +The framework requires several external dependencies. You can check your system for the required +dependencies by running `make check`. + +### Go + +Version 1.22.7 or higher. + +### Docker + +The framework uses Docker extensively for integration testing. Tests will often "fail" if Docker is +not given enough resources, specifically memory. If you experience testing that seems to hang +waiting for connections to other cluster members, it's probably a memory issue. + +The test runner takes a concurrency flag (./t -j=N) which will attempt to create _N_ number of +Dgraph clusters and run tests concurrently in those clusters. If you are testing on a machine with +limited resources, we advise you to not set this above _1_ (which is the default). + +You can preserve the test Docker containers for failure analysis with the `--keep` flag. + +### gotestsum + +The framework uses [gotestsum](https://github.com/gotestyourself/gotestsum#install) for collating +test output and other advanced functions. + +### protoc + +On non-Linux systems, protocol buffer tests are skipped. On Linux systems, instructions for +installing and configuring protoc can be found [here](https://github.com/protocolbuffers/protobuf). +Or, `sudo apt update && sudo apt install -y protobuf-compiler`. + +## Running Tests -You can run a specific package or a specific test via this script. You can use the concurrency flag -to specify how many clusters to run. +The tests use the Dgraph binary found at $(GOPATH)/bin/dgraph. To check your current $GOPATH: +`go env GOPATH`. --- -This script runs many clusters of Dgraph. To make your tests work with this script, they can get the -address for any instance by passing in the name of the instance and the port: +Use the `make install` target in the top-level Makefile to build a binary with your changes that +need testing. Note for non-Linux users: because the binary is run in the Docker environment, it +needs to be a valid Linux executable. See the section below on +[Running tests on OSX](#running-tests-on-osx). + +First, build the `t` program if you haven't already: + +```sh +make check && go build . +``` + +This will produce a `t` executable, which is the testing framework _cli_. + +To see a list of available flags: + +```sh +./t --help +``` + +### Testing packages + +One popular use of the framework is to target a specific package for integration testing. For +instance, to test the GraphQL system: + +```sh +./t --pkg=graphql/e2e/normal +``` + +Multiple packages can be specified by separated them with a comma. + +### Testing suites + +You can test one or more "suites" of functionality using the `--suite` flag. For instance: + +```sh +./t --suite=core,vector +``` + +The `--help` flag lists the available suites. + +### Testing single test functions + +```sh +./t --test=TestParseCountValError +``` + +This flag uses `ack` to find all tests matching the specified name(s). + +### Other useful flags + +The `--dry` (dry-run) flag can be used to list the packages that will be included for testing +without actually invoking the tests. + +The `--skip-slow` flag will skip tests known to be slow to complete. + +## Docker Compose Conventions + +The Docker-based integration tests follow a hierarchical file discovery system. When executing a +test, the framework first searches for a docker-compose.yml file in the test's immediate package +directory. If no file is found, it progressively checks parent directories until it locates one. The +root-level test configuration file is stored at +[../dgraph/docker-compose.yml](../dgraph/docker-compose.yml). When implementing tests that require +unique Docker configurations not covered by existing compose files, you should create a new +directory with your tests also containing a custom docker-compose.yml file tailored to your specific +testing requirements. + +## Running tests on OSX + +The testing framework works well on Linux systems. Some additional steps need to be taken for the +tests to run on OSX. + +### Install location + +The Docker environment used to perform integration testing uses the dgraph binary found in +$GOPATH/bin. This binary is required to be a GOOS=linux image. The following commands need to be run +prior to starting tests to ensure the appropriate images are in place. Note, if your GOPATH variable +is not set, run ``export GOPATH=`go env GOPATH` `` + +```sh +cd .. +# builds the OSX version +make install +mv $GOPATH/bin/dgraph $GOPATH/bin/dgraph_osx +# builds the linux version, take note of where the target reports it has written the dgraph executable +GOOS=linux make install +mv $GOPATH/bin/linux_arm64/dgraph $GOPATH/bin/dgraph +cd t +make check +``` + +The following environment variables are needed when tests are executed: + +- GOPATH - needed to map the Dgraph image in Docker environments +- DGRAPH_BINARY - the system-native (OSX) dgraph image, used by some tests not in the Docker + environment +- DOCKER_HOST - on newer Docker Desktop versions, the Docker communications socket was moved to your + home folder + +Example: + +```sh +export GOPATH=`go env GOPATH` +export DGRAPH_BINARY=$GOPATH/bin/dgraph_osx +export DOCKER_HOST=unix://${HOME}/.docker/run/docker.sock +``` + +At this point, the `t` executable can be run as described above. + +### Common Pitfalls -`testutil.ContainerAddr("alpha2", 9080)` +If you see `exec format error` output from test runs, it is most likely because some tests attempt +to run the Dgraph image copied from the filesystem in the Docker environment. This is a known issue +with some integration tests. diff --git a/t/t.go b/t/t.go index e3174728cdf..f4ee2700869 100644 --- a/t/t.go +++ b/t/t.go @@ -91,7 +91,7 @@ var ( skipSlow = pflag.BoolP("skip-slow", "s", false, "If true, don't run tests on slow packages.") suite = pflag.String("suite", "unit", "This flag is used to specify which "+ - "test suites to run. Possible values are all, ldbc, load, unit. Multiple suites can be "+ + "test suites to run. Possible values are all, ldbc, load, unit, systest, vector, core. Multiple suites can be "+ "selected like --suite=ldbc,load") tmp = pflag.String("tmp", "", "Temporary directory used to download data.") downloadResources = pflag.BoolP("download", "d", true, diff --git a/testutil/client.go b/testutil/client.go index 92d7a56e259..3a59963a033 100644 --- a/testutil/client.go +++ b/testutil/client.go @@ -483,7 +483,7 @@ top: // the curl command should have returned an non-zero code require.Error(t, err, "the curl command should have failed") if ee, ok := err.(*exec.ExitError); ok { - require.True(t, strings.Contains(string(ee.Stderr), failureConfig.CurlErrMsg), + require.Contains(t, string(ee.Stderr), failureConfig.CurlErrMsg, "the curl output does not contain the expected output") } } else { diff --git a/testutil/testaudit/audit.go b/testutil/testaudit/audit.go index 558e4ab3e42..823246af5e1 100644 --- a/testutil/testaudit/audit.go +++ b/testutil/testaudit/audit.go @@ -43,11 +43,11 @@ func TestGenerateAuditForTestDecrypt(t *testing.T) { // to generate audit logs, uncomment and run ./t --test=TestGenerateAuditForTestDecrypt t.Skip() zeroCmd := map[string][]string{ - "/removeNode": {`--location`, "--request", "GET", + "/removeNode": {`--location`, "--request", "GET", "--ipv4", fmt.Sprintf("%s/removeNode?id=3&group=1", testutil.SockAddrZeroHttp)}, - "/assign": {"--location", "--request", "GET", + "/assign": {"--location", "--request", "GET", "--ipv4", fmt.Sprintf("%s/assign?what=uids&num=100", testutil.SockAddrZeroHttp)}, - "/moveTablet": {"--location", "--request", "GET", + "/moveTablet": {"--location", "--request", "GET", "--ipv4", fmt.Sprintf("%s/moveTablet?tablet=name&group=2", testutil.SockAddrZeroHttp)}} for _, c := range zeroCmd { diff --git a/tlstest/certrequest/certrequest_test.go b/tlstest/certrequest/certrequest_test.go index a612fda8466..a4cce78f412 100644 --- a/tlstest/certrequest/certrequest_test.go +++ b/tlstest/certrequest/certrequest_test.go @@ -50,16 +50,18 @@ func TestAccessWithCaCert(t *testing.T) { func TestCurlAccessWithCaCert(t *testing.T) { // curl over plaintext should fail curlPlainTextArgs := []string{ + "--ipv4", "https://" + testutil.SockAddrHttpLocalhost + "/alter", "-d", "name: string @index(exact) .", } testutil.VerifyCurlCmd(t, curlPlainTextArgs, &testutil.CurlFailureConfig{ ShouldFail: true, - CurlErrMsg: "SSL certificate problem", + CurlErrMsg: "SSL", }) curlArgs := []string{ - "--cacert", "../tls/ca.crt", "https://" + testutil.SockAddrHttpLocalhost + "/alter", + "--cacert", "../tls/ca.crt", "--ipv4", + "https://" + testutil.SockAddrHttpLocalhost + "/alter", "-d", "name: string @index(exact) .", } testutil.VerifyCurlCmd(t, curlArgs, &testutil.CurlFailureConfig{