github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/dgraph/cmd/alpha/http_test.go (about)

     1  /*
     2   * Copyright 2017-2018 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package alpha
    18  
    19  import (
    20  	"bytes"
    21  	"compress/gzip"
    22  	"encoding/json"
    23  	"fmt"
    24  	"io/ioutil"
    25  	"net/http"
    26  	"net/http/httptest"
    27  	"sort"
    28  	"strconv"
    29  	"strings"
    30  	"testing"
    31  	"time"
    32  
    33  	"github.com/pkg/errors"
    34  	"github.com/stretchr/testify/require"
    35  
    36  	"github.com/dgraph-io/dgraph/query"
    37  	"github.com/dgraph-io/dgraph/testutil"
    38  	"github.com/dgraph-io/dgraph/x"
    39  )
    40  
    41  type res struct {
    42  	Data       json.RawMessage   `json:"data"`
    43  	Extensions *query.Extensions `json:"extensions,omitempty"`
    44  	Errors     []x.GqlError      `json:"errors,omitempty"`
    45  }
    46  
    47  type params struct {
    48  	Query     string            `json:"query"`
    49  	Variables map[string]string `json:"variables"`
    50  }
    51  
    52  func queryWithGz(queryText, contentType, debug, timeout string, gzReq, gzResp bool) (
    53  	string, *http.Response, error) {
    54  
    55  	params := make([]string, 0, 2)
    56  	if debug != "" {
    57  		params = append(params, "debug="+debug)
    58  	}
    59  	if timeout != "" {
    60  		params = append(params, fmt.Sprintf("timeout=%v", timeout))
    61  	}
    62  	url := addr + "/query?" + strings.Join(params, "&")
    63  
    64  	var buf *bytes.Buffer
    65  	if gzReq {
    66  		var b bytes.Buffer
    67  		gz := gzip.NewWriter(&b)
    68  		gz.Write([]byte(queryText))
    69  		gz.Close()
    70  		buf = &b
    71  	} else {
    72  		buf = bytes.NewBufferString(queryText)
    73  	}
    74  
    75  	req, err := http.NewRequest("POST", url, buf)
    76  	if err != nil {
    77  		return "", nil, err
    78  	}
    79  	req.Header.Add("Content-Type", contentType)
    80  
    81  	if gzReq {
    82  		req.Header.Set("Content-Encoding", "gzip")
    83  	}
    84  
    85  	if gzResp {
    86  		req.Header.Set("Accept-Encoding", "gzip")
    87  	}
    88  
    89  	client := &http.Client{}
    90  	resp, err := client.Do(req)
    91  	if err != nil {
    92  		return "", nil, err
    93  	}
    94  	if status := resp.StatusCode; status != http.StatusOK {
    95  		return "", nil, errors.Errorf("Unexpected status code: %v", status)
    96  	}
    97  
    98  	defer resp.Body.Close()
    99  	rd := resp.Body
   100  	if gzResp {
   101  		if strings.Contains(resp.Header.Get("Content-Encoding"), "gzip") {
   102  			rd, err = gzip.NewReader(rd)
   103  			if err != nil {
   104  				return "", nil, err
   105  			}
   106  			defer rd.Close()
   107  		} else {
   108  			return "", resp, errors.Errorf("Response not compressed")
   109  		}
   110  	}
   111  	body, err := ioutil.ReadAll(rd)
   112  	if err != nil {
   113  		return "", nil, err
   114  	}
   115  
   116  	var r res
   117  	x.Check(json.Unmarshal(body, &r))
   118  
   119  	// Check for errors
   120  	if len(r.Errors) != 0 {
   121  		return "", nil, errors.New(r.Errors[0].Message)
   122  	}
   123  
   124  	// Remove the extensions.
   125  	r2 := res{
   126  		Data: r.Data,
   127  	}
   128  	output, err := json.Marshal(r2)
   129  
   130  	return string(output), resp, err
   131  }
   132  
   133  func queryWithTs(queryText, contentType, debug string, ts uint64) (string, uint64, error) {
   134  	params := make([]string, 0, 2)
   135  	if debug != "" {
   136  		params = append(params, "debug="+debug)
   137  	}
   138  	if ts != 0 {
   139  		params = append(params, fmt.Sprintf("startTs=%v", strconv.FormatUint(ts, 10)))
   140  	}
   141  	url := addr + "/query?" + strings.Join(params, "&")
   142  
   143  	_, body, err := runWithRetries("POST", contentType, url, queryText)
   144  	if err != nil {
   145  		return "", 0, err
   146  	}
   147  
   148  	var r res
   149  	x.Check(json.Unmarshal(body, &r))
   150  	startTs := r.Extensions.Txn.StartTs
   151  
   152  	// Remove the extensions.
   153  	r2 := res{
   154  		Data: r.Data,
   155  	}
   156  	output, err := json.Marshal(r2)
   157  
   158  	return string(output), startTs, err
   159  }
   160  
   161  func mutationWithTs(m, t string, isJson bool, commitNow bool, ts uint64) (
   162  	[]string, []string, uint64, error) {
   163  
   164  	params := make([]string, 2)
   165  	if ts != 0 {
   166  		params = append(params, "startTs="+strconv.FormatUint(ts, 10))
   167  	}
   168  	var keys []string
   169  	var preds []string
   170  	if commitNow {
   171  		params = append(params, "commitNow=true")
   172  	}
   173  
   174  	url := addr + "/mutate?" + strings.Join(params, "&")
   175  	_, body, err := runWithRetries("POST", t, url, m)
   176  	if err != nil {
   177  		return keys, preds, 0, err
   178  	}
   179  
   180  	var r res
   181  	x.Check(json.Unmarshal(body, &r))
   182  	startTs := r.Extensions.Txn.StartTs
   183  
   184  	return r.Extensions.Txn.Keys, r.Extensions.Txn.Preds, startTs, nil
   185  }
   186  
   187  func createRequest(method, contentType, url string, body string) (*http.Request, error) {
   188  	req, err := http.NewRequest(method, url, bytes.NewBufferString(body))
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  
   193  	if contentType != "" {
   194  		req.Header.Set("Content-Type", contentType)
   195  	}
   196  
   197  	return req, nil
   198  }
   199  
   200  func runWithRetries(method, contentType, url string, body string) (
   201  	*x.QueryResWithData, []byte, error) {
   202  
   203  	req, err := createRequest(method, contentType, url, body)
   204  	if err != nil {
   205  		return nil, nil, err
   206  	}
   207  
   208  	qr, respBody, err := runRequest(req)
   209  	if err != nil && strings.Contains(err.Error(), "Token is expired") {
   210  		grootAccessJwt, grootRefreshJwt, err = testutil.HttpLogin(&testutil.LoginParams{
   211  			Endpoint:   addr + "/login",
   212  			RefreshJwt: grootRefreshJwt,
   213  		})
   214  
   215  		// create a new request since the previous request would have been closed upon the err
   216  		retryReq, err := createRequest(method, contentType, url, body)
   217  		if err != nil {
   218  			return nil, nil, err
   219  		}
   220  
   221  		return runRequest(retryReq)
   222  	}
   223  	return qr, respBody, err
   224  }
   225  
   226  // attach the grootAccessJWT to the request and sends the http request
   227  func runRequest(req *http.Request) (*x.QueryResWithData, []byte, error) {
   228  	client := &http.Client{}
   229  	req.Header.Set("X-Dgraph-AccessToken", grootAccessJwt)
   230  	resp, err := client.Do(req)
   231  	if err != nil {
   232  		return nil, nil, err
   233  	}
   234  	if status := resp.StatusCode; status != http.StatusOK {
   235  		return nil, nil, errors.Errorf("Unexpected status code: %v", status)
   236  	}
   237  
   238  	defer resp.Body.Close()
   239  	body, err := ioutil.ReadAll(resp.Body)
   240  	if err != nil {
   241  		return nil, nil, errors.Errorf("unable to read from body: %v", err)
   242  	}
   243  
   244  	qr := new(x.QueryResWithData)
   245  	json.Unmarshal(body, qr) // Don't check error.
   246  	if len(qr.Errors) > 0 {
   247  		return nil, nil, errors.New(qr.Errors[0].Message)
   248  	}
   249  	return qr, body, nil
   250  }
   251  
   252  func commitWithTs(keys, preds []string, ts uint64) error {
   253  	url := addr + "/commit"
   254  	if ts != 0 {
   255  		url += "?startTs=" + strconv.FormatUint(ts, 10)
   256  	}
   257  
   258  	m := make(map[string]interface{})
   259  	m["keys"] = keys
   260  	m["preds"] = preds
   261  	b, err := json.Marshal(m)
   262  	if err != nil {
   263  		return err
   264  	}
   265  	req, err := http.NewRequest("POST", url, bytes.NewReader(b))
   266  	if err != nil {
   267  		return err
   268  	}
   269  	_, _, err = runRequest(req)
   270  	return err
   271  }
   272  
   273  func commitWithTsKeysOnly(keys []string, ts uint64) error {
   274  	url := addr + "/commit"
   275  	if ts != 0 {
   276  		url += "?startTs=" + strconv.FormatUint(ts, 10)
   277  	}
   278  
   279  	b, err := json.Marshal(keys)
   280  	if err != nil {
   281  		return err
   282  	}
   283  	req, err := http.NewRequest("POST", url, bytes.NewReader(b))
   284  	if err != nil {
   285  		return err
   286  	}
   287  	_, _, err = runRequest(req)
   288  	return err
   289  }
   290  
   291  func TestTransactionBasic(t *testing.T) {
   292  	require.NoError(t, dropAll())
   293  	require.NoError(t, alterSchema(`name: string @index(term) .`))
   294  
   295  	q1 := `
   296  	{
   297  	  balances(func: anyofterms(name, "Alice Bob")) {
   298  	    name
   299  	    balance
   300  	  }
   301  	}
   302  	`
   303  	_, ts, err := queryWithTs(q1, "application/graphql+-", "", 0)
   304  	require.NoError(t, err)
   305  
   306  	m1 := `
   307      {
   308  	  set {
   309  		_:alice <name> "Bob" .
   310  		_:alice <balance> "110" .
   311  		_:bob <balance> "60" .
   312  	  }
   313  	}
   314  	`
   315  
   316  	keys, preds, mts, err := mutationWithTs(m1, "application/rdf", false, false, ts)
   317  	require.NoError(t, err)
   318  	require.Equal(t, mts, ts)
   319  	require.Equal(t, 4, len(keys))
   320  	require.Equal(t, 2, len(preds))
   321  	var parsedPreds []string
   322  	for _, pred := range preds {
   323  		parsedPreds = append(parsedPreds, strings.Join(strings.Split(pred, "-")[1:], "-"))
   324  	}
   325  	sort.Strings(parsedPreds)
   326  	require.Equal(t, "balance", parsedPreds[0])
   327  	require.Equal(t, "name", parsedPreds[1])
   328  
   329  	data, _, err := queryWithTs(q1, "application/graphql+-", "", 0)
   330  	require.NoError(t, err)
   331  	require.Equal(t, `{"data":{"balances":[]}}`, data)
   332  
   333  	// Query with same timestamp.
   334  	data, _, err = queryWithTs(q1, "application/graphql+-", "", ts)
   335  	require.NoError(t, err)
   336  	require.Equal(t, `{"data":{"balances":[{"name":"Bob","balance":"110"}]}}`, data)
   337  
   338  	// Commit and query.
   339  	require.NoError(t, commitWithTs(keys, preds, ts))
   340  	data, _, err = queryWithTs(q1, "application/graphql+-", "", 0)
   341  	require.NoError(t, err)
   342  	require.Equal(t, `{"data":{"balances":[{"name":"Bob","balance":"110"}]}}`, data)
   343  }
   344  
   345  func TestTransactionBasicNoPreds(t *testing.T) {
   346  	require.NoError(t, dropAll())
   347  	require.NoError(t, alterSchema(`name: string @index(term) .`))
   348  
   349  	q1 := `
   350  	{
   351  	  balances(func: anyofterms(name, "Alice Bob")) {
   352  	    name
   353  	    balance
   354  	  }
   355  	}
   356  	`
   357  	_, ts, err := queryWithTs(q1, "application/graphql+-", "", 0)
   358  	require.NoError(t, err)
   359  
   360  	m1 := `
   361      {
   362  	  set {
   363  		_:alice <name> "Bob" .
   364  		_:alice <balance> "110" .
   365  		_:bob <balance> "60" .
   366  	  }
   367  	}
   368  	`
   369  
   370  	keys, _, mts, err := mutationWithTs(m1, "application/rdf", false, false, ts)
   371  	require.NoError(t, err)
   372  	require.Equal(t, mts, ts)
   373  	require.Equal(t, 4, len(keys))
   374  
   375  	data, _, err := queryWithTs(q1, "application/graphql+-", "", 0)
   376  	require.NoError(t, err)
   377  	require.Equal(t, `{"data":{"balances":[]}}`, data)
   378  
   379  	// Query with same timestamp.
   380  	data, _, err = queryWithTs(q1, "application/graphql+-", "", ts)
   381  	require.NoError(t, err)
   382  	require.Equal(t, `{"data":{"balances":[{"name":"Bob","balance":"110"}]}}`, data)
   383  
   384  	// Commit and query.
   385  	require.NoError(t, commitWithTs(keys, nil, ts))
   386  	data, _, err = queryWithTs(q1, "application/graphql+-", "", 0)
   387  	require.NoError(t, err)
   388  	require.Equal(t, `{"data":{"balances":[{"name":"Bob","balance":"110"}]}}`, data)
   389  }
   390  
   391  func TestTransactionBasicOldCommitFormat(t *testing.T) {
   392  	require.NoError(t, dropAll())
   393  	require.NoError(t, alterSchema(`name: string @index(term) .`))
   394  
   395  	q1 := `
   396  	{
   397  	  balances(func: anyofterms(name, "Alice Bob")) {
   398  	    name
   399  	    balance
   400  	  }
   401  	}
   402  	`
   403  	_, ts, err := queryWithTs(q1, "application/graphql+-", "", 0)
   404  	require.NoError(t, err)
   405  
   406  	m1 := `
   407      {
   408  	  set {
   409  		_:alice <name> "Bob" .
   410  		_:alice <balance> "110" .
   411  		_:bob <balance> "60" .
   412  	  }
   413  	}
   414  	`
   415  
   416  	keys, _, mts, err := mutationWithTs(m1, "application/rdf", false, false, ts)
   417  	require.NoError(t, err)
   418  	require.Equal(t, mts, ts)
   419  	require.Equal(t, 4, len(keys))
   420  
   421  	data, _, err := queryWithTs(q1, "application/graphql+-", "", 0)
   422  	require.NoError(t, err)
   423  	require.Equal(t, `{"data":{"balances":[]}}`, data)
   424  
   425  	// Query with same timestamp.
   426  	data, _, err = queryWithTs(q1, "application/graphql+-", "", ts)
   427  	require.NoError(t, err)
   428  	require.Equal(t, `{"data":{"balances":[{"name":"Bob","balance":"110"}]}}`, data)
   429  
   430  	// One more time, with json body this time.
   431  	d1, err := json.Marshal(params{Query: q1})
   432  	require.NoError(t, err)
   433  	data, _, err = queryWithTs(string(d1), "application/json", "", ts)
   434  	require.NoError(t, err)
   435  	require.Equal(t, `{"data":{"balances":[{"name":"Bob","balance":"110"}]}}`, data)
   436  
   437  	// Commit (using a list of keys instead of a map) and query.
   438  	require.NoError(t, commitWithTsKeysOnly(keys, ts))
   439  	data, _, err = queryWithTs(q1, "application/graphql+-", "", 0)
   440  	require.NoError(t, err)
   441  	require.Equal(t, `{"data":{"balances":[{"name":"Bob","balance":"110"}]}}`, data)
   442  
   443  	// Aborting a transaction
   444  	url := fmt.Sprintf("%s/commit?startTs=%d&abort=true", addr, ts)
   445  	req, err := http.NewRequest("POST", url, nil)
   446  	require.NoError(t, err)
   447  	_, _, err = runRequest(req)
   448  	require.NoError(t, err)
   449  }
   450  
   451  func TestAlterAllFieldsShouldBeSet(t *testing.T) {
   452  	req, err := http.NewRequest("PUT", "/alter", bytes.NewBufferString(
   453  		`{"dropall":true}`, // "dropall" is spelt incorrect - should be "drop_all"
   454  	))
   455  	require.NoError(t, err)
   456  	rr := httptest.NewRecorder()
   457  	handler := http.HandlerFunc(alterHandler)
   458  	handler.ServeHTTP(rr, req)
   459  
   460  	require.Equal(t, rr.Code, http.StatusOK)
   461  	var qr x.QueryResWithData
   462  	require.NoError(t, json.Unmarshal(rr.Body.Bytes(), &qr))
   463  	require.Len(t, qr.Errors, 1)
   464  	require.Equal(t, qr.Errors[0].Extensions["code"], "Error")
   465  }
   466  
   467  func TestHttpCompressionSupport(t *testing.T) {
   468  	require.NoError(t, dropAll())
   469  	require.NoError(t, alterSchema(`name: string @index(term) .`))
   470  
   471  	q1 := `
   472  	{
   473  	  names(func: has(name), orderasc: name) {
   474  	    name
   475  	  }
   476  	}
   477  	`
   478  
   479  	q2 := `
   480  	query all($name: string) {
   481  	  names(func: eq(name, $name)) {
   482  	    name
   483  	  }
   484  	}
   485  	`
   486  
   487  	m1 := `
   488  	{
   489  	  set {
   490  		_:a <name> "Alice" .
   491  		_:b <name> "Bob" .
   492  		_:c <name> "Charlie" .
   493  		_:d <name> "David" .
   494  		_:e <name> "Emily" .
   495  		_:f <name> "Frank" .
   496  		_:g <name> "Gloria" .
   497  		_:h <name> "Hannah" .
   498  		_:i <name> "Ian" .
   499  		_:j <name> "Judy" .
   500  		_:k <name> "Kevin" .
   501  		_:l <name> "Linda" .
   502  		_:m <name> "Michael" .
   503  	  }
   504  	}
   505  	`
   506  
   507  	r1 := `{"data":{"names":[{"name":"Alice"},{"name":"Bob"},{"name":"Charlie"},{"name":"David"},` +
   508  		`{"name":"Emily"},{"name":"Frank"},{"name":"Gloria"},{"name":"Hannah"},{"name":"Ian"},` +
   509  		`{"name":"Judy"},{"name":"Kevin"},{"name":"Linda"},{"name":"Michael"}]}}`
   510  	err := runMutation(m1)
   511  	require.NoError(t, err)
   512  
   513  	data, resp, err := queryWithGz(q1, "application/graphql+-", "false", "", false, false)
   514  	require.NoError(t, err)
   515  	require.Equal(t, r1, data)
   516  	require.Empty(t, resp.Header.Get("Content-Encoding"))
   517  
   518  	data, resp, err = queryWithGz(q1, "application/graphql+-", "", "", false, true)
   519  	require.NoError(t, err)
   520  	require.Equal(t, r1, data)
   521  	require.Equal(t, "gzip", resp.Header.Get("Content-Encoding"))
   522  
   523  	data, resp, err = queryWithGz(q1, "application/graphql+-", "", "", true, false)
   524  	require.NoError(t, err)
   525  	require.Equal(t, r1, data)
   526  	require.Empty(t, resp.Header.Get("Content-Encoding"))
   527  
   528  	data, resp, err = queryWithGz(q1, "application/graphql+-", "", "", true, true)
   529  	require.NoError(t, err)
   530  	require.Equal(t, r1, data)
   531  	require.Equal(t, "gzip", resp.Header.Get("Content-Encoding"))
   532  
   533  	// query with timeout
   534  	data, resp, err = queryWithGz(q1, "application/graphql+-", "", "1ms", false, false)
   535  	require.EqualError(t, err, ": context deadline exceeded")
   536  	require.Equal(t, "", data)
   537  
   538  	data, resp, err = queryWithGz(q1, "application/graphql+-", "", "1s", false, false)
   539  	require.NoError(t, err)
   540  	require.Equal(t, r1, data)
   541  	require.Empty(t, resp.Header.Get("Content-Encoding"))
   542  
   543  	d1, err := json.Marshal(params{Query: q1})
   544  	require.NoError(t, err)
   545  	data, resp, err = queryWithGz(string(d1), "application/json", "", "1s", false, false)
   546  	require.NoError(t, err)
   547  	require.Equal(t, r1, data)
   548  	require.Empty(t, resp.Header.Get("Content-Encoding"))
   549  
   550  	d2, err := json.Marshal(params{
   551  		Query: q2,
   552  		Variables: map[string]string{
   553  			"$name": "Alice",
   554  		},
   555  	})
   556  	require.NoError(t, err)
   557  	data, resp, err = queryWithGz(string(d2), "application/json", "", "1s", false, false)
   558  	require.NoError(t, err)
   559  	require.Equal(t, `{"data":{"names":[{"name":"Alice"}]}}`, data)
   560  	require.Empty(t, resp.Header.Get("Content-Encoding"))
   561  }
   562  
   563  func TestDebugSupport(t *testing.T) {
   564  	require.NoError(t, dropAll())
   565  	require.NoError(t, alterSchema(`name: string @index(term) .`))
   566  
   567  	m1 := `
   568  	{
   569  	  set {
   570  		_:a <name> "Alice" .
   571  		_:b <name> "Bob" .
   572  		_:c <name> "Charlie" .
   573  		_:d <name> "David" .
   574  		_:e <name> "Emily" .
   575  		_:f <name> "Frank" .
   576  		_:g <name> "Gloria" .
   577  	  }
   578  	}
   579  	`
   580  	err := runMutation(m1)
   581  	require.NoError(t, err)
   582  
   583  	q1 := `
   584  	{
   585  	  users(func: has(name), orderasc: name) {
   586  	    name
   587  	  }
   588  	}
   589  	`
   590  
   591  	requireEqual := func(t *testing.T, data string) {
   592  		var r struct {
   593  			Data struct {
   594  				Users []struct {
   595  					Name string `json:"name"`
   596  					UID  string `json:"uid"`
   597  				} `json:"users"`
   598  			} `json:"data"`
   599  		}
   600  		if err := json.Unmarshal([]byte(data), &r); err != nil {
   601  			require.NoError(t, err)
   602  		}
   603  
   604  		exp := []string{"Alice", "Bob", "Charlie", "David", "Emily", "Frank", "Gloria"}
   605  		actual := make([]string, 0, len(exp))
   606  		for _, u := range r.Data.Users {
   607  			actual = append(actual, u.Name)
   608  			require.NotEmpty(t, u.UID, "uid should be nonempty in debug mode")
   609  		}
   610  		sort.Strings(actual)
   611  		require.Equal(t, exp, actual)
   612  	}
   613  
   614  	data, resp, err := queryWithGz(q1, "application/graphql+-", "true", "", false, false)
   615  	require.NoError(t, err)
   616  	requireEqual(t, data)
   617  	require.Empty(t, resp.Header.Get("Content-Encoding"))
   618  
   619  	data, resp, err = queryWithGz(q1, "application/graphql+-", "true", "", false, true)
   620  	require.NoError(t, err)
   621  	requireEqual(t, data)
   622  	require.Equal(t, "gzip", resp.Header.Get("Content-Encoding"))
   623  
   624  	data, resp, err = queryWithGz(q1, "application/graphql+-", "true", "", true, false)
   625  	require.NoError(t, err)
   626  	requireEqual(t, data)
   627  	require.Empty(t, resp.Header.Get("Content-Encoding"))
   628  
   629  	data, resp, err = queryWithGz(q1, "application/graphql+-", "true", "", true, true)
   630  	require.NoError(t, err)
   631  	requireEqual(t, data)
   632  	require.Equal(t, "gzip", resp.Header.Get("Content-Encoding"))
   633  
   634  	// query with timeout
   635  	data, resp, err = queryWithGz(q1, "application/graphql+-", "true", "1ms", false, false)
   636  	require.EqualError(t, err, ": context deadline exceeded")
   637  	require.Equal(t, "", data)
   638  
   639  	data, resp, err = queryWithGz(q1, "application/graphql+-", "true", "1s", false, false)
   640  	require.NoError(t, err)
   641  	requireEqual(t, data)
   642  	require.Empty(t, resp.Header.Get("Content-Encoding"))
   643  
   644  	d1, err := json.Marshal(params{Query: q1})
   645  	require.NoError(t, err)
   646  	data, resp, err = queryWithGz(string(d1), "application/json", "true", "1s", false, false)
   647  	require.NoError(t, err)
   648  	requireEqual(t, data)
   649  	require.Empty(t, resp.Header.Get("Content-Encoding"))
   650  
   651  	// This test passes access token along with debug flag
   652  	data, _, err = queryWithTs(q1, "application/graphql+-", "true", 0)
   653  	require.NoError(t, err)
   654  	requireEqual(t, data)
   655  	require.Empty(t, resp.Header.Get("Content-Encoding"))
   656  }
   657  
   658  func TestHealth(t *testing.T) {
   659  	url := fmt.Sprintf("%s/health", addr)
   660  	resp, err := http.Get(url)
   661  	require.NoError(t, err)
   662  
   663  	defer resp.Body.Close()
   664  	data, err := ioutil.ReadAll(resp.Body)
   665  	require.NoError(t, err)
   666  
   667  	var info struct {
   668  		Version  string        `json:"version"`
   669  		Instance string        `json:"instance"`
   670  		Uptime   time.Duration `json:"uptime"`
   671  	}
   672  	require.NoError(t, json.Unmarshal(data, &info))
   673  	require.Equal(t, "alpha", info.Instance)
   674  	require.True(t, info.Uptime > time.Duration(1))
   675  }
   676  
   677  func setDrainingMode(t *testing.T, enable bool) {
   678  	url := fmt.Sprintf("%s/admin/draining?enable=%v", addr, enable)
   679  	req, err := http.NewRequest("POST", url, nil)
   680  	require.NoError(t, err, "Error while creating post request for %s", url)
   681  	client := &http.Client{}
   682  	resp, err := client.Do(req)
   683  	require.NoError(t, err, "Error while sending post request to %s", url)
   684  	status := resp.StatusCode
   685  	require.Equal(t, http.StatusOK, status, "Unexpected status code: %v", status)
   686  }
   687  
   688  func TestDrainingMode(t *testing.T) {
   689  	runRequests := func(expectErr bool) {
   690  		q1 := `
   691  	{
   692  	  alice(func: has(name)) {
   693  	    name
   694  	  }
   695  	}
   696  	`
   697  		_, _, err := queryWithTs(q1, "application/graphql+-", "", 0)
   698  		if expectErr {
   699  			require.True(t, err != nil && strings.Contains(err.Error(), "the server is in draining mode"))
   700  		} else {
   701  			require.NoError(t, err, "Got error while running query: %v", err)
   702  		}
   703  
   704  		m1 := `
   705      {
   706  	  set {
   707  		_:alice <name> "Alice" .
   708  	  }
   709  	}
   710  	`
   711  		_, _, _, err = mutationWithTs(m1, "application/rdf", false, true, ts)
   712  		if expectErr {
   713  			require.True(t, err != nil && strings.Contains(err.Error(), "the server is in draining mode"))
   714  		} else {
   715  			require.NoError(t, err, "Got error while running mutation: %v", err)
   716  		}
   717  
   718  		err = alterSchema(`name: string @index(term) .`)
   719  		if expectErr {
   720  			require.True(t, err != nil && strings.Contains(err.Error(), "the server is in draining mode"))
   721  		} else {
   722  			require.NoError(t, err, "Got error while running alter: %v", err)
   723  		}
   724  
   725  	}
   726  
   727  	setDrainingMode(t, true)
   728  	runRequests(true)
   729  
   730  	setDrainingMode(t, false)
   731  	runRequests(false)
   732  }