Skip to content
Snippets Groups Projects
query_test.go 11.7 KiB
Newer Older
 * Copyright 2015 DGraph Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 		http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package query

import (
Pawan Rawal's avatar
Pawan Rawal committed
	"bytes"
	"encoding/gob"
	"github.com/dgraph-io/dgraph/commit"
	"github.com/dgraph-io/dgraph/posting"
	"github.com/dgraph-io/dgraph/query/graph"
	"github.com/dgraph-io/dgraph/store"
	"github.com/dgraph-io/dgraph/task"
	"github.com/dgraph-io/dgraph/worker"
	"github.com/dgraph-io/dgraph/x"
)

func setErr(err *error, nerr error) {
	if err != nil {
		return
	}
	*err = nerr
}

func addEdge(t *testing.T, edge x.DirectedEdge, l *posting.List) {
	if err := l.AddMutation(edge, posting.Set); err != nil {
		t.Error(err)
	}
}

func checkName(t *testing.T, r *task.Result, idx int, expected string) {
	var tv task.Value
	if ok := r.Values(&tv, idx); !ok {
		t.Error("Unable to retrieve value")
	}
Manish R Jain's avatar
Manish R Jain committed
	var iname interface{}
	if err := posting.ParseValue(&iname, tv.ValBytes()); err != nil {
Manish R Jain's avatar
Manish R Jain committed
	name := iname.(string)
	if name != expected {
		t.Errorf("Expected: %v. Got: %v", expected, name)
	}
}

func checkSingleValue(t *testing.T, child *SubGraph,
	attr string, value string) {
Pawan Rawal's avatar
Pawan Rawal committed
	if child.Attr != attr || len(child.Result) == 0 {
		t.Error("Expected attr name with some.Result")
Pawan Rawal's avatar
Pawan Rawal committed
	uo := flatbuffers.GetUOffsetT(child.Result)
	r := new(task.Result)
Pawan Rawal's avatar
Pawan Rawal committed
	r.Init(child.Result, uo)
	if r.ValuesLength() != 1 {
		t.Errorf("Expected value length 1. Got: %v", r.ValuesLength())
	}
	if r.UidmatrixLength() != 1 {
		t.Errorf("Expected uidmatrix length 1. Got: %v", r.UidmatrixLength())
	var ul task.UidList
	if ok := r.Uidmatrix(&ul, 0); !ok {
		t.Errorf("While parsing uidlist")
	}

	if ul.UidsLength() != 0 {
		t.Errorf("Expected uids length 0. Got: %v", ul.UidsLength())
	}
	checkName(t, r, 0, value)
}

func TestNewGraph(t *testing.T) {
	var ex uint64
	ex = 101

	dir, err := ioutil.TempDir("", "storetest_")
	ps := new(store.Store)
	ps.Init(dir)
	sg, err := newGraph(ex, "")
	worker.Init(ps, nil, 0, 1)
Pawan Rawal's avatar
Pawan Rawal committed
	uo := flatbuffers.GetUOffsetT(sg.Result)
Pawan Rawal's avatar
Pawan Rawal committed
	r.Init(sg.Result, uo)
	if r.UidmatrixLength() != 1 {
		t.Errorf("Expected length 1. Got: %v", r.UidmatrixLength())
	}
	var ul task.UidList
	if ok := r.Uidmatrix(&ul, 0); !ok {
		t.Errorf("Unable to parse uidlist at index 0")
	}
	if ul.UidsLength() != 1 {
		t.Errorf("Expected length 1. Got: %v", ul.UidsLength())
	}
	if ul.Uids(0) != ex {
		t.Errorf("Expected uid: %v. Got: %v", ex, ul.Uids(0))
	}
}

func populateGraph(t *testing.T) (string, *store.Store) {
	dir, err := ioutil.TempDir("", "storetest_")
	if err != nil {
		t.Error(err)

	ps := new(store.Store)
	worker.Init(ps, nil, 0, 1)
	clog := commit.NewLogger(dir, "mutations", 50<<20)
	clog.Init()
	posting.Init(clog)

	// So, user we're interested in has uid: 1.
	// She has 4 friends: 23, 24, 25, 31, and 101
	edge := x.DirectedEdge{
		ValueId:   23,
		Source:    "testing",
		Timestamp: time.Now(),
	}
	addEdge(t, edge, posting.GetOrCreate(posting.Key(1, "friend"), ps))
	edge.ValueId = 24
	addEdge(t, edge, posting.GetOrCreate(posting.Key(1, "friend"), ps))
	edge.ValueId = 25
	addEdge(t, edge, posting.GetOrCreate(posting.Key(1, "friend"), ps))
	edge.ValueId = 31
	addEdge(t, edge, posting.GetOrCreate(posting.Key(1, "friend"), ps))
	edge.ValueId = 101
	addEdge(t, edge, posting.GetOrCreate(posting.Key(1, "friend"), ps))

	// Now let's add a few properties for the main user.
	edge.Value = "Michonne"
	addEdge(t, edge, posting.GetOrCreate(posting.Key(1, "name"), ps))
	edge.Value = "female"
	addEdge(t, edge, posting.GetOrCreate(posting.Key(1, "gender"), ps))
	edge.Value = "alive"
	addEdge(t, edge, posting.GetOrCreate(posting.Key(1, "status"), ps))

	// Now let's add a name for each of the friends, except 101.
	edge.Value = "Rick Grimes"
	addEdge(t, edge, posting.GetOrCreate(posting.Key(23, "name"), ps))
	edge.Value = "Glenn Rhee"
	addEdge(t, edge, posting.GetOrCreate(posting.Key(24, "name"), ps))
	edge.Value = "Daryl Dixon"
	addEdge(t, edge, posting.GetOrCreate(posting.Key(25, "name"), ps))
	edge.Value = "Andrea"
	addEdge(t, edge, posting.GetOrCreate(posting.Key(31, "name"), ps))
Pawan Rawal's avatar
Pawan Rawal committed
	addEdge(t, edge, posting.GetOrCreate(posting.Key(1, "_xid_"), ps))
Manish R Jain's avatar
Manish R Jain committed
}

func TestProcessGraph(t *testing.T) {
	dir, _ := populateGraph(t)
Manish R Jain's avatar
Manish R Jain committed

	// Alright. Now we have everything set up. Let's create the query.
	gq, _, err := gql.Parse(query)
	sg, err := ToSubGraph(gq)
	if err != nil {
		t.Error(err)
	}

	ch := make(chan error)
Manish R Jain's avatar
Manish R Jain committed
	go ProcessGraph(sg, ch, time.Minute)
	err = <-ch
	if err != nil {
		t.Error(err)
	}

	if len(sg.Children) != 4 {
		t.Errorf("Expected len 4. Got: %v", len(sg.Children))
	}
	child := sg.Children[0]
	if child.Attr != "friend" {
		t.Errorf("Expected attr friend. Got: %v", child.Attr)
	}
Pawan Rawal's avatar
Pawan Rawal committed
	if len(child.Result) == 0 {
		t.Errorf("Expected some.Result.")
Pawan Rawal's avatar
Pawan Rawal committed
	uo := flatbuffers.GetUOffsetT(child.Result)
	r := new(task.Result)
Pawan Rawal's avatar
Pawan Rawal committed
	r.Init(child.Result, uo)
	if r.UidmatrixLength() != 1 {
		t.Errorf("Expected 1 matrix. Got: %v", r.UidmatrixLength())
	}
	var ul task.UidList
	if ok := r.Uidmatrix(&ul, 0); !ok {
		t.Errorf("While parsing uidlist")
	}

	if ul.UidsLength() != 5 {
		t.Errorf("Expected 5 friends. Got: %v", ul.UidsLength())
	if ul.Uids(0) != 23 || ul.Uids(1) != 24 || ul.Uids(2) != 25 ||
		ul.Uids(3) != 31 || ul.Uids(4) != 101 {
		t.Errorf("Friend ids don't match")
	}
	if len(child.Children) != 1 || child.Children[0].Attr != "name" {
		t.Errorf("Expected attr name")
	}
	child = child.Children[0]
Pawan Rawal's avatar
Pawan Rawal committed
	uo = flatbuffers.GetUOffsetT(child.Result)
	r.Init(child.Result, uo)
	if r.ValuesLength() != 5 {
		t.Errorf("Expected 5 names of 5 friends")
	}
	checkName(t, r, 0, "Rick Grimes")
	checkName(t, r, 1, "Glenn Rhee")
	checkName(t, r, 2, "Daryl Dixon")
	checkName(t, r, 3, "Andrea")
	{
		var tv task.Value
		if ok := r.Values(&tv, 4); !ok {
			t.Error("Unable to retrieve value")
		}
		if tv.ValLength() != 1 || tv.ValBytes()[0] != 0x00 {
			t.Error("Expected a null byte")
		}
	}

	checkSingleValue(t, sg.Children[1], "name", "Michonne")
	checkSingleValue(t, sg.Children[2], "gender", "female")
	checkSingleValue(t, sg.Children[3], "status", "alive")
Manish R Jain's avatar
Manish R Jain committed
}

func TestToJson(t *testing.T) {
	dir, _ := populateGraph(t)
Manish R Jain's avatar
Manish R Jain committed

	// Alright. Now we have everything set up. Let's create the query.
	gq, _, err := gql.Parse(query)
	sg, err := ToSubGraph(gq)
Manish R Jain's avatar
Manish R Jain committed
	if err != nil {
		t.Error(err)
	}

	ch := make(chan error)
Manish R Jain's avatar
Manish R Jain committed
	go ProcessGraph(sg, ch, time.Minute)
Manish R Jain's avatar
Manish R Jain committed
	err = <-ch
	if err != nil {
		t.Error(err)
	}
func getProperty(properties []*graph.Property, prop string) *graph.Value {
	for _, p := range properties {
		if p.Prop == prop {
			return p.Val
		}
	}
	return nil
func TestToPB(t *testing.T) {
	dir, _ := populateGraph(t)
	defer os.RemoveAll(dir)

	query := `
		{
			me(_uid_:0x01) {
Pawan Rawal's avatar
Pawan Rawal committed
				_xid_
Pawan Rawal's avatar
Pawan Rawal committed
				friend {
				}
			}
		}
	`

	gq, _, err := gql.Parse(query)
	if err != nil {
		t.Error(err)
	}
	sg, err := ToSubGraph(gq)
	if err != nil {
		t.Error(err)
	}

	ch := make(chan error)
Manish R Jain's avatar
Manish R Jain committed
	go ProcessGraph(sg, ch, time.Minute)
Pawan Rawal's avatar
Pawan Rawal committed
	var l Latency
	gr, err := sg.ToProtocolBuffer(&l)
	if gr.Attribute != "_root_" {
		t.Errorf("Expected attribute _root_, Got: %v", gr.Attribute)
Pawan Rawal's avatar
Pawan Rawal committed
	if gr.Uid != 1 {
		t.Errorf("Expected uid 1, Got: %v", gr.Uid)
	if gr.Xid != "mich" {
		t.Errorf("Expected xid mich, Got: %v", gr.Xid)
Pawan Rawal's avatar
Pawan Rawal committed
	if len(gr.Properties) != 3 {
		t.Errorf("Expected values map to contain 3 properties, Got: %v",
Pawan Rawal's avatar
Pawan Rawal committed
			len(gr.Properties))
	if getProperty(gr.Properties, "name").Str != "Michonne" {
		t.Errorf("Expected property name to have value Michonne, Got: %v",
			getProperty(gr.Properties, "name").Str)
Pawan Rawal's avatar
Pawan Rawal committed
	if len(gr.Children) != 10 {
		t.Errorf("Expected 10 children, Got: %v", len(gr.Children))
Pawan Rawal's avatar
Pawan Rawal committed
	if child.Uid != 23 {
		t.Errorf("Expected uid 23, Got: %v", gr.Uid)
	}
	if child.Attribute != "friend" {
		t.Errorf("Expected attribute friend, Got: %v", child.Attribute)
Pawan Rawal's avatar
Pawan Rawal committed
	if len(child.Properties) != 1 {
		t.Errorf("Expected values map to contain 1 property, Got: %v",
Pawan Rawal's avatar
Pawan Rawal committed
			len(child.Properties))
	if getProperty(child.Properties, "name").Str != "Rick Grimes" {
		t.Errorf("Expected property name to have value Rick Grimes, Got: %v",
			getProperty(child.Properties, "name").Str)
Pawan Rawal's avatar
Pawan Rawal committed
	}
	if len(child.Children) != 0 {
		t.Errorf("Expected 0 children, Got: %v", len(child.Children))
	}
Pawan Rawal's avatar
Pawan Rawal committed
	child = gr.Children[5]
	if child.Uid != 23 {
		t.Errorf("Expected uid 23, Got: %v", gr.Uid)
	}
	if child.Attribute != "friend" {
		t.Errorf("Expected attribute friend, Got: %v", child.Attribute)
	}
	if len(child.Properties) != 0 {
		t.Errorf("Expected values map to contain 0 properties, Got: %v",
			len(child.Properties))
	if len(child.Children) != 0 {
		t.Errorf("Expected 0 children, Got: %v", len(child.Children))
Pawan Rawal's avatar
Pawan Rawal committed

func benchmarkToJson(file string, b *testing.B) {
	b.ReportAllocs()
	var sg SubGraph
	var l Latency

	f, err := ioutil.ReadFile(file)
	if err != nil {
		b.Error(err)
	}

	buf := bytes.NewBuffer(f)
	dec := gob.NewDecoder(buf)
	err = dec.Decode(&sg)
	if err != nil {
		b.Error(err)
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if _, err := sg.ToJson(&l); err != nil {
			b.Fatal(err)
		}
	}
}

func BenchmarkToJSON_10_Actor(b *testing.B)      { benchmarkToJson("benchmark/actors10.bin", b) }
func BenchmarkToJSON_10_Director(b *testing.B)   { benchmarkToJson("benchmark/directors10.bin", b) }
func BenchmarkToJSON_100_Actor(b *testing.B)     { benchmarkToJson("benchmark/actors100.bin", b) }
func BenchmarkToJSON_100_Director(b *testing.B)  { benchmarkToJson("benchmark/directors100.bin", b) }
func BenchmarkToJSON_1000_Actor(b *testing.B)    { benchmarkToJson("benchmark/actors1000.bin", b) }
func BenchmarkToJSON_1000_Director(b *testing.B) { benchmarkToJson("benchmark/directors1000.bin", b) }
Pawan Rawal's avatar
Pawan Rawal committed

func benchmarkToPB(file string, b *testing.B) {
Pawan Rawal's avatar
Pawan Rawal committed
	b.ReportAllocs()
	var sg SubGraph
	var l Latency

	f, err := ioutil.ReadFile(file)
	if err != nil {
		b.Error(err)
	}

	buf := bytes.NewBuffer(f)
	dec := gob.NewDecoder(buf)
	err = dec.Decode(&sg)
	if err != nil {
		b.Error(err)
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if _, err := sg.ToProtocolBuffer(&l); err != nil {
			b.Fatal(err)
		}
	}
}

func BenchmarkToPB_10_Actor(b *testing.B)      { benchmarkToPB("benchmark/actors10.bin", b) }
func BenchmarkToPB_10_Director(b *testing.B)   { benchmarkToPB("benchmark/directors10.bin", b) }
func BenchmarkToPB_100_Actor(b *testing.B)     { benchmarkToPB("benchmark/actors100.bin", b) }
func BenchmarkToPB_100_Director(b *testing.B)  { benchmarkToPB("benchmark/directors100.bin", b) }
func BenchmarkToPB_1000_Actor(b *testing.B)    { benchmarkToPB("benchmark/actors1000.bin", b) }
func BenchmarkToPB_1000_Director(b *testing.B) { benchmarkToPB("benchmark/directors1000.bin", b) }