From 737ff8857b1975958a065fdeaeca3c58bd4b28b4 Mon Sep 17 00:00:00 2001 From: Sergey Date: Mon, 28 Nov 2022 15:12:11 +0500 Subject: [PATCH] GO-511 Smoke test --- .dockerignore | 1 + Dockerfile | 26 +++++---- docker-compose.yml | 79 ++----------------------- test/basic_test.go | 141 +++++++++++++++++++++++++++++++++++++++++++++ test/events.go | 64 ++++++++++++++++++++ 5 files changed, 227 insertions(+), 84 deletions(-) create mode 100644 .dockerignore create mode 100644 test/basic_test.go create mode 100644 test/events.go diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..1d1fe94df --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +Dockerfile \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index a90450b77..5d3e9a652 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,27 @@ -FROM golang:1.16-buster AS builder +FROM golang:1.18 AS builder MAINTAINER Anytype # This is (in large part) copied (with love) from # https://hub.docker.com/r/ipfs/go-ipfs/dockerfile -ENV SRC_DIR /anytype -ENV BUILD_DIR /tmp +WORKDIR /anytype # Download packages first so they can be cached. -COPY go.mod go.sum $SRC_DIR/ -RUN cd $SRC_DIR \ - && go mod download +COPY go.mod go.sum / +RUN go mod download -COPY . $SRC_DIR +COPY . . # Install the binary -RUN cd $SRC_DIR \ - && go build -v -o $BUILD_DIR/server ./cmd/grpcserver/grpc.go +RUN go build -o server ./cmd/grpcserver/grpc.go -ENTRYPOINT ["/tmp/server"] +FROM ubuntu + +# TODO: more fine-grained dependencies +RUN apt update && apt install -y curl +COPY --from=builder /anytype/server . +EXPOSE 31007 +EXPOSE 31008 +ENV ANYTYPE_GRPC_ADDR=:31007 +ENV ANYTYPE_GRPCWEB_ADDR=:31008 +CMD ["./server"] diff --git a/docker-compose.yml b/docker-compose.yml index edc700875..3d0ec76b6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,77 +1,8 @@ -version: "3" +version: "3.9" services: test: - container_name: test - image: docker.pkg.github.com/anytypeio/python-anytype-testing/tests:latest - volumes: - - ./allure-results:/app/allure-results - - shared-temp:/tmp/shared - links: - - middleware-node-a - - middleware-node-b - - middleware-node-base - environment: - TEST_MIDDLEWARE_NODE_A_ADDRESS_HOST: middleware-node-a - TEST_MIDDLEWARE_NODE_A_ADDRESS_PORT: 31007 - TEST_MIDDLEWARE_NODE_A_ADDRESS_GATEWAY_PORT: 32007 - TEST_MIDDLEWARE_NODE_B_ADDRESS_HOST: middleware-node-b - TEST_MIDDLEWARE_NODE_B_ADDRESS_PORT: 41007 - TEST_MIDDLEWARE_NODE_B_ADDRESS_GATEWAY_PORT: 42007 - TEST_MIDDLEWARE_NODE_BASE_ADDRESS_HOST: middleware-node-base - TEST_MIDDLEWARE_NODE_BASE_ADDRESS_PORT: 51007 - TEST_MIDDLEWARE_NODE_BASE_ADDRESS_GATEWAY_PORT: 52007 - command: bash -c "make test" - - middleware-node-a: - stop_grace_period: 1s - stop_signal: SIGABRT - image: docker.pkg.github.com/anytypeio/go-anytype-middleware/server:${TAG} - environment: - ANYTYPE_GRPC_ADDR: "0.0.0.0:31007" - ANYTYPE_GATEWAY_ADDR: "0.0.0.0:32007" - ANYTYPE_LOG_LEVEL: "anytype-mw-app=DEBUG;grpc=DEBUG;anytype-gateway=DEBUG" - ANYTYPE_LOG_NOGELF: 1 - ANYTYPE_GRPC_LOG: 3 - # local tracing - #ANYTYPE_GRPC_TRACE: 3 - #JAEGER_AGENT_HOST: "docker.for.mac.localhost" - #JAEGER_SERVICE_NAME: "mw-a" - volumes: - - shared-temp:/tmp/shared - middleware-node-b: - stop_grace_period: 1s - stop_signal: SIGABRT - image: docker.pkg.github.com/anytypeio/go-anytype-middleware/server:${TAG} - environment: - ANYTYPE_GRPC_ADDR: "0.0.0.0:41007" - ANYTYPE_GATEWAY_ADDR: "0.0.0.0:42007" - ANYTYPE_LOG_LEVEL: "anytype-mw-app=DEBUG;grpc=DEBUG;anytype-gateway=DEBUG" - ANYTYPE_LOG_NOGELF: 1 - ANYTYPE_GRPC_LOG: 3 - # local tracing - #ANYTYPE_GRPC_TRACE: 3 - #JAEGER_AGENT_HOST: "docker.for.mac.localhost" - #JAEGER_SERVICE_NAME: "mw-b" - #JAEGER_SERVICE_NAME: "mw-b" - volumes: - - shared-temp:/tmp/shared - middleware-node-base: - stop_grace_period: 1s - stop_signal: SIGABRT - image: docker.pkg.github.com/anytypeio/go-anytype-middleware/server:${BASE_TAG} - environment: - ANYTYPE_GRPC_ADDR: "0.0.0.0:51007" - ANYTYPE_GATEWAY_ADDR: "0.0.0.0:52007" - ANYTYPE_LOG_LEVEL: "anytype-mw-app=DEBUG;grpc=DEBUG;anytype-gateway=DEBUG" - ANYTYPE_LOG_NOGELF: 1 - ANYTYPE_GRPC_LOG: 3 - # local tracing - #ANYTYPE_GRPC_TRACE: 3 - #JAEGER_AGENT_HOST: "docker.for.mac.localhost" - #JAEGER_SERVICE_NAME: "mw-b" - #JAEGER_SERVICE_NAME: "mw-b" - volumes: - - shared-temp:/tmp/shared -volumes: - shared-temp: \ No newline at end of file + build: . + ports: + - "31007:31007" + - "31008:31008" \ No newline at end of file diff --git a/test/basic_test.go b/test/basic_test.go new file mode 100644 index 000000000..914e47cb0 --- /dev/null +++ b/test/basic_test.go @@ -0,0 +1,141 @@ +package test + +import ( + "context" + "encoding/json" + "os" + "testing" + + "github.com/anytypeio/go-anytype-middleware/pb" + "github.com/anytypeio/go-anytype-middleware/pb/service" + "github.com/anytypeio/go-anytype-middleware/pkg/lib/bundle" + "github.com/anytypeio/go-anytype-middleware/pkg/lib/pb/model" + "github.com/anytypeio/go-anytype-middleware/util/pbtypes" + "github.com/gogo/protobuf/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/metadata" +) + +func TestBasic(t *testing.T) { + conn, err := grpc.Dial("127.0.0.1:31007", grpc.WithBlock(), grpc.WithTransportCredentials(insecure.NewCredentials())) + require.NoError(t, err) + + c := service.NewClientCommandsClient(conn) + + const mnemonic = "lamp crane identify video setup cactus hat icon guard develop alert solar" + const rootPath = "/var/anytype" + ctx := context.Background() + + t.Run("WalletRecover", func(t *testing.T) { + resp, err := c.WalletRecover(ctx, &pb.RpcWalletRecoverRequest{ + Mnemonic: mnemonic, + RootPath: rootPath, + }) + assert.NoError(t, json.NewEncoder(os.Stdout).Encode(resp)) + require.NoError(t, err) + }) + + var tok string + t.Run("WalletCreateSession", func(t *testing.T) { + resp, err := c.WalletCreateSession(ctx, &pb.RpcWalletCreateSessionRequest{ + Mnemonic: mnemonic, + }) + require.NoError(t, err) + tok = resp.Token + }) + + ctx = metadata.AppendToOutgoingContext(ctx, "token", tok) + + stream, err := c.ListenSessionEvents(ctx, &pb.StreamRequest{Token: tok}) + require.NoError(t, err) + + er := startEventReceiver(ctx, stream) + + t.Run("AccountRecover", func(t *testing.T) { + resp, err := c.AccountRecover(ctx, &pb.RpcAccountRecoverRequest{}) + require.NoError(t, err) + + assert.NoError(t, json.NewEncoder(os.Stdout).Encode(resp)) + }) + + t.Run("AccountSelect", func(t *testing.T) { + var id string + // TODO: log waiting for event? + waitEvent(er, func(a *pb.EventMessageValueOfAccountShow) { + id = a.AccountShow.Account.Id + }) + + resp, err := c.AccountSelect(ctx, &pb.RpcAccountSelectRequest{ + Id: id, + }) + require.NoError(t, err) + + assert.NoError(t, json.NewEncoder(os.Stdout).Encode(resp)) + }) + + t.Run("ObjectSearch", func(t *testing.T) { + resp, err := c.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ + Keys: []string{"id", "type", "name"}, + }) + require.NoError(t, err) + require.NotEmpty(t, resp.Records) + }) + + t.Run("ObjectSearchSubscribe", func(t *testing.T) { + resp, err := c.ObjectSearchSubscribe(ctx, &pb.RpcObjectSearchSubscribeRequest{ + SubId: "recent", + Filters: []*model.BlockContentDataviewFilter{ + { + RelationKey: bundle.RelationKeyLastOpenedDate.String(), + Condition: model.BlockContentDataviewFilter_Greater, + }, + }, + Keys: []string{"id", "lastOpenedDate"}, + }) + require.NoError(t, err) + require.NotEmpty(t, resp.Records) + }) + + var objId string + t.Run("BlockLinkCreateWithObject", func(t *testing.T) { + resp, err := c.BlockLinkCreateWithObject(ctx, &pb.RpcBlockLinkCreateWithObjectRequest{ + InternalFlags: []*model.InternalFlag{ + { + Value: model.InternalFlag_editorDeleteEmpty, + }, + { + Value: model.InternalFlag_editorSelectType, + }, + }, + Details: &types.Struct{ + Fields: map[string]*types.Value{ + bundle.RelationKeyType.String(): pbtypes.String(bundle.TypeKeyNote.URL()), + }, + }, + }) + + require.NoError(t, err) + require.NotEmpty(t, resp.TargetId) + objId = resp.TargetId + }) + + t.Run("ObjectOpen", func(t *testing.T) { + resp, err := c.ObjectOpen(ctx, &pb.RpcObjectOpenRequest{ + ObjectId: objId, + }) + + require.NoError(t, err) + require.NotNil(t, resp.ObjectView) + + waitEvent(er, func(sa *pb.EventMessageValueOfSubscriptionAdd) { + require.Equal(t, sa.SubscriptionAdd.Id, objId) + }) + waitEvent(er, func(sa *pb.EventMessageValueOfObjectDetailsSet) { + require.Equal(t, sa.ObjectDetailsSet.Id, objId) + require.Contains(t, sa.ObjectDetailsSet.Details.Fields, bundle.RelationKeyLastOpenedDate.String()) + }) + }) +} diff --git a/test/events.go b/test/events.go new file mode 100644 index 000000000..9135424a4 --- /dev/null +++ b/test/events.go @@ -0,0 +1,64 @@ +package test + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/anytypeio/go-anytype-middleware/pb" + "github.com/anytypeio/go-anytype-middleware/pb/service" +) + +type eventReceiver struct { + lock *sync.Mutex + events []*pb.EventMessage + // events chan<- *pb.EventMessage +} + +func startEventReceiver(ctx context.Context, c service.ClientCommands_ListenSessionEventsClient) *eventReceiver { + er := &eventReceiver{ + lock: &sync.Mutex{}, + } + go func() { + for { + select { + case <-ctx.Done(): + return + default: + ev, err := c.Recv() + if err != nil { + fmt.Println("receive error:", err) + continue + } + er.lock.Lock() + for _, m := range ev.Messages { + er.events = append(er.events, m) + } + er.lock.Unlock() + } + } + }() + return er +} + +func waitEvent[t pb.IsEventMessageValue](er *eventReceiver, fn func(x t)) { + for { + er.lock.Lock() + for i := len(er.events) - 1; i >= 0; i-- { + m := er.events[i] + if m == nil { + continue + } + if v, ok := m.Value.(t); ok { + fn(v) + er.events[i] = nil + er.lock.Unlock() + return + } + } + er.lock.Unlock() + + time.Sleep(10 * time.Millisecond) + } +}