261 lines
7.4 KiB
Go
261 lines
7.4 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package container_test
|
|
|
|
import (
|
|
"bytes"
|
|
"io/ioutil"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
|
|
"github.com/hyperledger/fabric/core/chaincode/persistence"
|
|
"github.com/hyperledger/fabric/core/container"
|
|
"github.com/hyperledger/fabric/core/container/ccintf"
|
|
"github.com/hyperledger/fabric/core/container/mock"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
var _ = Describe("Router", func() {
|
|
var (
|
|
fakeDockerBuilder *mock.DockerBuilder
|
|
fakeExternalBuilder *mock.ExternalBuilder
|
|
fakePackageProvider *mock.PackageProvider
|
|
fakeInstance *mock.Instance
|
|
router *container.Router
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
fakeDockerBuilder = &mock.DockerBuilder{}
|
|
fakeExternalBuilder = &mock.ExternalBuilder{}
|
|
fakeInstance = &mock.Instance{}
|
|
fakePackageProvider = &mock.PackageProvider{}
|
|
fakePackageProvider.GetChaincodePackageReturns(
|
|
&persistence.ChaincodePackageMetadata{
|
|
Type: "package-type",
|
|
Path: "package-path",
|
|
},
|
|
[]byte(`{"some":"json"}`),
|
|
ioutil.NopCloser(bytes.NewBuffer([]byte("code-bytes"))),
|
|
nil,
|
|
)
|
|
|
|
router = &container.Router{
|
|
DockerBuilder: fakeDockerBuilder,
|
|
ExternalBuilder: fakeExternalBuilder,
|
|
PackageProvider: fakePackageProvider,
|
|
}
|
|
})
|
|
|
|
Describe("Build", func() {
|
|
BeforeEach(func() {
|
|
fakeExternalBuilder.BuildReturns(fakeInstance, nil)
|
|
})
|
|
|
|
It("calls the external builder with the correct args", func() {
|
|
err := router.Build("package-id")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(fakeExternalBuilder.BuildCallCount()).To(Equal(1))
|
|
ccid, md, codeStream := fakeExternalBuilder.BuildArgsForCall(0)
|
|
Expect(ccid).To(Equal("package-id"))
|
|
Expect(md).To(Equal([]byte(`{"some":"json"}`)))
|
|
codePackage, err := ioutil.ReadAll(codeStream)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(codePackage).To(Equal([]byte("code-bytes")))
|
|
})
|
|
|
|
Context("when the package provider returns an error before calling the external builder", func() {
|
|
BeforeEach(func() {
|
|
fakePackageProvider.GetChaincodePackageReturns(nil, nil, nil, errors.New("fake-package-error"))
|
|
})
|
|
|
|
It("wraps and returns the error", func() {
|
|
err := router.Build("package-id")
|
|
Expect(err).To(MatchError("failed to get chaincode package for external build: fake-package-error"))
|
|
})
|
|
|
|
It("does not call the external builder", func() {
|
|
router.Build("package-id")
|
|
Expect(fakeExternalBuilder.BuildCallCount()).To(Equal(0))
|
|
})
|
|
})
|
|
|
|
Context("when the external builder returns an error", func() {
|
|
BeforeEach(func() {
|
|
fakeExternalBuilder.BuildReturns(nil, errors.New("fake-external-error"))
|
|
fakeDockerBuilder.BuildReturns(fakeInstance, nil)
|
|
})
|
|
|
|
It("wraps and returns the error", func() {
|
|
err := router.Build("package-id")
|
|
Expect(err).To(MatchError("external builder failed: fake-external-error"))
|
|
})
|
|
})
|
|
|
|
Context("when the external builder returns successfully with an instance", func() {
|
|
It("does not call the docker builder", func() {
|
|
err := router.Build("package-id")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(fakeExternalBuilder.BuildCallCount()).To(Equal(1))
|
|
Expect(fakeDockerBuilder.BuildCallCount()).To(Equal(0))
|
|
})
|
|
})
|
|
|
|
Context("when the external builder returns a nil instance", func() {
|
|
BeforeEach(func() {
|
|
fakeExternalBuilder.BuildReturns(nil, nil)
|
|
fakeDockerBuilder.BuildReturns(fakeInstance, nil)
|
|
})
|
|
|
|
It("falls back to the docker impl", func() {
|
|
err := router.Build("package-id")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(fakeDockerBuilder.BuildCallCount()).To(Equal(1))
|
|
ccid, md, codeStream := fakeDockerBuilder.BuildArgsForCall(0)
|
|
Expect(ccid).To(Equal("package-id"))
|
|
Expect(md).To(Equal(&persistence.ChaincodePackageMetadata{
|
|
Type: "package-type",
|
|
Path: "package-path",
|
|
}))
|
|
codePackage, err := ioutil.ReadAll(codeStream)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(codePackage).To(Equal([]byte("code-bytes")))
|
|
})
|
|
|
|
Context("when the docker vm builder is nil", func() {
|
|
BeforeEach(func() {
|
|
router.DockerBuilder = nil
|
|
})
|
|
|
|
It("returns the error", func() {
|
|
err := router.Build("package-id")
|
|
Expect(err).To(MatchError("no DockerBuilder, cannot build"))
|
|
})
|
|
})
|
|
|
|
Context("when the package provider returns an error before calling the docker builder", func() {
|
|
BeforeEach(func() {
|
|
fakePackageProvider.GetChaincodePackageReturnsOnCall(1, nil, nil, nil, errors.New("fake-package-error"))
|
|
})
|
|
|
|
It("wraps and returns the error", func() {
|
|
err := router.Build("package-id")
|
|
Expect(err).To(MatchError("failed to get chaincode package for docker build: fake-package-error"))
|
|
})
|
|
})
|
|
})
|
|
|
|
Context("when an external builder is not provided", func() {
|
|
BeforeEach(func() {
|
|
router.ExternalBuilder = nil
|
|
fakeDockerBuilder.BuildReturns(fakeInstance, nil)
|
|
})
|
|
|
|
It("uses the docker vm builder", func() {
|
|
err := router.Build("package-id")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(fakeDockerBuilder.BuildCallCount()).To(Equal(1))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Post-build operations", func() {
|
|
BeforeEach(func() {
|
|
fakeExternalBuilder.BuildReturns(fakeInstance, nil)
|
|
err := router.Build("fake-id")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
|
|
Describe("Start", func() {
|
|
BeforeEach(func() {
|
|
fakeInstance.StartReturns(errors.New("fake-start-error"))
|
|
})
|
|
|
|
It("passes through to the docker impl", func() {
|
|
err := router.Start(
|
|
"fake-id",
|
|
&ccintf.PeerConnection{
|
|
Address: "peer-address",
|
|
TLSConfig: &ccintf.TLSConfig{
|
|
ClientKey: []byte("key"),
|
|
ClientCert: []byte("cert"),
|
|
RootCert: []byte("root"),
|
|
},
|
|
},
|
|
)
|
|
|
|
Expect(err).To(MatchError("fake-start-error"))
|
|
Expect(fakeInstance.StartCallCount()).To(Equal(1))
|
|
Expect(fakeInstance.StartArgsForCall(0)).To(Equal(&ccintf.PeerConnection{
|
|
Address: "peer-address",
|
|
TLSConfig: &ccintf.TLSConfig{
|
|
ClientKey: []byte("key"),
|
|
ClientCert: []byte("cert"),
|
|
RootCert: []byte("root"),
|
|
},
|
|
}))
|
|
})
|
|
|
|
Context("when the chaincode has not yet been built", func() {
|
|
It("returns an error", func() {
|
|
err := router.Start(
|
|
"missing-name",
|
|
&ccintf.PeerConnection{
|
|
Address: "peer-address",
|
|
},
|
|
)
|
|
Expect(err).To(MatchError("instance has not yet been built, cannot be started"))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Stop", func() {
|
|
BeforeEach(func() {
|
|
fakeInstance.StopReturns(errors.New("Boo"))
|
|
})
|
|
|
|
It("passes through to the docker impl", func() {
|
|
err := router.Stop("fake-id")
|
|
Expect(err).To(MatchError("Boo"))
|
|
Expect(fakeInstance.StopCallCount()).To(Equal(1))
|
|
})
|
|
|
|
Context("when the chaincode has not yet been built", func() {
|
|
It("returns an error", func() {
|
|
err := router.Stop("missing-name")
|
|
Expect(err).To(MatchError("instance has not yet been built, cannot be stopped"))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Wait", func() {
|
|
BeforeEach(func() {
|
|
fakeInstance.WaitReturns(7, errors.New("fake-wait-error"))
|
|
})
|
|
|
|
It("passes through to the docker impl", func() {
|
|
res, err := router.Wait(
|
|
"fake-id",
|
|
)
|
|
Expect(res).To(Equal(7))
|
|
Expect(err).To(MatchError("fake-wait-error"))
|
|
Expect(fakeInstance.WaitCallCount()).To(Equal(1))
|
|
})
|
|
|
|
Context("when the chaincode has not yet been built", func() {
|
|
It("returns an error", func() {
|
|
_, err := router.Wait("missing-name")
|
|
Expect(err).To(MatchError("instance has not yet been built, cannot wait"))
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|