github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/contrib/integration/testtxn/main_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 main_test
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"fmt"
    23  	"log"
    24  	"os"
    25  	"sort"
    26  	"strconv"
    27  	"strings"
    28  	"sync"
    29  	"testing"
    30  	"time"
    31  
    32  	"github.com/dgraph-io/dgo"
    33  	"github.com/dgraph-io/dgo/protos/api"
    34  	"github.com/dgraph-io/dgraph/testutil"
    35  	"github.com/dgraph-io/dgraph/x"
    36  	"github.com/stretchr/testify/assert"
    37  	"github.com/stretchr/testify/require"
    38  	"google.golang.org/grpc"
    39  )
    40  
    41  type state struct {
    42  	dg *dgo.Dgraph
    43  }
    44  
    45  var s state
    46  var addr string = testutil.SockAddr
    47  
    48  func TestMain(m *testing.M) {
    49  	log.SetFlags(log.LstdFlags | log.Lshortfile)
    50  	testutil.AssignUids(200)
    51  	dg := testutil.DgraphClientWithGroot(testutil.SockAddr)
    52  	s.dg = dg
    53  
    54  	r := m.Run()
    55  	os.Exit(r)
    56  }
    57  
    58  // readTs == startTs
    59  func TestTxnRead1(t *testing.T) {
    60  	op := &api.Operation{}
    61  	op.DropAll = true
    62  	require.NoError(t, s.dg.Alter(context.Background(), op))
    63  
    64  	txn := s.dg.NewTxn()
    65  	mu := &api.Mutation{}
    66  	mu.SetJson = []byte(`{"name": "Manish"}`)
    67  	assigned, err := txn.Mutate(context.Background(), mu)
    68  	if err != nil {
    69  		log.Fatalf("Error while running mutation: %v\n", err)
    70  	}
    71  	if len(assigned.Uids) != 1 {
    72  		log.Fatalf("Error. Nothing assigned. %+v\n", assigned)
    73  	}
    74  	uid := retrieveUids(assigned.Uids)[0]
    75  	q := fmt.Sprintf(`{ me(func: uid(%s)) { name }}`, uid)
    76  	resp, err := txn.Query(context.Background(), q)
    77  	if err != nil {
    78  		log.Fatalf("Error while running query: %v\n", err)
    79  	}
    80  	x.AssertTrue(bytes.Equal(resp.Json, []byte("{\"me\":[{\"name\":\"Manish\"}]}")))
    81  	require.NoError(t, txn.Commit(context.Background()))
    82  }
    83  
    84  // readTs < commitTs
    85  func TestTxnRead2(t *testing.T) {
    86  	txn := s.dg.NewTxn()
    87  
    88  	mu := &api.Mutation{}
    89  	mu.SetJson = []byte(`{"name": "Manish"}`)
    90  	assigned, err := txn.Mutate(context.Background(), mu)
    91  	if err != nil {
    92  		log.Fatalf("Error while running mutation: %v\n", err)
    93  	}
    94  	if len(assigned.Uids) != 1 {
    95  		log.Fatalf("Error. Nothing assigned. %+v\n", assigned)
    96  	}
    97  	var uid string
    98  	for _, u := range assigned.Uids {
    99  		uid = u
   100  	}
   101  
   102  	txn2 := s.dg.NewTxn()
   103  
   104  	q := fmt.Sprintf(`{ me(func: uid(%s)) { name }}`, uid)
   105  	resp, err := txn2.Query(context.Background(), q)
   106  	if err != nil {
   107  		log.Fatalf("Error while running query: %v\n", err)
   108  	}
   109  	x.AssertTruef(bytes.Equal(resp.Json, []byte("{\"me\":[]}")), "%s", resp.Json)
   110  	require.NoError(t, txn.Commit(context.Background()))
   111  }
   112  
   113  // readTs > commitTs
   114  func TestTxnRead3(t *testing.T) {
   115  	op := &api.Operation{}
   116  	op.DropAttr = "name"
   117  	attempts := 0
   118  	for attempts < 10 {
   119  		if err := s.dg.Alter(context.Background(), op); err == nil {
   120  			break
   121  		}
   122  		attempts++
   123  	}
   124  
   125  	txn := s.dg.NewTxn()
   126  
   127  	mu := &api.Mutation{}
   128  	mu.SetJson = []byte(`{"name": "Manish"}`)
   129  	assigned, err := txn.Mutate(context.Background(), mu)
   130  	if err != nil {
   131  		log.Fatalf("Error while running mutation: %v\n", err)
   132  	}
   133  	if len(assigned.Uids) != 1 {
   134  		log.Fatalf("Error. Nothing assigned. %+v\n", assigned)
   135  	}
   136  	var uid string
   137  	for _, u := range assigned.Uids {
   138  		uid = u
   139  	}
   140  
   141  	require.NoError(t, txn.Commit(context.Background()))
   142  	txn = s.dg.NewTxn()
   143  	q := fmt.Sprintf(`{ me(func: uid(%s)) { name }}`, uid)
   144  	resp, err := txn.Query(context.Background(), q)
   145  	if err != nil {
   146  		log.Fatalf("Error while running query: %v\n", err)
   147  	}
   148  	x.AssertTrue(bytes.Equal(resp.Json, []byte("{\"me\":[{\"name\":\"Manish\"}]}")))
   149  }
   150  
   151  // readTs > commitTs
   152  func TestTxnRead4(t *testing.T) {
   153  	txn := s.dg.NewTxn()
   154  
   155  	mu := &api.Mutation{}
   156  	mu.SetJson = []byte(`{"name": "Manish"}`)
   157  	assigned, err := txn.Mutate(context.Background(), mu)
   158  	if err != nil {
   159  		log.Fatalf("Error while running mutation: %v\n", err)
   160  	}
   161  	if len(assigned.Uids) != 1 {
   162  		log.Fatalf("Error. Nothing assigned. %+v\n", assigned)
   163  	}
   164  	var uid string
   165  	for _, u := range assigned.Uids {
   166  		uid = u
   167  	}
   168  
   169  	require.NoError(t, txn.Commit(context.Background()))
   170  	txn2 := s.dg.NewTxn()
   171  
   172  	txn3 := s.dg.NewTxn()
   173  	mu = &api.Mutation{}
   174  	mu.SetJson = []byte(fmt.Sprintf(`{"uid": "%s", "name": "Manish2"}`, uid))
   175  	assigned, err = txn3.Mutate(context.Background(), mu)
   176  	if err != nil {
   177  		log.Fatalf("Error while running mutation: %v\n", err)
   178  	}
   179  	q := fmt.Sprintf(`{ me(func: uid(%s)) { name }}`, uid)
   180  	resp, err := txn2.Query(context.Background(), q)
   181  	if err != nil {
   182  		log.Fatalf("Error while running query: %v\n", err)
   183  	}
   184  	x.AssertTrue(bytes.Equal(resp.Json, []byte("{\"me\":[{\"name\":\"Manish\"}]}")))
   185  
   186  	require.NoError(t, txn3.Commit(context.Background()))
   187  
   188  	txn4 := s.dg.NewTxn()
   189  	q = fmt.Sprintf(`{ me(func: uid(%s)) { name }}`, uid)
   190  	resp, err = txn4.Query(context.Background(), q)
   191  	if err != nil {
   192  		log.Fatalf("Error while running query: %v\n", err)
   193  	}
   194  	x.AssertTrue(bytes.Equal(resp.Json, []byte("{\"me\":[{\"name\":\"Manish2\"}]}")))
   195  }
   196  
   197  func TestTxnRead5(t *testing.T) {
   198  	txn := s.dg.NewTxn()
   199  
   200  	mu := &api.Mutation{}
   201  	mu.SetJson = []byte(`{"name": "Manish"}`)
   202  	assigned, err := txn.Mutate(context.Background(), mu)
   203  	if err != nil {
   204  		log.Fatalf("Error while running mutation: %v\n", err)
   205  	}
   206  	if len(assigned.Uids) != 1 {
   207  		log.Fatalf("Error. Nothing assigned. %+v\n", assigned)
   208  	}
   209  	var uid string
   210  	for _, u := range assigned.Uids {
   211  		uid = u
   212  	}
   213  
   214  	require.NoError(t, txn.Commit(context.Background()))
   215  	q := fmt.Sprintf(`{ me(func: uid(%s)) { name }}`, uid)
   216  	// We don't supply startTs, it should be fetched from zero by dgraph alpha.
   217  	req := api.Request{
   218  		Query: q,
   219  	}
   220  
   221  	conn, err := grpc.Dial(addr, grpc.WithInsecure())
   222  	if err != nil {
   223  		log.Fatal(err)
   224  	}
   225  	dc := api.NewDgraphClient(conn)
   226  
   227  	resp, err := dc.Query(context.Background(), &req)
   228  	if err != nil {
   229  		log.Fatalf("Error while running query: %v\n", err)
   230  	}
   231  	x.AssertTrue(bytes.Equal(resp.Json, []byte("{\"me\":[{\"name\":\"Manish\"}]}")))
   232  	x.AssertTrue(resp.Txn.StartTs > 0)
   233  
   234  	mu = &api.Mutation{}
   235  	mu.SetJson = []byte(fmt.Sprintf("{\"uid\": \"%s\", \"name\": \"Manish2\"}", uid))
   236  
   237  	muReq := api.Request{
   238  		Mutations: []*api.Mutation{mu},
   239  		CommitNow: true,
   240  	}
   241  	res, err := dc.Query(context.Background(), &muReq)
   242  	if err != nil {
   243  		log.Fatalf("Error while running mutation: %v\n", err)
   244  	}
   245  	x.AssertTrue(res.Txn.StartTs > 0)
   246  	resp, err = dc.Query(context.Background(), &req)
   247  	if err != nil {
   248  		log.Fatalf("Error while running query: %v\n", err)
   249  	}
   250  	x.AssertTrue(bytes.Equal(resp.Json, []byte(`{"me":[{"name":"Manish2"}]}`)))
   251  }
   252  
   253  func TestConflict(t *testing.T) {
   254  	op := &api.Operation{}
   255  	op.DropAll = true
   256  	require.NoError(t, s.dg.Alter(context.Background(), op))
   257  
   258  	txn := s.dg.NewTxn()
   259  
   260  	mu := &api.Mutation{}
   261  	mu.SetJson = []byte(`{"name": "Manish"}`)
   262  	assigned, err := txn.Mutate(context.Background(), mu)
   263  	if err != nil {
   264  		log.Fatalf("Error while running mutation: %v\n", err)
   265  	}
   266  	if len(assigned.Uids) != 1 {
   267  		log.Fatalf("Error. Nothing assigned. %+v\n", assigned)
   268  	}
   269  	var uid string
   270  	for _, u := range assigned.Uids {
   271  		uid = u
   272  	}
   273  
   274  	txn2 := s.dg.NewTxn()
   275  	mu = &api.Mutation{}
   276  	mu.SetJson = []byte(fmt.Sprintf(`{"uid": "%s", "name": "Manish"}`, uid))
   277  	x.Check2(txn2.Mutate(context.Background(), mu))
   278  
   279  	require.NoError(t, txn.Commit(context.Background()))
   280  	err = txn2.Commit(context.Background())
   281  	x.AssertTrue(err != nil)
   282  
   283  	txn = s.dg.NewTxn()
   284  	q := fmt.Sprintf(`{ me(func: uid(%s)) { name }}`, uid)
   285  	resp, err := txn.Query(context.Background(), q)
   286  	if err != nil {
   287  		log.Fatalf("Error while running query: %v\n", err)
   288  	}
   289  	x.AssertTrue(bytes.Equal(resp.Json, []byte("{\"me\":[{\"name\":\"Manish\"}]}")))
   290  }
   291  
   292  func TestConflictTimeout(t *testing.T) {
   293  	var uid string
   294  	txn := s.dg.NewTxn()
   295  	{
   296  		mu := &api.Mutation{}
   297  		mu.SetJson = []byte(`{"name": "Manish"}`)
   298  		assigned, err := txn.Mutate(context.Background(), mu)
   299  		if err != nil {
   300  			log.Fatalf("Error while running mutation: %v\n", err)
   301  		}
   302  		if len(assigned.Uids) != 1 {
   303  			log.Fatalf("Error. Nothing assigned. %+v\n", assigned)
   304  		}
   305  		for _, u := range assigned.Uids {
   306  			uid = u
   307  		}
   308  	}
   309  
   310  	txn2 := s.dg.NewTxn()
   311  	q := fmt.Sprintf(`{ me(func: uid(%s)) { name }}`, uid)
   312  	_, err := txn2.Query(context.Background(), q)
   313  	require.NoError(t, err)
   314  
   315  	mu := &api.Mutation{}
   316  	mu.SetJson = []byte(fmt.Sprintf(`{"uid": "%s", "name": "Jan the man"}`, uid))
   317  	_, err = txn2.Mutate(context.Background(), mu)
   318  	if err == nil {
   319  		require.NoError(t, txn2.Commit(context.Background()))
   320  	}
   321  
   322  	err = txn.Commit(context.Background())
   323  	x.AssertTrue(err != nil)
   324  
   325  	txn3 := s.dg.NewTxn()
   326  	q = fmt.Sprintf(`{ me(func: uid(%s)) { name }}`, uid)
   327  	_, err = txn3.Query(context.Background(), q)
   328  	require.NoError(t, err)
   329  }
   330  
   331  func TestConflictTimeout2(t *testing.T) {
   332  	var uid string
   333  	txn := s.dg.NewTxn()
   334  	{
   335  
   336  		mu := &api.Mutation{}
   337  		mu.SetJson = []byte(`{"name": "Manish"}`)
   338  		assigned, err := txn.Mutate(context.Background(), mu)
   339  		if err != nil {
   340  			log.Fatalf("Error while running mutation: %v\n", err)
   341  		}
   342  		if len(assigned.Uids) != 1 {
   343  			log.Fatalf("Error. Nothing assigned. %+v\n", assigned)
   344  		}
   345  		for _, u := range assigned.Uids {
   346  			uid = u
   347  		}
   348  	}
   349  
   350  	txn2 := s.dg.NewTxn()
   351  	mu := &api.Mutation{}
   352  	mu.SetJson = []byte(fmt.Sprintf(`{"uid": "%s", "name": "Jan the man"}`, uid))
   353  	x.Check2(txn2.Mutate(context.Background(), mu))
   354  
   355  	require.NoError(t, txn.Commit(context.Background()))
   356  	err := txn2.Commit(context.Background())
   357  	x.AssertTrue(err != nil)
   358  
   359  	txn3 := s.dg.NewTxn()
   360  	mu = &api.Mutation{}
   361  	mu.SetJson = []byte(fmt.Sprintf(`{"uid": "%s", "name": "Jan the man"}`, uid))
   362  	assigned, err := txn3.Mutate(context.Background(), mu)
   363  	if err == nil {
   364  		require.NoError(t, txn3.Commit(context.Background()))
   365  	}
   366  	for _, u := range assigned.Uids {
   367  		uid = u
   368  	}
   369  
   370  	txn4 := s.dg.NewTxn()
   371  	q := fmt.Sprintf(`{ me(func: uid(%s)) { name }}`, uid)
   372  	_, err = txn4.Query(context.Background(), q)
   373  	require.NoError(t, err)
   374  }
   375  
   376  func TestIgnoreIndexConflict(t *testing.T) {
   377  	op := &api.Operation{}
   378  	op.DropAll = true
   379  	require.NoError(t, s.dg.Alter(context.Background(), op))
   380  
   381  	op = &api.Operation{}
   382  	op.Schema = `name: string @index(exact) .`
   383  	if err := s.dg.Alter(context.Background(), op); err != nil {
   384  		log.Fatal(err)
   385  	}
   386  
   387  	txn := s.dg.NewTxn()
   388  	mu := &api.Mutation{}
   389  	mu.SetJson = []byte(`{"name": "Manish"}`)
   390  	assigned, err := txn.Mutate(context.Background(), mu)
   391  	if err != nil {
   392  		log.Fatalf("Error while running mutation: %v\n", err)
   393  	}
   394  	if len(assigned.Uids) != 1 {
   395  		log.Fatalf("Error. Nothing assigned. %+v\n", assigned)
   396  	}
   397  	var uid1, uid2 string
   398  	for _, u := range assigned.Uids {
   399  		uid1 = u
   400  	}
   401  
   402  	txn2 := s.dg.NewTxn()
   403  	mu = &api.Mutation{}
   404  	mu.SetJson = []byte(`{"name": "Manish"}`)
   405  	assigned, err = txn2.Mutate(context.Background(), mu)
   406  	if err != nil {
   407  		log.Fatalf("Error while running mutation: %v\n", err)
   408  	}
   409  	if len(assigned.Uids) != 1 {
   410  		log.Fatalf("Error. Nothing assigned. %+v\n", assigned)
   411  	}
   412  	for _, u := range assigned.Uids {
   413  		uid2 = u
   414  	}
   415  
   416  	require.NoError(t, txn.Commit(context.Background()))
   417  	require.NoError(t, txn2.Commit(context.Background()))
   418  
   419  	txn = s.dg.NewTxn()
   420  	q := `{ me(func: eq(name, "Manish")) { uid }}`
   421  	resp, err := txn.Query(context.Background(), q)
   422  	if err != nil {
   423  		log.Fatalf("Error while running query: %v\n", err)
   424  	}
   425  	expectedResp := []byte(fmt.Sprintf(`{"me":[{"uid":"%s"},{"uid":"%s"}]}`, uid1, uid2))
   426  	require.Equal(t, expectedResp, resp.Json)
   427  }
   428  
   429  func TestReadIndexKeySameTxn(t *testing.T) {
   430  	op := &api.Operation{}
   431  	op.DropAll = true
   432  	require.NoError(t, s.dg.Alter(context.Background(), op))
   433  
   434  	op = &api.Operation{}
   435  	op.Schema = `name: string @index(exact) .`
   436  	if err := s.dg.Alter(context.Background(), op); err != nil {
   437  		log.Fatal(err)
   438  	}
   439  
   440  	txn := s.dg.NewTxn()
   441  
   442  	mu := &api.Mutation{
   443  		CommitNow: true,
   444  		SetJson:   []byte(`{"name": "Manish"}`),
   445  	}
   446  	assigned, err := txn.Mutate(context.Background(), mu)
   447  	if err != nil {
   448  		log.Fatalf("Error while running mutation: %v\n", err)
   449  	}
   450  	if len(assigned.Uids) != 1 {
   451  		log.Fatalf("Error. Nothing assigned. %+v\n", assigned)
   452  	}
   453  	var uid string
   454  	for _, u := range assigned.Uids {
   455  		uid = u
   456  	}
   457  
   458  	txn = s.dg.NewTxn()
   459  	defer txn.Discard(context.Background())
   460  	q := `{ me(func: le(name, "Manish")) { uid }}`
   461  	resp, err := txn.Query(context.Background(), q)
   462  	if err != nil {
   463  		log.Fatalf("Error while running query: %v\n", err)
   464  	}
   465  	expectedResp := []byte(fmt.Sprintf(`{"me":[{"uid":"%s"}]}`, uid))
   466  	x.AssertTrue(bytes.Equal(resp.Json, expectedResp))
   467  }
   468  
   469  func TestEmailUpsert(t *testing.T) {
   470  	op := &api.Operation{}
   471  	op.DropAll = true
   472  	require.NoError(t, s.dg.Alter(context.Background(), op))
   473  
   474  	op = &api.Operation{}
   475  	op.Schema = `email: string @index(exact) @upsert .`
   476  	if err := s.dg.Alter(context.Background(), op); err != nil {
   477  		log.Fatal(err)
   478  	}
   479  
   480  	txn1 := s.dg.NewTxn()
   481  	mu := &api.Mutation{}
   482  	mu.SetJson = []byte(`{"uid": "_:user1", "email": "email@email.org"}`)
   483  	_, err := txn1.Mutate(context.Background(), mu)
   484  	assert.Nil(t, err)
   485  
   486  	txn2 := s.dg.NewTxn()
   487  	mu = &api.Mutation{}
   488  	mu.SetJson = []byte(`{"uid": "_:user2", "email": "email@email.org"}`)
   489  	_, err = txn2.Mutate(context.Background(), mu)
   490  	assert.Nil(t, err)
   491  
   492  	txn3 := s.dg.NewTxn()
   493  	mu = &api.Mutation{}
   494  	mu.SetJson = []byte(`{"uid": "_:user3", "email": "email3@email.org"}`)
   495  	_, err = txn3.Mutate(context.Background(), mu)
   496  	assert.Nil(t, err)
   497  
   498  	require.NoError(t, txn1.Commit(context.Background()))
   499  	require.NotNil(t, txn2.Commit(context.Background()))
   500  	require.NoError(t, txn3.Commit(context.Background()))
   501  }
   502  
   503  // TestFriendList tests that we are not able to set a node to node edge between
   504  // the same nodes concurrently.
   505  func TestFriendList(t *testing.T) {
   506  	op := &api.Operation{}
   507  	op.DropAll = true
   508  	require.NoError(t, s.dg.Alter(context.Background(), op))
   509  
   510  	op = &api.Operation{}
   511  	op.Schema = `
   512  	friend: [uid] @reverse .`
   513  	if err := s.dg.Alter(context.Background(), op); err != nil {
   514  		log.Fatal(err)
   515  	}
   516  
   517  	txn1 := s.dg.NewTxn()
   518  	mu := &api.Mutation{}
   519  	mu.SetJson = []byte(`{"uid": "0x01", "friend": [{"uid": "0x02"}]}`)
   520  	_, err := txn1.Mutate(context.Background(), mu)
   521  	assert.Nil(t, err)
   522  
   523  	txn2 := s.dg.NewTxn()
   524  	mu = &api.Mutation{}
   525  	mu.SetJson = []byte(`{"uid": "0x01", "friend": [{"uid": "0x02"}]}`)
   526  	_, err = txn2.Mutate(context.Background(), mu)
   527  	assert.Nil(t, err)
   528  
   529  	txn3 := s.dg.NewTxn()
   530  	mu = &api.Mutation{}
   531  	mu.SetJson = []byte(`{"uid": "0x01", "friend": [{"uid": "0x03"}]}`)
   532  	_, err = txn3.Mutate(context.Background(), mu)
   533  	assert.Nil(t, err)
   534  
   535  	require.NoError(t, txn1.Commit(context.Background()))
   536  	require.NotNil(t, txn2.Commit(context.Background()))
   537  	require.NoError(t, txn3.Commit(context.Background()))
   538  }
   539  
   540  // TestNameSet tests that we are not able to set a property edge for the same
   541  // subject id concurrently.
   542  func TestNameSet(t *testing.T) {
   543  	op := &api.Operation{}
   544  	op.DropAll = true
   545  	require.NoError(t, s.dg.Alter(context.Background(), op))
   546  
   547  	op = &api.Operation{}
   548  	op.Schema = `name: string .`
   549  	if err := s.dg.Alter(context.Background(), op); err != nil {
   550  		log.Fatal(err)
   551  	}
   552  
   553  	txn1 := s.dg.NewTxn()
   554  	mu := &api.Mutation{}
   555  	mu.SetJson = []byte(`{"uid": "0x01", "name": "manish"}`)
   556  	_, err := txn1.Mutate(context.Background(), mu)
   557  	assert.Nil(t, err)
   558  
   559  	txn2 := s.dg.NewTxn()
   560  	mu = &api.Mutation{}
   561  	mu.SetJson = []byte(`{"uid": "0x01", "name": "contributor"}`)
   562  	_, err = txn2.Mutate(context.Background(), mu)
   563  	assert.Nil(t, err)
   564  
   565  	require.NoError(t, txn1.Commit(context.Background()))
   566  	require.NotNil(t, txn2.Commit(context.Background()))
   567  }
   568  
   569  // retrieve the uids in the uidMap in the order of ascending keys
   570  func retrieveUids(uidMap map[string]string) []string {
   571  	keys := make([]string, 0, len(uidMap))
   572  	for key := range uidMap {
   573  		keys = append(keys, key)
   574  	}
   575  
   576  	sort.Slice(keys, func(i, j int) bool {
   577  		num1 := strings.Split(keys[i], ".")[2]
   578  
   579  		num2 := strings.Split(keys[j], ".")[2]
   580  		n1, err := strconv.Atoi(num1)
   581  		x.Check(err)
   582  		n2, err := strconv.Atoi(num2)
   583  		x.Check(err)
   584  		return n1 < n2
   585  	})
   586  
   587  	uids := make([]string, 0, len(uidMap))
   588  	for _, k := range keys {
   589  		uids = append(uids, uidMap[k])
   590  	}
   591  	return uids
   592  }
   593  
   594  func TestSPStar(t *testing.T) {
   595  	op := &api.Operation{}
   596  	op.DropAll = true
   597  	require.NoError(t, s.dg.Alter(context.Background(), op))
   598  
   599  	op = &api.Operation{}
   600  	op.Schema = `friend: [uid] .`
   601  	require.NoError(t, s.dg.Alter(context.Background(), op))
   602  
   603  	txn := s.dg.NewTxn()
   604  	mu := &api.Mutation{}
   605  	mu.SetJson = []byte(`{"name": "Manish", "friend": [{"name": "Jan"}]}`)
   606  	assigned, err := txn.Mutate(context.Background(), mu)
   607  	require.Equal(t, 2, len(assigned.Uids))
   608  	uid1 := retrieveUids(assigned.Uids)[0]
   609  	require.NoError(t, err)
   610  	require.Equal(t, 2, len(assigned.Uids))
   611  	require.NoError(t, txn.Commit(context.Background()))
   612  
   613  	txn = s.dg.NewTxn()
   614  	mu = &api.Mutation{}
   615  	dgo.DeleteEdges(mu, uid1, "friend")
   616  	assigned, err = txn.Mutate(context.Background(), mu)
   617  	require.NoError(t, err)
   618  	require.Equal(t, 0, len(assigned.Uids))
   619  
   620  	mu = &api.Mutation{}
   621  	mu.SetJson = []byte(fmt.Sprintf(`{"uid": "%s" ,"name": "Manish", "friend": [{"name": "Jan2"}]}`, uid1))
   622  	assigned, err = txn.Mutate(context.Background(), mu)
   623  	require.NoError(t, err)
   624  	require.Equal(t, 1, len(assigned.Uids))
   625  	uid2 := retrieveUids(assigned.Uids)[0]
   626  
   627  	q := fmt.Sprintf(`{
   628  		me(func: uid(%s)) {
   629  			uid
   630  			friend {
   631  				uid
   632  				name
   633  			}
   634  		}
   635  	}`, uid1)
   636  
   637  	resp, err := txn.Query(context.Background(), q)
   638  	require.NoError(t, err)
   639  	expectedResp := fmt.Sprintf(`{"me":[{"uid":"%s", "friend": [{"name": "Jan2", "uid":"%s"}]}]}`, uid1, uid2)
   640  	require.JSONEq(t, expectedResp, string(resp.Json))
   641  }
   642  
   643  func TestSPStar2(t *testing.T) {
   644  	op := &api.Operation{}
   645  	op.DropAll = true
   646  	require.NoError(t, s.dg.Alter(context.Background(), op))
   647  
   648  	op = &api.Operation{}
   649  	op.Schema = `friend: [uid] .`
   650  	require.NoError(t, s.dg.Alter(context.Background(), op))
   651  
   652  	// Add edge
   653  	txn := s.dg.NewTxn()
   654  	mu := &api.Mutation{}
   655  	mu.SetJson = []byte(`{"name": "Manish", "friend": [{"name": "Jan"}]}`)
   656  	assigned, err := txn.Mutate(context.Background(), mu)
   657  
   658  	require.NoError(t, err)
   659  	require.Equal(t, 2, len(assigned.Uids))
   660  
   661  	uids := retrieveUids(assigned.Uids)
   662  	uid1 := uids[0]
   663  	uid2 := uids[1]
   664  	q := fmt.Sprintf(`{
   665  		me(func: uid(%s)) {
   666  			uid
   667  			friend {
   668  				uid
   669  				name
   670  			}
   671  		}
   672  	}`, uid1)
   673  
   674  	resp, err := txn.Query(context.Background(), q)
   675  	require.NoError(t, err)
   676  	expectedResp := fmt.Sprintf(`{"me":[{"uid":"%s", "friend": [{"name": "Jan", "uid":"%s"}]}]}`, uid1, uid2)
   677  	require.JSONEq(t, expectedResp, string(resp.Json))
   678  
   679  	// Delete S P *
   680  	mu = &api.Mutation{}
   681  	dgo.DeleteEdges(mu, uid1, "friend")
   682  	assigned, err = txn.Mutate(context.Background(), mu)
   683  	require.NoError(t, err)
   684  	require.Equal(t, 0, len(assigned.Uids))
   685  
   686  	resp, err = txn.Query(context.Background(), q)
   687  	require.NoError(t, err)
   688  	expectedResp = fmt.Sprintf(`{"me":[{"uid":"%s"}]}`, uid1)
   689  	require.JSONEq(t, expectedResp, string(resp.Json))
   690  
   691  	// Add edge
   692  	mu = &api.Mutation{}
   693  	mu.SetJson = []byte(fmt.Sprintf(`{"uid": "%s" ,"name": "Manish", "friend": [{"name": "Jan2"}]}`, uid1))
   694  	assigned, err = txn.Mutate(context.Background(), mu)
   695  	require.NoError(t, err)
   696  	require.Equal(t, 1, len(assigned.Uids))
   697  	uid3 := retrieveUids(assigned.Uids)[0]
   698  	resp, err = txn.Query(context.Background(), q)
   699  	require.NoError(t, err)
   700  	expectedResp = fmt.Sprintf(`{"me":[{"uid":"%s", "friend": [{"name": "Jan2", "uid":"%s"}]}]}`,
   701  		uid1, uid3)
   702  	require.JSONEq(t, expectedResp, string(resp.Json))
   703  
   704  	// Delete S P *
   705  	mu = &api.Mutation{}
   706  	dgo.DeleteEdges(mu, uid1, "friend")
   707  	assigned, err = txn.Mutate(context.Background(), mu)
   708  	require.NoError(t, err)
   709  	require.Equal(t, 0, len(assigned.Uids))
   710  
   711  	resp, err = txn.Query(context.Background(), q)
   712  	require.NoError(t, err)
   713  	expectedResp = fmt.Sprintf(`{"me":[{"uid":"%s"}]}`, uid1)
   714  	require.JSONEq(t, expectedResp, string(resp.Json))
   715  
   716  	// Add edge
   717  	mu = &api.Mutation{}
   718  	mu.SetJson = []byte(fmt.Sprintf(`{"uid": "%s" ,"name": "Manish", "friend": [{"name": "Jan3"}]}`, uid1))
   719  	assigned, err = txn.Mutate(context.Background(), mu)
   720  	require.NoError(t, err)
   721  	require.Equal(t, 1, len(assigned.Uids))
   722  
   723  	uid4 := retrieveUids(assigned.Uids)[0]
   724  	resp, err = txn.Query(context.Background(), q)
   725  	require.NoError(t, err)
   726  	expectedResp = fmt.Sprintf(`{"me":[{"uid":"%s", "friend": [{"name": "Jan3", "uid":"%s"}]}]}`, uid1, uid4)
   727  	require.JSONEq(t, expectedResp, string(resp.Json))
   728  }
   729  
   730  var (
   731  	ctxb       = context.Background()
   732  	countQuery = `
   733  query countAnswers($num: int) {
   734    me(func: eq(count(answer), $num)) {
   735      uid
   736      count(answer)
   737    }
   738  }
   739  `
   740  )
   741  
   742  func TestCountIndexConcurrentTxns(t *testing.T) {
   743  	dg := testutil.DgraphClientWithGroot(testutil.SockAddr)
   744  	testutil.DropAll(t, dg)
   745  	alterSchema(dg, "answer: [uid] @count .")
   746  
   747  	// Expected edge count of 0x100: 1
   748  	txn0 := dg.NewTxn()
   749  	mu := api.Mutation{SetNquads: []byte("<0x100> <answer> <0x200> .")}
   750  	_, err := txn0.Mutate(ctxb, &mu)
   751  	x.Check(err)
   752  	err = txn0.Commit(ctxb)
   753  	x.Check(err)
   754  
   755  	// The following two mutations are in separate interleaved txns.
   756  	txn1 := dg.NewTxn()
   757  	mu = api.Mutation{SetNquads: []byte("<0x1> <answer> <0x2> .")}
   758  	_, err = txn1.Mutate(ctxb, &mu)
   759  	x.Check(err)
   760  
   761  	txn2 := dg.NewTxn()
   762  	mu = api.Mutation{SetNquads: []byte("<0x1> <answer> <0x3> .")}
   763  	_, err = txn2.Mutate(ctxb, &mu)
   764  	x.Check(err)
   765  
   766  	err = txn1.Commit(ctxb)
   767  	x.Check(err)
   768  	err = txn2.Commit(ctxb)
   769  	require.Error(t, err,
   770  		"the txn2 should be aborted due to concurrent update on the count index of	<0x01>")
   771  
   772  	// retry the mutatiton
   773  	txn3 := dg.NewTxn()
   774  	_, err = txn3.Mutate(ctxb, &mu)
   775  	x.Check(err)
   776  	err = txn3.Commit(ctxb)
   777  	x.Check(err)
   778  
   779  	// Verify count queries
   780  	txn := dg.NewReadOnlyTxn()
   781  	vars := map[string]string{"$num": "1"}
   782  	resp, err := txn.QueryWithVars(ctxb, countQuery, vars)
   783  	x.Check(err)
   784  	js := string(resp.GetJson())
   785  	require.JSONEq(t,
   786  		`{"me": [{"count(answer)": 1, "uid": "0x100"}]}`,
   787  		js)
   788  	txn = dg.NewReadOnlyTxn()
   789  	vars = map[string]string{"$num": "2"}
   790  	resp, err = txn.QueryWithVars(ctxb, countQuery, vars)
   791  	x.Check(err)
   792  	js = string(resp.GetJson())
   793  	require.JSONEq(t,
   794  		`{"me": [{"count(answer)": 2, "uid": "0x1"}]}`,
   795  		js)
   796  }
   797  
   798  func TestCountIndexSerialTxns(t *testing.T) {
   799  	dg := testutil.DgraphClientWithGroot(testutil.SockAddr)
   800  	testutil.DropAll(t, dg)
   801  	alterSchema(dg, "answer: [uid] @count .")
   802  
   803  	// Expected Edge count of 0x100: 1
   804  	txn0 := dg.NewTxn()
   805  	mu := api.Mutation{SetNquads: []byte("<0x100> <answer> <0x200> .")}
   806  	_, err := txn0.Mutate(ctxb, &mu)
   807  	require.NoError(t, err)
   808  	err = txn0.Commit(ctxb)
   809  	require.NoError(t, err)
   810  
   811  	// Expected edge count of 0x1: 2
   812  	// This should NOT appear in the query result
   813  	// The following two mutations are in serial txns.
   814  	txn1 := dg.NewTxn()
   815  	mu = api.Mutation{SetNquads: []byte("<0x1> <answer> <0x2> .")}
   816  	_, err = txn1.Mutate(ctxb, &mu)
   817  	require.NoError(t, err)
   818  	err = txn1.Commit(ctxb)
   819  	require.NoError(t, err)
   820  
   821  	txn2 := dg.NewTxn()
   822  	mu = api.Mutation{SetNquads: []byte("<0x1> <answer> <0x3> .")}
   823  	_, err = txn2.Mutate(ctxb, &mu)
   824  	require.NoError(t, err)
   825  	err = txn2.Commit(ctxb)
   826  	require.NoError(t, err)
   827  
   828  	// Verify query
   829  	txn := dg.NewReadOnlyTxn()
   830  	vars := map[string]string{"$num": "1"}
   831  	resp, err := txn.QueryWithVars(ctxb, countQuery, vars)
   832  	require.NoError(t, err)
   833  	js := string(resp.GetJson())
   834  	require.JSONEq(t,
   835  		`{"me": [{"count(answer)": 1, "uid": "0x100"}]}`,
   836  		js)
   837  	txn = dg.NewReadOnlyTxn()
   838  	vars = map[string]string{"$num": "2"}
   839  	resp, err = txn.QueryWithVars(ctxb, countQuery, vars)
   840  	require.NoError(t, err)
   841  	js = string(resp.GetJson())
   842  	require.JSONEq(t,
   843  		`{"me": [{"count(answer)": 2, "uid": "0x1"}]}`,
   844  		js)
   845  }
   846  
   847  func TestCountIndexSameTxn(t *testing.T) {
   848  	dg := testutil.DgraphClientWithGroot(testutil.SockAddr)
   849  	testutil.DropAll(t, dg)
   850  	alterSchema(dg, "answer: [uid] @count .")
   851  
   852  	// Expected Edge count of 0x100: 1
   853  	txn0 := dg.NewTxn()
   854  	mu := api.Mutation{SetNquads: []byte("<0x100> <answer> <0x200> .")}
   855  	_, err := txn0.Mutate(ctxb, &mu)
   856  	x.Check(err)
   857  	err = txn0.Commit(ctxb)
   858  	x.Check(err)
   859  
   860  	// Expected edge count of 0x1: 2
   861  	// This should NOT appear in the query result
   862  	// The following two mutations are in the same txn.
   863  	txn1 := dg.NewTxn()
   864  	mu = api.Mutation{SetNquads: []byte("<0x1> <answer> <0x2> .")}
   865  	_, err = txn1.Mutate(ctxb, &mu)
   866  	x.Check(err)
   867  	mu = api.Mutation{SetNquads: []byte("<0x1> <answer> <0x3> .")}
   868  	_, err = txn1.Mutate(ctxb, &mu)
   869  	x.Check(err)
   870  	err = txn1.Commit(ctxb)
   871  	x.Check(err)
   872  
   873  	// Verify query
   874  	txn := dg.NewReadOnlyTxn()
   875  	vars := map[string]string{"$num": "1"}
   876  	resp, err := txn.QueryWithVars(ctxb, countQuery, vars)
   877  	x.Check(err)
   878  	js := string(resp.GetJson())
   879  	require.JSONEq(t,
   880  		`{"me": [{"count(answer)": 1, "uid": "0x100"}]}`,
   881  		js)
   882  	txn = dg.NewReadOnlyTxn()
   883  	vars = map[string]string{"$num": "2"}
   884  	resp, err = txn.QueryWithVars(ctxb, countQuery, vars)
   885  	x.Check(err)
   886  	js = string(resp.GetJson())
   887  	require.JSONEq(t,
   888  		`{"me": [{"count(answer)": 2, "uid": "0x1"}]}`,
   889  		js)
   890  }
   891  
   892  func TestConcurrentQueryMutate(t *testing.T) {
   893  	testutil.DropAll(t, s.dg)
   894  	alterSchema(s.dg, "name: string .")
   895  
   896  	txn := s.dg.NewTxn()
   897  	defer txn.Discard(context.Background())
   898  
   899  	// Do one query, so a new timestamp is assigned to the txn.
   900  	q := `{me(func: uid(0x01)) { name }}`
   901  	_, err := txn.Query(context.Background(), q)
   902  	require.NoError(t, err)
   903  
   904  	var wg sync.WaitGroup
   905  	wg.Add(2)
   906  	start := time.Now()
   907  	go func() {
   908  		defer wg.Done()
   909  		for time.Since(start) < 5*time.Second {
   910  			mu := &api.Mutation{}
   911  			mu.SetJson = []byte(`{"uid": "0x01", "name": "manish"}`)
   912  			_, err := txn.Mutate(context.Background(), mu)
   913  			assert.Nil(t, err)
   914  		}
   915  	}()
   916  
   917  	go func() {
   918  		defer wg.Done()
   919  		for time.Since(start) < 5*time.Second {
   920  			_, err := txn.Query(context.Background(), q)
   921  			require.NoError(t, err)
   922  		}
   923  	}()
   924  	wg.Wait()
   925  	t.Logf("Done\n")
   926  }
   927  
   928  func alterSchema(dg *dgo.Dgraph, schema string) {
   929  	op := api.Operation{}
   930  	op.Schema = schema
   931  	err := dg.Alter(ctxb, &op)
   932  	x.Check(err)
   933  }