package storage import ( "context" "fmt" "io/ioutil" "local/dndex/storage/entity" "local/dndex/storage/operator" "os" "strings" "testing" "time" "github.com/google/uuid" ) func TestIntegration(t *testing.T) { os.Args = os.Args[:1] f, err := ioutil.TempFile(os.TempDir(), "pattern*") if err != nil { t.Fatal(err) } f.Close() defer os.Remove(f.Name()) os.Setenv("DBURI", f.Name()) graph := NewRateLimitedGraph() ctx, can := context.WithCancel(context.TODO()) defer can() clean := func() { graph.g.driver.Delete(context.TODO(), "col", map[string]string{}) } clean() defer clean() ones := []entity.One{ randomOne(), randomOne(), randomOne(), } ones[0].Connections = map[string]entity.One{ones[2].Name: entity.One{Name: ones[2].Name, Relationship: ":("}} ones[1].Name = ones[0].Name[1 : len(ones[0].Name)-1] cleanFill := func() { clean() for i := range ones { if err := graph.g.driver.Insert(context.TODO(), "col", ones[i]); err != nil { t.Fatal(err) } } } t.Run("graph.Insert(...)", func(t *testing.T) { clean() for _, one := range ones { err := graph.Insert(ctx, "col", one) if err != nil { t.Fatal(err) } } }) t.Run("graph.List", func(t *testing.T) { cleanFill() all, err := graph.List(ctx, "col") if err != nil { t.Fatal(err) } t.Logf("\nall = %+v", all) if len(all) != 3 { t.Fatalf("%v: %+v", len(all), all) } }) t.Run("graph.ListCaseInsensitive", func(t *testing.T) { cleanFill() all, err := graph.ListCaseInsensitive(ctx, "col") if err != nil { t.Fatal(err) } t.Logf("\nall = %+v", all) if len(all) != 3 { t.Fatalf("%v: %+v", len(all), all) } }) t.Run("graph.List(foo => *)", func(t *testing.T) { cleanFill() some, err := graph.List(ctx, "col", ones[0].Peers()...) if err != nil { t.Fatal(err) } t.Logf("\nsom = %+v", some) if len(some) != 1 { t.Fatalf("%+v: %+v", len(some), some) } }) t.Run("graph.List(FOO => *)", func(t *testing.T) { cleanFill() peers := ones[0].Peers() for i := range peers { peers[i] = strings.ToUpper(peers[i]) } some, err := graph.List(ctx, "col", peers...) if err != nil { t.Fatal(err) } t.Logf("\nsom = %+v", some) if len(some) != 0 { t.Fatalf("%+v: %+v", len(some), some) } }) t.Run("graph.ListCaseInsensitive(FOO => *)", func(t *testing.T) { cleanFill() peers := ones[0].Peers() for i := range peers { peers[i] = strings.ToUpper(peers[i]) } some, err := graph.ListCaseInsensitive(ctx, "col", peers...) if err != nil { t.Fatal(err) } t.Logf("\nsom = %+v", some) if len(some) != 1 { t.Fatalf("%+v: %+v", len(some), some) } }) t.Run("graph.Delete(case insensitives() => 0)", func(t *testing.T) { cleanFill() err := graph.Delete(ctx, "col", operator.CaseInsensitives{Key: entity.Name, Values: []string{}}) if err != nil { t.Fatal(err) } ones, err := graph.List(ctx, "col") if err != nil { t.Fatal(err) } if len(ones) != 0 { t.Fatal(len(ones)) } }) t.Run("graph.Delete(case insensitives(.*) => 0)", func(t *testing.T) { cleanFill() err := graph.Delete(ctx, "col", operator.CaseInsensitives{Key: entity.Name, Values: []string{".*"}}) if err != nil { t.Fatal(err) } ones, err := graph.List(ctx, "col") if err != nil { t.Fatal(err) } if len(ones) < 0 { t.Fatal(len(ones)) } }) t.Run("graph.Delete(case insensitive(.*) => 0)", func(t *testing.T) { cleanFill() err := graph.Delete(ctx, "col", operator.CaseInsensitive{Key: entity.Name, Value: ".*"}) if err != nil { t.Fatal(err) } ones, err := graph.List(ctx, "col") if err != nil { t.Fatal(err) } if len(ones) < 0 { t.Fatal(len(ones)) } }) t.Run("graph.Search(foo => *)", func(t *testing.T) { cleanFill() some, err := graph.Search(ctx, "col", ones[0].Name[:3]) if err != nil { t.Fatal(err) } t.Logf("searching for %s (%s)\nsom = %+v", ones[0].Name, ones[0].Name[:3], some) if len(some) < 1 { t.Fatalf("%+v: %+v", len(some), some) } }) t.Run("graph.Update(foo, --bar)", func(t *testing.T) { cleanFill() err := graph.Update(ctx, "col", ones[0].Query(), operator.Set{entity.Connections, map[string]interface{}{}}) if err != nil { t.Fatal(err) } some, err := graph.List(ctx, "col", ones[0].Name) if err != nil { t.Fatal(err) } t.Logf("\nsm' = %+v", some) if len(some) != 1 { t.Fatal(len(some)) } if some[0].Name != ones[0].Name { t.Fatal(some[0].Name) } if l := len(some[0].Peers()); l > 0 { t.Fatalf("%d: %+v", l, some[0]) } }) t.Run("graph.Update(foo, +=2); graph.Update(foo, -=1)", func(t *testing.T) { cleanFill() err := graph.Update(ctx, "col", ones[0].Query(), operator.Set{entity.Connections, map[string]entity.One{ "hello": entity.One{Name: "hello", Relationship: ":("}, "world": entity.One{Name: "world", Relationship: ":("}, }}) if err != nil { t.Fatal(err) } some1, err := graph.List(ctx, "col", ones[0].Name) if err != nil { t.Fatal(err) } t.Logf("sm1 = %+v", some1[0]) if len(some1) != 1 { t.Fatal(len(some1)) } if len(some1[0].Peers()) != 2 { t.Fatal(some1[0].Peers()) } err = graph.Update(ctx, "col", ones[0].Query(), operator.Unset(fmt.Sprintf("%s.world", entity.Connections))) if err != nil { t.Fatal(err) } some2, err := graph.List(ctx, "col", ones[0].Name) if err != nil { t.Fatal(err) } t.Logf("sm2 = %+v", some2[0]) if len(some2) != 1 { t.Fatal(len(some2)) } if len(some2[0].Peers()) != 1 { t.Fatal(some2[0].Peers()) } }) t.Run("graph.Update(new attachment), Update(--new attachment)", func(t *testing.T) { cleanFill() err := graph.Update(ctx, "col", ones[0].Query(), operator.Set{Key: fmt.Sprintf("%s.new attachment", entity.Attachments), Value: "my new attachment"}) if err != nil { t.Fatal(err) } some1, err := graph.List(ctx, "col", ones[0].Name) if err != nil { t.Fatal(err) } t.Logf("sm1 = %+v", some1[0]) if len(some1) != 1 { t.Fatal(len(some1)) } if v, ok := some1[0].Attachments["new attachment"]; !ok { t.Fatal(ok, some1[0].Attachments) } else if v != "my new attachment" { t.Fatal(v, some1[0].Attachments) } err = graph.Update(ctx, "col", ones[0].Query(), operator.Unset(fmt.Sprintf("%s.new attachment", entity.Attachments))) if err != nil { t.Fatal(err) } some2, err := graph.List(ctx, "col", ones[0].Name) if err != nil { t.Fatal(err) } t.Logf("sm1 = %+v", some2[0]) if len(some2) != 1 { t.Fatal(len(some2)) } if _, ok := some2[0].Attachments["new attachment"]; ok { t.Fatal(ok, some2[0].Attachments) } else if len(some2[0].Attachments) == 0 { t.Fatal(len(some2[0].Attachments), some2[0].Attachments) } }) t.Run("graph.Insert Collision(...)", func(t *testing.T) { cleanFill() one := randomOne() err := graph.Insert(ctx, "col", one) if err != nil { t.Fatal(err) } one.Name = strings.ToUpper(one.Name) err = graph.Insert(ctx, "col", one) if err == nil { t.Fatal(err) } err = graph.Delete(ctx, "col", operator.CaseInsensitive{Key: entity.Name, Value: one.Name}) if err != nil { t.Fatal(err) } ones, err = graph.ListCaseInsensitive(ctx, "col", one.Name) if err != nil { t.Fatal(err) } if len(ones) > 0 { t.Fatal(err) } }) t.Run("graph.Insert Collision(...)", func(t *testing.T) { cleanFill() one := randomOne() err := graph.Insert(ctx, "col", one) if err != nil { t.Fatal(err) } err = graph.Insert(ctx, "col", one) if err == nil { t.Fatal(err) } err = graph.Delete(ctx, "col", operator.CaseInsensitive{Key: entity.Name, Value: one.Name}) if err != nil { t.Fatal(err) } ones, err = graph.ListCaseInsensitive(ctx, "col", one.Name) if err != nil { t.Fatal(err) } if len(ones) > 0 { t.Fatal(err) } }) t.Run("graph.Update connections when none previously", func(t *testing.T) { cleanFill() one := randomOne() one.Connections = nil err := graph.Insert(ctx, "col", one) if err != nil { t.Fatal(err) } err = graph.Update(ctx, "col", one.Query(), operator.Set{Key: entity.Connections + ".newfriend", Value: randomOne()}) if err != nil { t.Fatal(err) } ones, err = graph.ListCaseInsensitive(ctx, "col", one.Name) if err != nil { t.Fatal(err) } if len(ones) != 1 { t.Fatal(ones) } if len(ones[0].Connections) != 1 { t.Fatal(ones[0].Connections) } if _, ok := ones[0].Connections["newfriend"]; !ok { t.Fatal(ones[0].Connections) } }) } func randomOne() entity.One { return entity.One{ Name: "name-" + uuid.New().String()[:5], Type: "Humman", Title: "Biggus", Text: "tee hee xd", Modified: time.Now().UnixNano(), Connections: map[string]entity.One{}, Attachments: map[string]string{ "pdf file": "/path/to.pdf", "png file": "/path/to.png", }, } }