Skip to content

Commit

Permalink
chore: make testing more resilient and update docs (#9278)
Browse files Browse the repository at this point in the history
**Description**

This PR updates testing code to make testing easier on non-Linux
environments and fix some commonly failing tests. It also more
thoroughly documents the `t` framework as well as offering guidance on
other tests.

**Checklist**

- [x] Code compiles correctly and linting passes locally
  • Loading branch information
matthewmcneely authored Jan 21, 2025
1 parent 053a440 commit df2ccc6
Show file tree
Hide file tree
Showing 15 changed files with 319 additions and 125 deletions.
111 changes: 38 additions & 73 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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/<homedir>/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.
Expand All @@ -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

Expand Down
4 changes: 4 additions & 0 deletions dgraph/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
54 changes: 43 additions & 11 deletions dgraphtest/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
21 changes: 19 additions & 2 deletions dgraphtest/local_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -764,24 +764,41 @@ 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")
}
conns = append(conns, conn)
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 {
Expand Down
1 change: 1 addition & 0 deletions ee/acl/acl_curl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
}
Expand Down
5 changes: 5 additions & 0 deletions protos/protos_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package protos

import (
"path/filepath"
"runtime"
"testing"

"github.com/stretchr/testify/require"
Expand All @@ -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)

Expand Down
16 changes: 8 additions & 8 deletions systest/audit/audit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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")) {
Expand All @@ -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> <balance> "110" .
Expand Down
Loading

0 comments on commit df2ccc6

Please sign in to comment.