First integrational test!

This commit is contained in:
Dmitry 2022-12-23 20:43:06 +08:00 committed by Mikhail Iudin
parent 8afb4b5c1f
commit aa029ce71b
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0

View File

@ -3,14 +3,59 @@ package commands
import (
"context"
"fmt"
clientproto "github.com/anytypeio/go-anytype-infrastructure-experiments/client/debug/clientdebugrpc/clientdebugrpcproto"
clientproto "github.com/anytypeio/go-anytype-infrastructure-experiments/client/api/apiproto"
nodeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/node/api/apiproto"
"github.com/spf13/cobra"
"github.com/zeebo/errs"
"golang.org/x/exp/slices"
"math/rand"
"strings"
"sync"
"time"
)
type DebugClient struct {
name string
address string
}
func keepChecking(fn func() bool, finished chan bool) {
ticker := time.NewTicker(time.Second * 1)
go func() {
for {
select {
case <-ticker.C:
if fn() {
finished <- true
ticker.Stop()
return
}
}
}
}()
<-finished
}
func containsFunc[E comparable](s []E, f func(E) bool) bool {
return slices.IndexFunc(s, f) >= 0
}
func iterate(shouldStop func(iteration int) bool, wg *sync.WaitGroup, iterationCount int) {
ticker := time.NewTicker(time.Millisecond * 10)
defer wg.Done()
defer ticker.Stop()
for i := 0; i < iterationCount; i++ {
select {
case <-ticker.C:
if shouldStop(i) {
return
}
}
}
}
func (s *service) registerScripts() {
cmdAddTextMany := &cobra.Command{
Use: "add-text-many [text]",
@ -76,4 +121,233 @@ func (s *service) registerScripts() {
cmdAddTextMany.MarkFlagRequired("document")
cmdAddTextMany.MarkFlagRequired("clients")
s.scripts = append(s.scripts, cmdAddTextMany)
integration := &cobra.Command{
Use: "integration-tests",
Short: "integration-tests",
Args: cobra.RangeArgs(0, 0),
Run: func(cmd *cobra.Command, args []string) {
documentsCount, _ := cmd.Flags().GetInt("documents")
node1, node2, node3 :=
DebugClient{
name: "Node1",
address: s.peers["node1"],
},
DebugClient{
name: "Node2",
address: s.peers["node2"],
},
DebugClient{
name: "Node3",
address: s.peers["node3"],
}
nodes := []DebugClient{node1, node2, node3}
start := time.Now()
elapsedFunc := func() time.Duration { return time.Since(start) }
print := func(output string) {
fmt.Printf("%s | %s \n", output, elapsedFunc())
}
createSpace := func(client DebugClient) string {
space, err := s.client.CreateSpace(context.Background(), client.address, &clientproto.CreateSpaceRequest{})
if err != nil {
panic("can't create a space")
}
print(fmt.Sprintf("%s: Created a space with id %s", client.name, space.Id))
return space.Id
}
doesNodesContainDocument := func(docId string, spaceId string) map[string]bool {
var dictionary = map[string]bool{}
for _, node := range nodes {
resp, _ := s.node.TreeParams(context.Background(), node.address, &nodeproto.TreeParamsRequest{
SpaceId: spaceId,
DocumentId: docId,
})
dictionary[node.name] = resp.GetHeadIds() != nil
}
return dictionary
}
waitUntilLoadSpace := func(spaceId string, client DebugClient) bool {
print(fmt.Sprintf("%s: Trying to load space with id %s", client.name, spaceId))
_, err := s.client.LoadSpace(context.Background(), client.address, &clientproto.LoadSpaceRequest{spaceId})
if err != nil {
return false
}
print(fmt.Sprintf("%s: Did load space with id %s", client.name, spaceId))
return true
}
waitUntilSpaceExists := func(groupId string, client DebugClient) bool {
allSpaces, err := s.client.AllSpaces(context.Background(), client.address, &clientproto.AllSpacesRequest{})
if err != nil {
panic("can't retrieve all spaces")
}
print(fmt.Sprintf("%s: contains %s, %t", client, groupId, slices.Contains(allSpaces.SpaceIds, groupId)))
return slices.Contains(allSpaces.SpaceIds, groupId)
}
waitUntilDocumentExists := func(client DebugClient, spaceId string, documentId string) bool {
rs, _ := s.client.AllTrees(context.Background(), client.address, &clientproto.AllTreesRequest{SpaceId: spaceId})
contains := containsFunc(rs.Trees, func(c *clientproto.Tree) bool {
return c.Id == documentId
})
if !contains {
print(fmt.Sprintf("%s doesn't contain a document %s", client.name, documentId))
fmt.Println(doesNodesContainDocument(documentId, spaceId))
} else {
print(fmt.Sprintf("%s contains a document %s", client.name, documentId))
}
return contains
}
addTextFunc := func(iterationNumber int, client DebugClient, spaceId string, documentId string) bool {
randText := func(nonce int) string {
rand.Seed(time.Now().UnixNano())
buf := make([]byte, nonce*3)
rand.Read(buf)
return string(buf)
}
r, err := s.client.AddText(context.Background(), client.address, &clientproto.AddTextRequest{
SpaceId: spaceId,
DocumentId: documentId,
Text: randText(iterationNumber),
IsSnapshot: false,
})
if err != nil {
print(client.address + err.Error())
return true
} else {
print(fmt.Sprintf("%s: Did add text to document %s, head: %s, text: %d", client.name, r.DocumentId, r.HeadId, iterationNumber))
}
return false
}
createDocumentFunc := func(client DebugClient, spaceId string) string {
docResponse, err := s.client.CreateDocument(context.Background(), client.address, &clientproto.CreateDocumentRequest{SpaceId: spaceId})
if err != nil {
panic("can't create a document")
}
print(fmt.Sprintf("%s: Created a document in space %s with id %s", client.name, spaceId, docResponse.Id))
return docResponse.Id
}
_ = func(wg *sync.WaitGroup, client DebugClient, spaceId string, docId string) {
time.Sleep(2)
documentDeletion := func() bool {
print("Will remove document with id" + spaceId + "." + docId)
_, err := s.client.DeleteDocument(context.Background(), client.address, &clientproto.DeleteDocumentRequest{
SpaceId: spaceId,
DocumentId: docId,
})
return err == nil
}
var finita = make(chan bool)
go keepChecking(func() bool { return documentDeletion() }, finita)
wg.Done()
}
checkHeadsEqual := func(client1 DebugClient, client2 DebugClient, spaceId string, docId string) bool {
rs1, _ := s.client.TreeParams(context.Background(), client1.address, &clientproto.TreeParamsRequest{
SpaceId: spaceId,
DocumentId: docId,
})
rs2, _ := s.client.TreeParams(context.Background(), client2.address, &clientproto.TreeParamsRequest{
SpaceId: spaceId,
DocumentId: docId,
})
print(fmt.Sprintf("%s document %s head is %v", client1.name, docId, rs1.GetHeadIds()))
print(fmt.Sprintf("%s document %s head is %v", client2.name, docId, rs2.GetHeadIds()))
if rs1.GetHeadIds() == nil || rs1.GetHeadIds() == nil {
print("Some head is nil")
return false
}
return slices.Equal(rs1.GetHeadIds(), rs2.GetHeadIds())
}
client1, client2 := DebugClient{
name: "Client1",
address: s.peers["client1"],
}, DebugClient{
name: "Client2",
address: s.peers["client2"],
}
singleTest := func(testGroup *sync.WaitGroup, spaceId string) {
wg := sync.WaitGroup{}
finished := make(chan bool)
documentId := createDocumentFunc(client2, spaceId)
keepChecking(func() bool { return waitUntilDocumentExists(client1, spaceId, documentId) }, finished)
wg.Add(2)
go iterate(func(iteration int) bool {
return addTextFunc(iteration, client2, spaceId, documentId)
}, &wg, 70)
go iterate(func(iteration int) bool {
return addTextFunc(iteration, client1, spaceId, documentId)
}, &wg, 100)
wg.Wait()
keepChecking(func() bool { return checkHeadsEqual(client1, client2, spaceId, documentId) }, finished)
print("The End")
testGroup.Done()
}
// Start
finished := make(chan bool)
spaceId := createSpace(client1)
keepChecking(func() bool { return waitUntilLoadSpace(spaceId, client2) }, finished)
keepChecking(func() bool { return waitUntilSpaceExists(spaceId, client2) }, finished)
wg := sync.WaitGroup{}
wg.Add(documentsCount)
for i := 0; i < documentsCount; i++ {
go singleTest(&wg, spaceId)
}
wg.Wait()
print("Directed by robert b weide")
},
}
integration.Flags().Int("documents", 50, "how many documents would be created")
s.scripts = append(s.scripts, integration)
}