get.porter.sh/porter@v1.3.0/pkg/storage/grpc_test.go (about) 1 package storage 2 3 import ( 4 "context" 5 "net" 6 "testing" 7 "time" 8 9 "get.porter.sh/porter/pkg/portercontext" 10 "get.porter.sh/porter/pkg/storage/plugins" 11 "get.porter.sh/porter/pkg/storage/plugins/proto" 12 "get.porter.sh/porter/pkg/storage/plugins/testplugin" 13 "get.porter.sh/porter/pkg/storage/pluginstore" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 "go.mongodb.org/mongo-driver/bson" 17 "google.golang.org/grpc" 18 "google.golang.org/grpc/credentials/insecure" 19 ) 20 21 func TestRoundTripDataOverGRPC(t *testing.T) { 22 // Just check that we can round trip data through our storage grpc service 23 c := portercontext.NewTestContext(t) 24 store := testplugin.NewTestStoragePlugin(c) 25 ctx := context.Background() 26 27 server := pluginstore.NewServer(c.Context, store) 28 addr := "localhost:" 29 lis, err := net.Listen("tcp", addr) 30 require.NoError(t, err) 31 grpcServer := grpc.NewServer() 32 proto.RegisterStorageProtocolServer(grpcServer, server) 33 errs := make(chan error, 1) 34 go func() { 35 errs <- grpcServer.Serve(lis) 36 }() 37 defer func() { 38 grpcServer.Stop() 39 if err := <-errs; err != nil { 40 require.NoError(t, err) 41 } 42 }() 43 44 conn, err := grpc.NewClient(lis.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials())) 45 require.NoError(t, err) 46 defer conn.Close() 47 client := pluginstore.NewClient(proto.NewStorageProtocolClient(conn)) 48 49 // Add an index to support filtering 50 const collection = "things" 51 err = client.EnsureIndex(ctx, plugins.EnsureIndexOptions{Indices: []plugins.Index{ 52 {Collection: collection, Keys: bson.D{{Key: "namespace", Value: 1}, {Key: "name", Value: 1}}}, 53 }}) 54 require.NoError(t, err) 55 56 thing1 := bson.M{"name": "Thing1", "namespace": "dev"} 57 err = client.Insert(ctx, plugins.InsertOptions{ 58 Collection: collection, 59 Documents: []bson.M{ 60 thing1, 61 {"name": "Thing2", "namespace": "staging"}, 62 }, 63 }) 64 require.NoError(t, err) 65 66 results, err := client.Find(ctx, plugins.FindOptions{ 67 Collection: collection, 68 Filter: bson.M{"namespace": "dev"}, 69 Select: bson.D{{Key: "name", Value: 1}, {Key: "namespace", Value: 1}, {Key: "_id", Value: 0}}, 70 }) 71 require.NoError(t, err) 72 require.Len(t, results, 1) 73 74 var gotThing1 bson.M 75 require.NoError(t, bson.Unmarshal(results[0], &gotThing1)) 76 assert.Equal(t, thing1, gotThing1) 77 78 opts := plugins.EnsureIndexOptions{ 79 Indices: []plugins.Index{ 80 // query most recent outputs by run (porter installation run show, when we list outputs) 81 {Collection: CollectionOutputs, Keys: bson.D{{Key: "namespace", Value: 1}, {Key: "installation", Value: 1}, {Key: "-resultId", Value: 1}}}, 82 // query outputs by result (list) 83 {Collection: CollectionOutputs, Keys: bson.D{{Key: "resultId", Value: 1}, {Key: "name", Value: 1}}, Unique: true}, 84 // query most recent outputs by name for an installation 85 {Collection: CollectionOutputs, Keys: bson.D{{Key: "namespace", Value: 1}, {Key: "installation", Value: 1}, {Key: "name", Value: 1}, {Key: "-resultId", Value: 1}}}, 86 }, 87 } 88 89 err = client.EnsureIndex(ctx, opts) 90 require.NoError(t, err) 91 92 err = client.Insert(ctx, plugins.InsertOptions{ 93 Collection: CollectionOutputs, 94 Documents: []bson.M{{"namespace": "dev", "installation": "test", "name": "thing1", "resultId": "111"}, 95 {"namespace": "dev", "installation": "test", "name": "thing2", "resultId": "111"}, 96 {"namespace": "dev", "installation": "test", "name": "thing2", "resultId": "222"}, 97 }, 98 }) 99 require.NoError(t, err) 100 101 // Add a small delay to ensure all documents are properly indexed 102 time.Sleep(200 * time.Millisecond) 103 104 aggregateResults, err := client.Aggregate(ctx, plugins.AggregateOptions{ 105 Collection: CollectionOutputs, 106 Pipeline: []bson.D{ 107 // List outputs by installation 108 {{Key: "$match", Value: bson.M{ 109 "namespace": "dev", 110 "installation": "test", 111 }}}, 112 // Reverse sort them (newest on top) 113 {{Key: "$sort", Value: bson.D{ 114 {Key: "namespace", Value: 1}, 115 {Key: "installation", Value: 1}, 116 {Key: "name", Value: 1}, 117 {Key: "resultId", Value: -1}, 118 }}}, 119 // Group them by output name and select the last value for each output 120 {{Key: "$group", Value: bson.D{ 121 {Key: "_id", Value: "$name"}, 122 {Key: "lastOutput", Value: bson.M{"$first": "$$ROOT"}}, 123 }}}, 124 }, 125 }) 126 require.NoError(t, err) 127 require.Len(t, aggregateResults, 2) 128 // Find the thing2 output and verify it has the most recent resultId 129 for _, result := range aggregateResults { 130 if result.Lookup("_id").String() == "thing2" { 131 require.Contains(t, result.Lookup("lastOutput").String(), "222") 132 break 133 } 134 } 135 }