github.com/s7techlab/cckit@v0.10.5/gateway/chaincode_service_test.go (about)

     1  package gateway_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/gogo/protobuf/proto"
     8  	"github.com/golang/protobuf/jsonpb"
     9  	"github.com/golang/protobuf/ptypes/empty"
    10  	. "github.com/onsi/ginkgo"
    11  	. "github.com/onsi/gomega"
    12  
    13  	"github.com/s7techlab/cckit/convert"
    14  	cpservice "github.com/s7techlab/cckit/examples/cpaper_asservice"
    15  	"github.com/s7techlab/cckit/examples/cpaper_asservice/testdata"
    16  	"github.com/s7techlab/cckit/extensions/encryption"
    17  	enctest "github.com/s7techlab/cckit/extensions/encryption/testing"
    18  	"github.com/s7techlab/cckit/gateway"
    19  	idtestdata "github.com/s7techlab/cckit/identity/testdata"
    20  	testcc "github.com/s7techlab/cckit/testing"
    21  	"github.com/s7techlab/cckit/testing/gomega"
    22  )
    23  
    24  func TestService(t *testing.T) {
    25  	RegisterFailHandler(Fail)
    26  	RunSpecs(t, "Gateway suite")
    27  }
    28  
    29  const (
    30  	Channel       = `my_channel`
    31  	ChaincodeName = `commercial_paper`
    32  )
    33  
    34  var (
    35  	ctx = gateway.ContextWithSigner(
    36  		context.Background(),
    37  		idtestdata.Certificates[0].MustIdentity(idtestdata.DefaultMSP),
    38  	)
    39  )
    40  
    41  var _ = Describe(`Gateway`, func() {
    42  
    43  	Context(`Chaincode service without options`, func() {
    44  
    45  		var (
    46  			ccService         *gateway.ChaincodeService
    47  			ccInstanceService *gateway.ChaincodeInstanceService
    48  			cPaperGateway     *cpservice.CPaperServiceGateway
    49  			mockStub          *testcc.MockStub
    50  		)
    51  
    52  		It("Init", func() {
    53  			ccImpl, err := cpservice.NewCC()
    54  			Expect(err).NotTo(HaveOccurred())
    55  
    56  			mockStub = testcc.NewMockStub(ChaincodeName, ccImpl)
    57  			peer := testcc.NewPeer().WithChannel(Channel, mockStub)
    58  
    59  			ccService = gateway.NewChaincodeService(peer)
    60  			ccInstanceService = ccService.InstanceService(
    61  				&gateway.ChaincodeLocator{Channel: Channel, Chaincode: ChaincodeName},
    62  				gateway.WithEventResolver(cpservice.EventMappings))
    63  
    64  			// "sdk" for deal with cpaper chaincode
    65  			cPaperGateway = cpservice.NewCPaperServiceGateway(peer, Channel, ChaincodeName)
    66  		})
    67  
    68  		Context(`Direct calls`, func() {
    69  
    70  			It("Require  to provide chaincode locator", func() {
    71  				_, err := ccService.Query(ctx, &gateway.ChaincodeQueryRequest{
    72  					Input: &gateway.ChaincodeInput{
    73  						Args: [][]byte{[]byte(`List`), {}},
    74  					},
    75  				})
    76  
    77  				Expect(err).To(HaveOccurred())
    78  				Expect(err.Error()).To(ContainSubstring(`invalid field Locator: message must exist`))
    79  			})
    80  		})
    81  
    82  		Context(`Chaincode gateway`, func() {
    83  
    84  			It("Allow to get empty commercial paper list", func() {
    85  				pp, err := cPaperGateway.List(ctx, &empty.Empty{})
    86  				Expect(err).NotTo(HaveOccurred())
    87  				Expect(pp.Items).To(HaveLen(0))
    88  			})
    89  
    90  			It("Invoke chaincode with 'tx waiter' in context", func() {
    91  				ctx = gateway.ContextWithTxWaiter(ctx, "all")
    92  				_, err := cPaperGateway.Issue(ctx, testdata.Issue1)
    93  				Expect(err).NotTo(HaveOccurred())
    94  			})
    95  
    96  			It("Invoke chaincode with custom identity in context", func() {
    97  				signer := idtestdata.Certificates[1].MustIdentity(idtestdata.DefaultMSP)
    98  				ctx = gateway.ContextWithDefaultSigner(ctx, signer)
    99  
   100  				_, err := cPaperGateway.Delete(ctx, testdata.Id1)
   101  				Expect(err).NotTo(HaveOccurred())
   102  			})
   103  		})
   104  
   105  		Context(`Events`, func() {
   106  
   107  			It(`allow to get events as LIST  (by default from block 0 to current channel height) `, func(done Done) {
   108  				events, err := ccInstanceService.Events(ctx, &gateway.ChaincodeInstanceEventsRequest{})
   109  
   110  				Expect(err).NotTo(HaveOccurred())
   111  				Expect(events.Items).To(HaveLen(1)) // 1 event on issue
   112  
   113  				e := events.Items[0]
   114  				var (
   115  					eventObj  interface{}
   116  					eventJson string
   117  				)
   118  				eventObj, err = convert.FromBytes(e.Event.Payload, &cpservice.IssueCommercialPaper{})
   119  				Expect(err).NotTo(HaveOccurred())
   120  
   121  				eventJson, err = (&jsonpb.Marshaler{EmitDefaults: true, OrigName: true}).
   122  					MarshalToString(eventObj.(proto.Message))
   123  				Expect(err).NotTo(HaveOccurred())
   124  				Expect(e.Event.EventName).To(Equal(`IssueCommercialPaper`))
   125  				Expect(e.Payload).NotTo(BeNil())
   126  				Expect(e.Payload.Value).To(Equal([]byte(eventJson))) // check event resolving
   127  				close(done)
   128  			})
   129  
   130  			It(`allow to get 0 events as LIST from chaincode with incorrect event name filter`, func(done Done) {
   131  				events, err := ccInstanceService.Events(ctx, &gateway.ChaincodeInstanceEventsRequest{
   132  					EventName: []string{`________IssueCommercialPaper______`},
   133  				})
   134  
   135  				Expect(err).NotTo(HaveOccurred())
   136  				Expect(events.Items).To(HaveLen(0)) // 1 event on issue
   137  
   138  				close(done)
   139  			})
   140  
   141  			It(`allow to get events from block 0 to current channel height AS STREAM`, func(done Done) {
   142  				ctxWithCancel, cancel := context.WithCancel(ctx)
   143  				stream := gateway.NewChaincodeEventServerStream(ctxWithCancel)
   144  
   145  				go func() {
   146  					req := &gateway.ChaincodeEventsStreamRequest{
   147  						Locator: &gateway.ChaincodeLocator{
   148  							Channel:   Channel,
   149  							Chaincode: ChaincodeName,
   150  						},
   151  						FromBlock: &gateway.BlockLimit{Num: 0},
   152  						ToBlock:   &gateway.BlockLimit{Num: 0},
   153  					}
   154  
   155  					err := ccService.EventsStream(req, &gateway.ChaincodeEventsServer{ServerStream: stream})
   156  
   157  					Expect(err).NotTo(HaveOccurred())
   158  				}()
   159  
   160  				var e *gateway.ChaincodeEvent
   161  				err := stream.Recv(e)
   162  				Expect(err).NotTo(HaveOccurred())
   163  				cancel()
   164  				close(done)
   165  			}, 1)
   166  		})
   167  
   168  	})
   169  
   170  	Context(`Chaincode service with encrypted chaincode`, func() {
   171  
   172  		var (
   173  			ccService  *gateway.ChaincodeService
   174  			ccInstance *gateway.ChaincodeInstanceService
   175  
   176  			cPaperGateway                  *cpservice.CPaperServiceGateway
   177  			cPaperGatewayWithoutEncryption *cpservice.CPaperServiceGateway
   178  
   179  			encMockStub *enctest.MockStub
   180  
   181  			encryptOpts []gateway.Opt
   182  		)
   183  
   184  		It("Init", func() {
   185  			ccImpl, err := cpservice.NewCCEncrypted()
   186  			Expect(err).NotTo(HaveOccurred())
   187  
   188  			encMockStub = enctest.NewMockStub(testcc.NewMockStub(ChaincodeName, ccImpl))
   189  
   190  			encryptOpts = []gateway.Opt{
   191  				gateway.WithEncryption(encMockStub.EncKey),
   192  				// Event resolver should be AFTER encryption / decryption middleware
   193  				gateway.WithEventResolver(cpservice.EventMappings),
   194  			}
   195  
   196  			// "sdk" for deal with cpaper chaincode
   197  			peer := testcc.NewPeer().WithChannel(Channel, encMockStub.MockStub)
   198  			ccService = gateway.NewChaincodeService(peer)
   199  
   200  			locator := &gateway.ChaincodeLocator{
   201  				Channel:   Channel,
   202  				Chaincode: ChaincodeName,
   203  			}
   204  
   205  			ccInstance = ccService.InstanceService(locator, encryptOpts...)
   206  
   207  			cPaperGateway = cpservice.NewCPaperServiceGateway(peer, Channel, ChaincodeName, encryptOpts...)
   208  			cPaperGatewayWithoutEncryption = cpservice.NewCPaperServiceGateway(
   209  				peer, Channel, ChaincodeName,
   210  				gateway.WithEventResolver(cpservice.EventMappings))
   211  		})
   212  
   213  		Context(`Chaincode gateway`, func() {
   214  
   215  			It("Disallow to query chaincode without encryption data", func() {
   216  				_, err := cPaperGatewayWithoutEncryption.List(ctx, &empty.Empty{})
   217  				Expect(err).To(gomega.ErrorIs(encryption.ErrKeyNotDefinedInTransientMap))
   218  
   219  			})
   220  
   221  			It("Allow to get empty commercial paper list", func() {
   222  				pp, err := cPaperGateway.List(ctx, &empty.Empty{})
   223  				Expect(err).NotTo(HaveOccurred())
   224  				Expect(pp.Items).To(HaveLen(0))
   225  			})
   226  
   227  			It("Invoke chaincode", func() {
   228  				issued, err := cPaperGateway.Issue(ctx, testdata.Issue1)
   229  				Expect(err).NotTo(HaveOccurred())
   230  				Expect(issued.Issuer).To(Equal(testdata.Issue1.Issuer))
   231  			})
   232  
   233  			It("Query chaincode", func() {
   234  				issued, err := cPaperGateway.Get(ctx, testdata.Id1)
   235  				Expect(err).NotTo(HaveOccurred())
   236  				Expect(issued.Issuer).To(Equal(testdata.Issue1.Issuer))
   237  			})
   238  
   239  		})
   240  
   241  		Context(`Events`, func() {
   242  
   243  			It(`allow to get encrypted events as LIST  (by default from block 0 to current channel height) `, func(done Done) {
   244  				events, err := ccInstance.Events(ctx, &gateway.ChaincodeInstanceEventsRequest{})
   245  
   246  				Expect(err).NotTo(HaveOccurred())
   247  				Expect(events.Items).To(HaveLen(1)) // 1 event on issue
   248  
   249  				e := events.Items[0]
   250  				var (
   251  					eventObj  interface{}
   252  					eventJson string
   253  				)
   254  				eventObj, err = convert.FromBytes(e.Event.Payload, &cpservice.IssueCommercialPaper{})
   255  				Expect(err).NotTo(HaveOccurred())
   256  
   257  				eventJson, err = (&jsonpb.Marshaler{EmitDefaults: true, OrigName: true}).
   258  					MarshalToString(eventObj.(proto.Message))
   259  				Expect(err).NotTo(HaveOccurred())
   260  				Expect(e.Event.EventName).To(Equal(`IssueCommercialPaper`))
   261  
   262  				Expect(e.Payload.Value).To(Equal([]byte(eventJson))) // check event resolving
   263  				close(done)
   264  			})
   265  
   266  			It(`allow to get encrypted events from block 0 to current channel height AS STREAM`, func(done Done) {
   267  				ctxWithCancel, cancel := context.WithCancel(ctx)
   268  				stream := gateway.NewChaincodeEventServerStream(ctxWithCancel)
   269  
   270  				go func() {
   271  					req := &gateway.ChaincodeInstanceEventsStreamRequest{
   272  						FromBlock: &gateway.BlockLimit{Num: 0},
   273  						ToBlock:   &gateway.BlockLimit{Num: 0},
   274  					}
   275  
   276  					err := ccInstance.EventsStream(req, &gateway.ChaincodeEventsServer{ServerStream: stream})
   277  
   278  					Expect(err).NotTo(HaveOccurred())
   279  				}()
   280  
   281  				var e *gateway.ChaincodeEvent
   282  				err := stream.Recv(e)
   283  				Expect(err).NotTo(HaveOccurred())
   284  				cancel()
   285  				close(done)
   286  			}, 1)
   287  
   288  		})
   289  
   290  	})
   291  	Context(`Chaincode instance service`, func() {
   292  
   293  		var (
   294  			ccInstanceService *gateway.ChaincodeInstanceService
   295  		)
   296  
   297  		It("Init", func() {
   298  			ccImpl, err := cpservice.NewCC()
   299  			Expect(err).NotTo(HaveOccurred())
   300  
   301  			// peer imitation
   302  			peer := testcc.NewPeer().WithChannel(Channel, testcc.NewMockStub(ChaincodeName, ccImpl))
   303  			ccInstanceService = gateway.NewChaincodeInstanceService(peer, &gateway.ChaincodeLocator{
   304  				Channel:   Channel,
   305  				Chaincode: ChaincodeName,
   306  			})
   307  		})
   308  
   309  		Context(`Direct calls`, func() {
   310  
   311  			It("Allow to get empty commercial paper list", func() {
   312  				resp, err := ccInstanceService.Query(ctx, &gateway.ChaincodeInstanceQueryRequest{
   313  					Input: &gateway.ChaincodeInput{
   314  						Args: [][]byte{[]byte(`List`), {}},
   315  					},
   316  				})
   317  
   318  				Expect(err).NotTo(HaveOccurred())
   319  				cPaperList := testcc.MustProtoUnmarshal(resp.Payload, &cpservice.CommercialPaperList{}).(*cpservice.CommercialPaperList)
   320  				Expect(cPaperList.Items).To(HaveLen(0))
   321  			})
   322  
   323  			It("Invoke chaincode", func() {
   324  
   325  				_, err := ccInstanceService.Invoke(ctx, &gateway.ChaincodeInstanceInvokeRequest{
   326  					Input: &gateway.ChaincodeInput{
   327  						Args: [][]byte{[]byte(`Issue`), testcc.MustProtoMarshal(testdata.Issue1)},
   328  					}})
   329  				Expect(err).NotTo(HaveOccurred())
   330  			})
   331  
   332  		})
   333  
   334  		Context(`Events delivery`, func() {
   335  
   336  			//It(`allow to get events as LIST from chaincode instance service (by default from block 0 to current channel height) `, func(done Done) {
   337  			//	events, err := ccInstanceService.Events(ctx, &gateway.ChaincodeInstanceEventsRequest{
   338  			//		EventName: []string{`IssueCommercialPaper`},
   339  			//	})
   340  			//
   341  			//	Expect(err).NotTo(HaveOccurred())
   342  			//	Expect(events.Items).To(HaveLen(1)) // 1 event on issue
   343  			//
   344  			//	close(done)
   345  			//})
   346  
   347  			It(`allow to get events as chan from chaincode instance service (by default from block 0 to current channel height) `, func(done Done) {
   348  				events, closer, err := ccInstanceService.EventsChan(ctx, &gateway.ChaincodeInstanceEventsStreamRequest{
   349  					EventName: []string{`IssueCommercialPaper`},
   350  					FromBlock: &gateway.BlockLimit{Num: 0},
   351  				})
   352  
   353  				Expect(err).NotTo(HaveOccurred())
   354  
   355  				event := <-events
   356  				Expect(event.Event.EventName).To(Equal(`IssueCommercialPaper`))
   357  
   358  				_ = closer()
   359  				close(done)
   360  			})
   361  		})
   362  	})
   363  
   364  })