From 1fdaa1f6cf634513ed4b189874783e66accb31a0 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Fri, 20 Dec 2024 19:30:38 +0000 Subject: [PATCH] [WIP] Improve integration tests Use github.com/rogpeppe/go-internal/testscript and github.com/kubernetes-sigs/e2e-framework to test the builder run command with a kind kubernetes cluster New integration tests should now be easier to add, e.g. for #228 Signed-off-by: James Taylor --- .github/workflows/go.yml | 1 - cmd/build.go | 56 +++++ cmd/build/main.go | 42 +--- cmd/detect.go | 54 +++++ cmd/detect/main.go | 41 +--- cmd/release.go | 50 ++++ cmd/release/main.go | 36 +-- cmd/run.go | 97 ++++++++ cmd/run/main.go | 80 +------ cmd/run/main_test.go | 71 ------ cmd/run/run_suite_test.go | 48 +--- go.mod | 21 +- go.sum | 46 +++- test/integration/integration_test.go | 63 +++++ test/integration/main_test.go | 99 ++++++++ .../testdata/chaincode_service_account.txtar | 32 +++ test/integration/testdata/run_chaincode.txtar | 62 +++++ test/testscript_helpers.go | 225 ++++++++++++++++++ 18 files changed, 812 insertions(+), 312 deletions(-) create mode 100644 cmd/build.go create mode 100644 cmd/detect.go create mode 100644 cmd/release.go create mode 100644 cmd/run.go create mode 100644 test/integration/integration_test.go create mode 100644 test/integration/main_test.go create mode 100644 test/integration/testdata/chaincode_service_account.txtar create mode 100644 test/integration/testdata/run_chaincode.txtar create mode 100644 test/testscript_helpers.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index ddffcff..308e8dd 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -44,7 +44,6 @@ jobs: run: go test -v ./... env: FABRIC_K8S_BUILDER_DEBUG: 'true' - INCLUDE_KIND_TESTS: ${{ matrix.os == 'ubuntu-latest' && 'true' || 'false' }} - name: Package run: | diff --git a/cmd/build.go b/cmd/build.go new file mode 100644 index 0000000..642850c --- /dev/null +++ b/cmd/build.go @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: Apache-2.0 + +package cmd + +import ( + "context" + "os" + "strconv" + + "github.com/hyperledger-labs/fabric-builder-k8s/internal/builder" + "github.com/hyperledger-labs/fabric-builder-k8s/internal/log" + "github.com/hyperledger-labs/fabric-builder-k8s/internal/util" +) + +func Build() int { + const ( + expectedArgsLength = 4 + chaincodeSourceDirectoryArg = 1 + chaincodeMetadataDirectoryArg = 2 + buildOutputDirectoryArg = 3 + ) + + debug, _ := strconv.ParseBool(util.GetOptionalEnv(util.DebugVariable, "false")) + ctx := log.NewCmdContext(context.Background(), debug) + logger := log.New(ctx) + + if len(os.Args) != expectedArgsLength { + logger.Println( + "Expected CHAINCODE_SOURCE_DIR, CHAINCODE_METADATA_DIR and BUILD_OUTPUT_DIR arguments", + ) + + return 1 + } + + chaincodeSourceDirectory := os.Args[chaincodeSourceDirectoryArg] + chaincodeMetadataDirectory := os.Args[chaincodeMetadataDirectoryArg] + buildOutputDirectory := os.Args[buildOutputDirectoryArg] + + logger.Debugf("Chaincode source directory: %s", chaincodeSourceDirectory) + logger.Debugf("Chaincode metadata directory: %s", chaincodeMetadataDirectory) + logger.Debugf("Build output directory: %s", buildOutputDirectory) + + build := &builder.Build{ + ChaincodeSourceDirectory: chaincodeSourceDirectory, + ChaincodeMetadataDirectory: chaincodeMetadataDirectory, + BuildOutputDirectory: buildOutputDirectory, + } + + if err := build.Run(ctx); err != nil { + logger.Printf("Error building chaincode: %+v", err) + + return 1 + } + + return 0 +} diff --git a/cmd/build/main.go b/cmd/build/main.go index 6cb8c59..fb8a1f8 100644 --- a/cmd/build/main.go +++ b/cmd/build/main.go @@ -3,49 +3,11 @@ package main import ( - "context" "os" - "github.com/hyperledger-labs/fabric-builder-k8s/internal/builder" - "github.com/hyperledger-labs/fabric-builder-k8s/internal/log" - "github.com/hyperledger-labs/fabric-builder-k8s/internal/util" -) - -const ( - expectedArgsLength = 4 - chaincodeSourceDirectoryArg = 1 - chaincodeMetadataDirectoryArg = 2 - buildOutputDirectoryArg = 3 + "github.com/hyperledger-labs/fabric-builder-k8s/cmd" ) func main() { - debug := util.GetOptionalEnv(util.DebugVariable, "false") - ctx := log.NewCmdContext(context.Background(), debug == "true") - logger := log.New(ctx) - - if len(os.Args) != expectedArgsLength { - logger.Println( - "Expected CHAINCODE_SOURCE_DIR, CHAINCODE_METADATA_DIR and BUILD_OUTPUT_DIR arguments", - ) - os.Exit(1) - } - - chaincodeSourceDirectory := os.Args[chaincodeSourceDirectoryArg] - chaincodeMetadataDirectory := os.Args[chaincodeMetadataDirectoryArg] - buildOutputDirectory := os.Args[buildOutputDirectoryArg] - - logger.Debugf("Chaincode source directory: %s", chaincodeSourceDirectory) - logger.Debugf("Chaincode metadata directory: %s", chaincodeMetadataDirectory) - logger.Debugf("Build output directory: %s", buildOutputDirectory) - - build := &builder.Build{ - ChaincodeSourceDirectory: chaincodeSourceDirectory, - ChaincodeMetadataDirectory: chaincodeMetadataDirectory, - BuildOutputDirectory: buildOutputDirectory, - } - - if err := build.Run(ctx); err != nil { - logger.Printf("Error building chaincode: %+v", err) - os.Exit(1) - } + os.Exit(cmd.Build()) } diff --git a/cmd/detect.go b/cmd/detect.go new file mode 100644 index 0000000..eadb785 --- /dev/null +++ b/cmd/detect.go @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: Apache-2.0 + +package cmd + +import ( + "context" + "errors" + "os" + "strconv" + + "github.com/hyperledger-labs/fabric-builder-k8s/internal/builder" + "github.com/hyperledger-labs/fabric-builder-k8s/internal/log" + "github.com/hyperledger-labs/fabric-builder-k8s/internal/util" +) + +func Detect() int { + const ( + expectedArgsLength = 3 + chaincodeSourceDirectoryArg = 1 + chaincodeMetadataDirectoryArg = 2 + ) + + debug, _ := strconv.ParseBool(util.GetOptionalEnv(util.DebugVariable, "false")) + ctx := log.NewCmdContext(context.Background(), debug) + logger := log.New(ctx) + + if len(os.Args) != expectedArgsLength { + logger.Println("Expected CHAINCODE_SOURCE_DIR and CHAINCODE_METADATA_DIR arguments") + + return 1 + } + + chaincodeSourceDirectory := os.Args[chaincodeSourceDirectoryArg] + chaincodeMetadataDirectory := os.Args[chaincodeMetadataDirectoryArg] + + logger.Debugf("Chaincode source directory: %s", chaincodeSourceDirectory) + logger.Debugf("Chaincode metadata directory: %s", chaincodeMetadataDirectory) + + detect := &builder.Detect{ + ChaincodeSourceDirectory: chaincodeSourceDirectory, + ChaincodeMetadataDirectory: chaincodeMetadataDirectory, + } + + if err := detect.Run(ctx); err != nil { + if !errors.Is(err, builder.ErrUnsupportedChaincodeType) { + // don't spam the peer log if it's just chaincode we don't recognise + logger.Printf("Error detecting chaincode: %+v", err) + } + + return 1 + } + + return 0 +} diff --git a/cmd/detect/main.go b/cmd/detect/main.go index bbfc60e..ad931ba 100644 --- a/cmd/detect/main.go +++ b/cmd/detect/main.go @@ -3,48 +3,11 @@ package main import ( - "context" - "errors" "os" - "github.com/hyperledger-labs/fabric-builder-k8s/internal/builder" - "github.com/hyperledger-labs/fabric-builder-k8s/internal/log" - "github.com/hyperledger-labs/fabric-builder-k8s/internal/util" -) - -const ( - expectedArgsLength = 3 - chaincodeSourceDirectoryArg = 1 - chaincodeMetadataDirectoryArg = 2 + "github.com/hyperledger-labs/fabric-builder-k8s/cmd" ) func main() { - debug := util.GetOptionalEnv(util.DebugVariable, "false") - ctx := log.NewCmdContext(context.Background(), debug == "true") - logger := log.New(ctx) - - if len(os.Args) != expectedArgsLength { - logger.Println("Expected CHAINCODE_SOURCE_DIR and CHAINCODE_METADATA_DIR arguments") - os.Exit(1) - } - - chaincodeSourceDirectory := os.Args[chaincodeSourceDirectoryArg] - chaincodeMetadataDirectory := os.Args[chaincodeMetadataDirectoryArg] - - logger.Debugf("Chaincode source directory: %s", chaincodeSourceDirectory) - logger.Debugf("Chaincode metadata directory: %s", chaincodeMetadataDirectory) - - detect := &builder.Detect{ - ChaincodeSourceDirectory: chaincodeSourceDirectory, - ChaincodeMetadataDirectory: chaincodeMetadataDirectory, - } - - if err := detect.Run(ctx); err != nil { - if !errors.Is(err, builder.ErrUnsupportedChaincodeType) { - // don't spam the peer log if it's just chaincode we don't recognise - logger.Printf("Error detecting chaincode: %+v", err) - } - - os.Exit(1) - } + os.Exit(cmd.Detect()) } diff --git a/cmd/release.go b/cmd/release.go new file mode 100644 index 0000000..27bc233 --- /dev/null +++ b/cmd/release.go @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: Apache-2.0 + +package cmd + +import ( + "context" + "os" + "strconv" + + "github.com/hyperledger-labs/fabric-builder-k8s/internal/builder" + "github.com/hyperledger-labs/fabric-builder-k8s/internal/log" + "github.com/hyperledger-labs/fabric-builder-k8s/internal/util" +) + +func Release() int { + const ( + expectedArgsLength = 3 + buildOutputDirectoryArg = 1 + releaseOutputDirectoryArg = 2 + ) + + debug, _ := strconv.ParseBool(util.GetOptionalEnv(util.DebugVariable, "false")) + ctx := log.NewCmdContext(context.Background(), debug) + logger := log.New(ctx) + + if len(os.Args) != expectedArgsLength { + logger.Println("Expected BUILD_OUTPUT_DIR and RELEASE_OUTPUT_DIR arguments") + + return 1 + } + + buildOutputDirectory := os.Args[buildOutputDirectoryArg] + releaseOutputDirectory := os.Args[releaseOutputDirectoryArg] + + logger.Debugf("Build output directory: %s", buildOutputDirectory) + logger.Debugf("Release output directory: %s", releaseOutputDirectory) + + release := &builder.Release{ + BuildOutputDirectory: buildOutputDirectory, + ReleaseOutputDirectory: releaseOutputDirectory, + } + + if err := release.Run(ctx); err != nil { + logger.Printf("Error releasing chaincode: %+v", err) + + return 1 + } + + return 0 +} diff --git a/cmd/release/main.go b/cmd/release/main.go index 24f11da..ebb272b 100644 --- a/cmd/release/main.go +++ b/cmd/release/main.go @@ -3,43 +3,11 @@ package main import ( - "context" "os" - "github.com/hyperledger-labs/fabric-builder-k8s/internal/builder" - "github.com/hyperledger-labs/fabric-builder-k8s/internal/log" - "github.com/hyperledger-labs/fabric-builder-k8s/internal/util" -) - -const ( - expectedArgsLength = 3 - buildOutputDirectoryArg = 1 - releaseOutputDirectoryArg = 2 + "github.com/hyperledger-labs/fabric-builder-k8s/cmd" ) func main() { - debug := util.GetOptionalEnv(util.DebugVariable, "false") - ctx := log.NewCmdContext(context.Background(), debug == "true") - logger := log.New(ctx) - - if len(os.Args) != expectedArgsLength { - logger.Println("Expected BUILD_OUTPUT_DIR and RELEASE_OUTPUT_DIR arguments") - os.Exit(1) - } - - buildOutputDirectory := os.Args[buildOutputDirectoryArg] - releaseOutputDirectory := os.Args[releaseOutputDirectoryArg] - - logger.Debugf("Build output directory: %s", buildOutputDirectory) - logger.Debugf("Release output directory: %s", releaseOutputDirectory) - - release := &builder.Release{ - BuildOutputDirectory: buildOutputDirectory, - ReleaseOutputDirectory: releaseOutputDirectory, - } - - if err := release.Run(ctx); err != nil { - logger.Printf("Error releasing chaincode: %+v", err) - os.Exit(1) - } + os.Exit(cmd.Release()) } diff --git a/cmd/run.go b/cmd/run.go new file mode 100644 index 0000000..cfdf528 --- /dev/null +++ b/cmd/run.go @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: Apache-2.0 + +package cmd + +import ( + "context" + "os" + "strconv" + + "github.com/hyperledger-labs/fabric-builder-k8s/internal/builder" + "github.com/hyperledger-labs/fabric-builder-k8s/internal/log" + "github.com/hyperledger-labs/fabric-builder-k8s/internal/util" + "k8s.io/apimachinery/pkg/api/validation" +) + +func Run() int { + const ( + expectedArgsLength = 3 + buildOutputDirectoryArg = 1 + runMetadataDirectoryArg = 2 + maximumKubeNamePrefixLength = 30 + ) + + debug, _ := strconv.ParseBool(util.GetOptionalEnv(util.DebugVariable, "false")) + ctx := log.NewCmdContext(context.Background(), debug) + logger := log.New(ctx) + + if len(os.Args) != expectedArgsLength { + logger.Println("Expected BUILD_OUTPUT_DIR and RUN_METADATA_DIR arguments") + + return 1 + } + + buildOutputDirectory := os.Args[buildOutputDirectoryArg] + runMetadataDirectory := os.Args[runMetadataDirectoryArg] + + logger.Debugf("Build output directory: %s", buildOutputDirectory) + logger.Debugf("Run metadata directory: %s", runMetadataDirectory) + + peerID, err := util.GetRequiredEnv(util.PeerIDVariable) + if err != nil { + logger.Printf("Expected %s environment variable\n", util.PeerIDVariable) + + return 1 + } + + logger.Debugf("%s=%s", util.PeerIDVariable, peerID) + + kubeconfigPath := util.GetOptionalEnv(util.KubeconfigPathVariable, "") + logger.Debugf("%s=%s", util.KubeconfigPathVariable, kubeconfigPath) + + kubeNamespace := util.GetOptionalEnv(util.ChaincodeNamespaceVariable, "") + logger.Debugf("%s=%s", util.ChaincodeNamespaceVariable, kubeNamespace) + + if kubeNamespace == "" { + kubeNamespace, err = util.GetKubeNamespace() + if err != nil { + kubeNamespace = util.DefaultNamespace + } + } + + kubeServiceAccount := util.GetOptionalEnv(util.ChaincodeServiceAccountVariable, util.DefaultServiceAccountName) + logger.Debugf("%s=%s", util.ChaincodeServiceAccountVariable, kubeServiceAccount) + + kubeNamePrefix := util.GetOptionalEnv(util.ObjectNamePrefixVariable, util.DefaultObjectNamePrefix) + logger.Debugf("%s=%s", util.ObjectNamePrefixVariable, kubeNamePrefix) + + if len(kubeNamePrefix) > maximumKubeNamePrefixLength { + logger.Printf("The FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX environment variable must be a maximum of 30 characters") + + return 1 + } + + if msgs := validation.NameIsDNS1035Label(kubeNamePrefix, true); len(msgs) > 0 { + logger.Printf("The FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX environment variable must be a valid DNS-1035 label: %s", msgs[0]) + + return 1 + } + + run := &builder.Run{ + BuildOutputDirectory: buildOutputDirectory, + RunMetadataDirectory: runMetadataDirectory, + PeerID: peerID, + KubeconfigPath: kubeconfigPath, + KubeNamespace: kubeNamespace, + KubeServiceAccount: kubeServiceAccount, + KubeNamePrefix: kubeNamePrefix, + } + + if err := run.Run(ctx); err != nil { + logger.Printf("Error running chaincode: %+v", err) + + return 1 + } + + return 0 +} diff --git a/cmd/run/main.go b/cmd/run/main.go index 4ddad81..15ce10b 100644 --- a/cmd/run/main.go +++ b/cmd/run/main.go @@ -3,87 +3,11 @@ package main import ( - "context" "os" - "github.com/hyperledger-labs/fabric-builder-k8s/internal/builder" - "github.com/hyperledger-labs/fabric-builder-k8s/internal/log" - "github.com/hyperledger-labs/fabric-builder-k8s/internal/util" - "k8s.io/apimachinery/pkg/api/validation" -) - -const ( - expectedArgsLength = 3 - buildOutputDirectoryArg = 1 - runMetadataDirectoryArg = 2 - maximumKubeNamePrefixLength = 30 + "github.com/hyperledger-labs/fabric-builder-k8s/cmd" ) func main() { - debug := util.GetOptionalEnv(util.DebugVariable, "false") - ctx := log.NewCmdContext(context.Background(), debug == "true") - logger := log.New(ctx) - - if len(os.Args) != expectedArgsLength { - logger.Println("Expected BUILD_OUTPUT_DIR and RUN_METADATA_DIR arguments") - os.Exit(1) - } - - buildOutputDirectory := os.Args[buildOutputDirectoryArg] - runMetadataDirectory := os.Args[runMetadataDirectoryArg] - - logger.Debugf("Build output directory: %s", buildOutputDirectory) - logger.Debugf("Run metadata directory: %s", runMetadataDirectory) - - peerID, err := util.GetRequiredEnv(util.PeerIDVariable) - if err != nil { - logger.Printf("Expected %s environment variable\n", util.PeerIDVariable) - os.Exit(1) - } - - logger.Debugf("%s=%s", util.PeerIDVariable, peerID) - - kubeconfigPath := util.GetOptionalEnv(util.KubeconfigPathVariable, "") - logger.Debugf("%s=%s", util.KubeconfigPathVariable, kubeconfigPath) - - kubeNamespace := util.GetOptionalEnv(util.ChaincodeNamespaceVariable, "") - logger.Debugf("%s=%s", util.ChaincodeNamespaceVariable, kubeNamespace) - - if kubeNamespace == "" { - kubeNamespace, err = util.GetKubeNamespace() - if err != nil { - kubeNamespace = util.DefaultNamespace - } - } - - kubeServiceAccount := util.GetOptionalEnv(util.ChaincodeServiceAccountVariable, util.DefaultServiceAccountName) - logger.Debugf("%s=%s", util.ChaincodeServiceAccountVariable, kubeServiceAccount) - - kubeNamePrefix := util.GetOptionalEnv(util.ObjectNamePrefixVariable, util.DefaultObjectNamePrefix) - logger.Debugf("%s=%s", util.ObjectNamePrefixVariable, kubeNamePrefix) - - if len(kubeNamePrefix) > maximumKubeNamePrefixLength { - logger.Printf("The FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX environment variable must be a maximum of 30 characters") - os.Exit(1) - } - - if msgs := validation.NameIsDNS1035Label(kubeNamePrefix, true); len(msgs) > 0 { - logger.Printf("The FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX environment variable must be a valid DNS-1035 label: %s", msgs[0]) - os.Exit(1) - } - - run := &builder.Run{ - BuildOutputDirectory: buildOutputDirectory, - RunMetadataDirectory: runMetadataDirectory, - PeerID: peerID, - KubeconfigPath: kubeconfigPath, - KubeNamespace: kubeNamespace, - KubeServiceAccount: kubeServiceAccount, - KubeNamePrefix: kubeNamePrefix, - } - - if err := run.Run(ctx); err != nil { - logger.Printf("Error running chaincode: %+v", err) - os.Exit(1) - } + os.Exit(cmd.Run()) } diff --git a/cmd/run/main_test.go b/cmd/run/main_test.go index 61174f2..a8166a4 100644 --- a/cmd/run/main_test.go +++ b/cmd/run/main_test.go @@ -1,10 +1,8 @@ package main_test import ( - "fmt" "os" "os/exec" - "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -66,73 +64,4 @@ var _ = Describe("Main", func() { Entry("When the FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX starts with a number", "1prefix", `run \[\d+\]: The FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX environment variable must be a valid DNS-1035 label: a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character`), Entry("When the FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX starts with a dash", "-prefix", `run \[\d+\]: The FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX environment variable must be a valid DNS-1035 label: a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character`), ) - - It( - "should start a chaincode job using the supplied configuration environment variables", - Label("kind"), - func() { - homedir, err := os.UserHomeDir() - Expect(err).NotTo(HaveOccurred()) - - args := []string{"./testdata/validimage", "./testdata/validchaincode"} - command := exec.Command(runCmdPath, args...) - command.Env = append(os.Environ(), - fmt.Sprintf("KUBECONFIG_PATH=%s/.kube/config", homedir), - "CORE_PEER_ID=core-peer-id-abcdefghijklmnopqrstuvwxyz-0123456789", - "FABRIC_K8S_BUILDER_DEBUG=true", - "FABRIC_K8S_BUILDER_NAMESPACE=chaincode", - "FABRIC_K8S_BUILDER_SERVICE_ACCOUNT=chaincode", - ) - session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) - Expect(err).NotTo(HaveOccurred()) - - Eventually(session).ShouldNot(gexec.Exit()) - Eventually( - session.Err, - ).Should(gbytes.Say(`run \[\d+\] DEBUG: FABRIC_K8S_BUILDER_NAMESPACE=chaincode`)) - Eventually( - session.Err, - ).Should(gbytes.Say(`run \[\d+\] DEBUG: FABRIC_K8S_BUILDER_SERVICE_ACCOUNT=chaincode`)) - Eventually( - session.Err, - ).Should(gbytes.Say(`run \[\d+\]: Running chaincode ID CHAINCODE_LABEL:6f98c4bb29414771312eddd1a813eef583df2121c235c4797792f141a46d4b45 with kubernetes job chaincode/hlfcc-chaincodelabel-piihcaj6ryttc`)) - - waitArgs := []string{ - "wait", - "--for=jsonpath=.status.ready=1", - "job", - "--timeout=120s", - "--namespace=chaincode", - "-l", - "fabric-builder-k8s-cclabel=CHAINCODE_LABEL", - } - waitCommand := exec.Command("kubectl", waitArgs...) - waitSession, err := gexec.Start(waitCommand, GinkgoWriter, GinkgoWriter) - Expect(err).NotTo(HaveOccurred()) - Eventually(waitSession).WithTimeout(240 * time.Second).Should(gexec.Exit(0)) - - descArgs := []string{ - "describe", - "job", - "--namespace=chaincode", - "-l", - "fabric-builder-k8s-cclabel=CHAINCODE_LABEL", - } - descCommand := exec.Command("kubectl", descArgs...) - descSession, err := gexec.Start(descCommand, GinkgoWriter, GinkgoWriter) - Expect(err).NotTo(HaveOccurred()) - - Eventually(descSession).Should(gexec.Exit(0)) - Eventually(descSession.Out).Should(gbytes.Say(`Namespace:\s+chaincode`)) - Eventually( - descSession.Out, - ).Should(gbytes.Say(`fabric-builder-k8s-ccid:\s+CHAINCODE_LABEL:6f98c4bb29414771312eddd1a813eef583df2121c235c4797792f141a46d4b45`)) - Eventually(descSession.Out).Should(gbytes.Say(`fabric-builder-k8s-mspid:\s+MSPID`)) - Eventually(descSession.Out).Should(gbytes.Say(`fabric-builder-k8s-peeraddress:\s+PEER_ADDRESS`)) - Eventually(descSession.Out).Should(gbytes.Say(`fabric-builder-k8s-peerid:\s+core-peer-id-abcdefghijklmnopqrstuvwxyz-0123456789`)) - Eventually(descSession.Out).Should(gbytes.Say(`CORE_CHAINCODE_ID_NAME:\s+CHAINCODE_LABEL:6f98c4bb29414771312eddd1a813eef583df2121c235c4797792f141a46d4b45`)) - Eventually(descSession.Out).Should(gbytes.Say(`CORE_PEER_ADDRESS:\s+PEER_ADDRESS`)) - Eventually(descSession.Out).Should(gbytes.Say(`CORE_PEER_LOCALMSPID:\s+MSPID`)) - }, - ) }) diff --git a/cmd/run/run_suite_test.go b/cmd/run/run_suite_test.go index 26119b9..8d9e17b 100644 --- a/cmd/run/run_suite_test.go +++ b/cmd/run/run_suite_test.go @@ -1,11 +1,9 @@ package main_test import ( - "os" "testing" "time" - "github.com/bitfield/script" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -13,31 +11,12 @@ import ( //nolint:gochecknoglobals // not sure how to avoid this var ( - includeKindTests bool - runCmdPath string + runCmdPath string ) func TestRun(t *testing.T) { RegisterFailHandler(Fail) - - suiteConfig, _ := GinkgoConfiguration() - - kindEnv := os.Getenv("INCLUDE_KIND_TESTS") - if kindEnv == "true" { - includeKindTests = true - } else { - includeKindTests = false - } - - if !includeKindTests { - if suiteConfig.LabelFilter == "" { - suiteConfig.LabelFilter = "!kind" - } else { - suiteConfig.LabelFilter = "(" + suiteConfig.LabelFilter + ") && !kind" - } - } - - RunSpecs(t, "Run Suite", suiteConfig) + RunSpecs(t, "Run Suite") } var _ = BeforeSuite(func() { @@ -46,31 +25,8 @@ var _ = BeforeSuite(func() { var err error runCmdPath, err = gexec.Build("github.com/hyperledger-labs/fabric-builder-k8s/cmd/run") Expect(err).NotTo(HaveOccurred()) - - if includeKindTests { - script.Exec("kind delete cluster --name fabric-builder-k8s-test") - - pipe := script.Exec("kind create cluster --name fabric-builder-k8s-test") - _, err = pipe.Stdout() - Expect(err).NotTo(HaveOccurred()) - Expect(pipe.ExitStatus()).To(Equal(0)) - - pipe = script.Exec("kubectl create namespace chaincode") - _, err = pipe.Stdout() - Expect(err).NotTo(HaveOccurred()) - Expect(pipe.ExitStatus()).To(Equal(0)) - - pipe = script.Exec("kubectl create serviceaccount chaincode --namespace=chaincode") - _, err = pipe.Stdout() - Expect(err).NotTo(HaveOccurred()) - Expect(pipe.ExitStatus()).To(Equal(0)) - } }) var _ = AfterSuite(func() { gexec.CleanupBuildArtifacts() - if includeKindTests { - _, err := script.Exec("kind delete cluster --name fabric-builder-k8s-test").Stdout() - Expect(err).NotTo(HaveOccurred()) - } }) diff --git a/go.mod b/go.mod index d3ffae7..9ff42ba 100644 --- a/go.mod +++ b/go.mod @@ -1,18 +1,26 @@ module github.com/hyperledger-labs/fabric-builder-k8s -go 1.22.0 +go 1.22.3 + +toolchain go1.22.10 require ( github.com/onsi/ginkgo/v2 v2.22.0 github.com/onsi/gomega v1.36.0 github.com/otiai10/copy v1.14.0 + github.com/rogpeppe/go-internal v1.13.1 k8s.io/api v0.31.3 k8s.io/apimachinery v0.31.3 k8s.io/client-go v0.31.3 + sigs.k8s.io/e2e-framework v0.5.0 ) require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/emicklei/go-restful/v3 v3.11.2 // indirect + github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.4 // indirect @@ -21,15 +29,26 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect github.com/itchyny/gojq v0.12.13 // indirect github.com/itchyny/timefmt-go v0.1.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/moby/spdystream v0.4.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/vladimirvivien/gexe v0.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/tools v0.26.0 // indirect + k8s.io/component-base v0.31.1 // indirect mvdan.cc/sh/v3 v3.7.0 // indirect + sigs.k8s.io/controller-runtime v0.19.0 // indirect ) require ( diff --git a/go.sum b/go.sum index d37b30d..ca289e0 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,29 @@ +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bitfield/script v0.23.0 h1:N0R5yLEl6wJIS9PR/A6xXwjMsplMubyxdi05N5l0X28= github.com/bitfield/script v0.23.0/go.mod h1:fv+6x4OzVsRs6qAlc7wiGq8fq1b5orhtQdtW0dwjUHI= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emicklei/go-restful/v3 v3.11.2 h1:1onLa9DcsMYO9P+CXaL0dStDqQ2EHHXLiz+BtnqkLAU= github.com/emicklei/go-restful/v3 v3.11.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= +github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= @@ -36,6 +48,8 @@ github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgY github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU= @@ -54,6 +68,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= +github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -61,6 +77,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.36.0 h1:Pb12RlruUtj4XUuPUqeEWc6j5DkVVVA49Uf6YLfC95Y= @@ -74,21 +92,37 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/vladimirvivien/gexe v0.3.0 h1:4xwiOwGrDob5OMR6E92B9olDXYDglXdHhzR1ggYtWJM= +github.com/vladimirvivien/gexe v0.3.0/go.mod h1:fp7cy60ON1xjhtEI/+bfSEIXX35qgmI+iRYlGOqbBFM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -143,10 +177,14 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8= k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE= +k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= +k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4= k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4= k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs= +k8s.io/component-base v0.31.1 h1:UpOepcrX3rQ3ab5NB6g5iP0tvsgJWzxTyAo20sgYSy8= +k8s.io/component-base v0.31.1/go.mod h1:WGeaw7t/kTsqpVTaCoVEtillbqAhF2/JgvO0LDOMa0w= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= @@ -155,6 +193,10 @@ k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1 k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8= +sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= +sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= +sigs.k8s.io/e2e-framework v0.5.0 h1:YLhk8R7EHuTFQAe6Fxy5eBzn5Vb+yamR5u8MH1Rq3cE= +sigs.k8s.io/e2e-framework v0.5.0/go.mod h1:jJSH8u2RNmruekUZgHAtmRjb5Wj67GErli9UjLSY7Zc= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= diff --git a/test/integration/integration_test.go b/test/integration/integration_test.go new file mode 100644 index 0000000..453d383 --- /dev/null +++ b/test/integration/integration_test.go @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: Apache-2.0 + +//go:build linux +// +build linux + +package integration_test + +import ( + "context" + "testing" + + "github.com/hyperledger-labs/fabric-builder-k8s/test" + "github.com/rogpeppe/go-internal/testscript" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/e2e-framework/pkg/envconf" + "sigs.k8s.io/e2e-framework/pkg/features" +) + +func TestRunChaincode(t *testing.T) { + testenv.Test(t, features.NewWithDescription(t.Name()+"Feature", "the builder should run chaincode in the specified namespace"). + Assess(t.Name()+"Assessment", func(ctx context.Context, t *testing.T, _ *envconf.Config) context.Context { + t.Helper() + + testscript.Run(t, test.NewTestscriptParams(t, "testdata/run_chaincode.txtar", testenv)) + + return ctx + }).Feature()) +} + +func TestRunChaincodeWithServiceAccount(t *testing.T) { + testenv.Test(t, features.NewWithDescription(t.Name()+"Feature", "the builder should run chaincode in with the specified service account"). + Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { + t.Helper() + + // TODO: create service account + serviceAccount := &v1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{Name: "chaincode", Namespace: cfg.Namespace()}, + } + client, err := cfg.NewClient() + if err != nil { + t.Fatal(err) + } + if err := client.Resources().Create(ctx, serviceAccount); err != nil { + t.Fatal(err) + } + return ctx + }). + Assess(t.Name()+"Assessment", func(ctx context.Context, t *testing.T, _ *envconf.Config) context.Context { + t.Helper() + + testscript.Run(t, test.NewTestscriptParams(t, "testdata/chaincode_service_account.txtar", testenv)) + + return ctx + }). + Teardown(func(ctx context.Context, t *testing.T, _ *envconf.Config) context.Context { + t.Helper() + + // TODO: delete service account? + + return ctx + }).Feature()) +} diff --git a/test/integration/main_test.go b/test/integration/main_test.go new file mode 100644 index 0000000..6dade0f --- /dev/null +++ b/test/integration/main_test.go @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: Apache-2.0 + +//go:build linux +// +build linux + +package integration_test + +import ( + "context" + "os" + "testing" + + "github.com/hyperledger-labs/fabric-builder-k8s/cmd" + "github.com/hyperledger-labs/fabric-builder-k8s/test" + "github.com/rogpeppe/go-internal/testscript" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/e2e-framework/pkg/env" + "sigs.k8s.io/e2e-framework/pkg/envconf" + "sigs.k8s.io/e2e-framework/pkg/envfuncs" + "sigs.k8s.io/e2e-framework/support/kind" +) + +//nolint:gochecknoglobals // not sure how to avoid this +var ( + testenv env.Environment +) + +func TestMain(m *testing.M) { + envCfg := envconf.New().WithRandomNamespace() + testenv = env.NewWithConfig(envCfg) + clusterName := envconf.RandomName("test-cluster", 16) + + testenv.Setup( + envfuncs.CreateCluster(kind.NewProvider(), clusterName), + envfuncs.CreateNamespace(envCfg.Namespace()), + ) + + testenv.BeforeEachTest( + //nolint:thelper,test,first // *testing.T must be the last param for a TestEnvFunc + func(ctx context.Context, cfg *envconf.Config, t *testing.T) (context.Context, error) { + t.Helper() + + t.Logf("Doing nothing before test %s", t.Name()) + + return ctx, nil + + // TODO create namespace... see https://github.com/kubernetes-sigs/e2e-framework/tree/main/examples/every_test_custom_ns + // name := cfg.Namespace() + + // t.Logf("Creating namespace %s before test %s", name, t.Name()) + + // return envfuncs.CreateNamespace(name)(ctx, cfg) + }, + ) + + testenv.AfterEachTest( + //nolint:thelper,test,first // *testing.T must be the last param for a TestEnvFunc + func(ctx context.Context, cfg *envconf.Config, t *testing.T) (context.Context, error) { + t.Helper() + + t.Logf("Doing nothing after test %s", t.Name()) + + return ctx, nil + + // name := cfg.Namespace() + + // t.Logf("Deleting namespace %s after test %s", name, t.Name()) + + // return envfuncs.DeleteNamespace(name)(ctx, cfg) + }, + ) + + testenv.Finish( + envfuncs.DeleteNamespace(envCfg.Namespace()), + envfuncs.DestroyCluster(clusterName), + ) + + // TODO make this less hacky?!!! + wm := test.NewWrappedM(m, testenv) + os.Exit(testscript.RunMain(wm, map[string]func() int{ + "run": cmd.Run, + })) +} + +// TODO new service account!!! +// apiVersion: v1 +// kind: ServiceAccount +// metadata: +// +// annotations: +// kubernetes.io/enforce-mountable-secrets: "true" +// name: my-serviceaccount +// namespace: my-namespace +func newServiceAccount(namespace string, name string) *v1.ServiceAccount { + return &v1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace}, + } +} diff --git a/test/integration/testdata/chaincode_service_account.txtar b/test/integration/testdata/chaincode_service_account.txtar new file mode 100644 index 0000000..d4ef9e5 --- /dev/null +++ b/test/integration/testdata/chaincode_service_account.txtar @@ -0,0 +1,32 @@ +env CORE_PEER_ID=core-peer-id-abcdefghijklmnopqrstuvwxyz-0123456789 +env FABRIC_K8S_BUILDER_NAMESPACE=$TESTENV_NAMESPACE +env FABRIC_K8S_BUILDER_SERVICE_ACCOUNT=chaincode + +# the builder should create a chaincode job +exec run build_output_dir run_metadata_dir &builder& + +jobinfo SERVICE_ACCOUNT_CHAINCODE_LABEL 6f98c4bb29414771312eddd1a813eef583df2121c235c4797792f141a46d4b45 + +# the chaincode job should start a chaincode pod +podinfo SERVICE_ACCOUNT_CHAINCODE_LABEL 6f98c4bb29414771312eddd1a813eef583df2121c235c4797792f141a46d4b45 + +# the chaincode job should have the expected service account +stdout -count=1 '^Pod service account: chaincode$' + +kill builder + +-- build_output_dir/image.json -- +{ + "name": "nginx", + "digest": "sha256:da3cc3053314be9ca3871307366f6e30ce2b11e1ea6a72e5957244d99b2515bf" +} + +-- run_metadata_dir/chaincode.json -- +{ + "chaincode_id": "SERVICE_ACCOUNT_CHAINCODE_LABEL:6f98c4bb29414771312eddd1a813eef583df2121c235c4797792f141a46d4b45", + "peer_address": "PEER_ADDRESS", + "client_cert": "CLIENT_CERT", + "client_key": "CLIENT_KEY", + "root_cert": "ROOT_CERT", + "mspid": "MSPID" +} diff --git a/test/integration/testdata/run_chaincode.txtar b/test/integration/testdata/run_chaincode.txtar new file mode 100644 index 0000000..ffe6dc5 --- /dev/null +++ b/test/integration/testdata/run_chaincode.txtar @@ -0,0 +1,62 @@ +env CORE_PEER_ID=core-peer-id-abcdefghijklmnopqrstuvwxyz-0123456789 +env FABRIC_K8S_BUILDER_NAMESPACE=$TESTENV_NAMESPACE + +# the builder should create a chaincode job +exec run build_output_dir run_metadata_dir &builder& + +jobinfo RUN_CHAINCODE_LABEL 6f98c4bb29414771312eddd1a813eef583df2121c235c4797792f141a46d4b45 + +# the chaincode job should have the expected name +stdout -count=1 '^Job name: hlfcc-runchaincodelabel-uyg2zc6uzes7g-[a-z0-9]{5}$' + +# the chaincode job should have the expected labels +stdout -count=1 '^app\.kubernetes\.io/created-by=fabric-builder-k8s$' +stdout -count=1 '^app\.kubernetes\.io/managed-by=fabric-builder-k8s$' +stdout -count=1 '^app\.kubernetes\.io/name=hyperledger-fabric$' +stdout -count=1 '^fabric-builder-k8s-cchash=N6MMJOZJIFDXCMJO3XI2QE7O6WB56IJBYI24I6LXSLYUDJDNJNCQ$' +stdout -count=1 '^fabric-builder-k8s-cclabel=RUN_CHAINCODE_LABEL$' +stdout -count=1 '^app\.kubernetes\.io/component=chaincode$' + +# the chaincode job should have the expected annotations +stdout -count=1 'fabric-builder-k8s-peerid=core-peer-id-abcdefghijklmnopqrstuvwxyz-0123456789$' +stdout -count=1 'fabric-builder-k8s-ccid=RUN_CHAINCODE_LABEL:6f98c4bb29414771312eddd1a813eef583df2121c235c4797792f141a46d4b45$' +stdout -count=1 'fabric-builder-k8s-mspid=MSPID$' +stdout -count=1 'fabric-builder-k8s-peeraddress=PEER_ADDRESS$' + +# the chaincode job should start a chaincode pod +podinfo RUN_CHAINCODE_LABEL 6f98c4bb29414771312eddd1a813eef583df2121c235c4797792f141a46d4b45 + +# the chaincode pod should have the expected name +stdout -count=1 '^Pod name: hlfcc-runchaincodelabel-uyg2zc6uzes7g-[a-z0-9]{5}-[a-z0-9]{5}$' + +# the chaincode pod should have the expected labels +stdout -count=1 '^app\.kubernetes\.io/created-by=fabric-builder-k8s$' +stdout -count=1 '^app\.kubernetes\.io/managed-by=fabric-builder-k8s$' +stdout -count=1 '^app\.kubernetes\.io/name=hyperledger-fabric$' +stdout -count=1 '^fabric-builder-k8s-cchash=N6MMJOZJIFDXCMJO3XI2QE7O6WB56IJBYI24I6LXSLYUDJDNJNCQ$' +stdout -count=1 '^fabric-builder-k8s-cclabel=RUN_CHAINCODE_LABEL$' +stdout -count=1 '^app\.kubernetes\.io/component=chaincode$' + +# the chaincode pod should have the expected annotations +stdout -count=1 'fabric-builder-k8s-peerid=core-peer-id-abcdefghijklmnopqrstuvwxyz-0123456789$' +stdout -count=1 'fabric-builder-k8s-ccid=RUN_CHAINCODE_LABEL:6f98c4bb29414771312eddd1a813eef583df2121c235c4797792f141a46d4b45$' +stdout -count=1 'fabric-builder-k8s-mspid=MSPID$' +stdout -count=1 'fabric-builder-k8s-peeraddress=PEER_ADDRESS$' + +kill builder + +-- build_output_dir/image.json -- +{ + "name": "nginx", + "digest": "sha256:da3cc3053314be9ca3871307366f6e30ce2b11e1ea6a72e5957244d99b2515bf" +} + +-- run_metadata_dir/chaincode.json -- +{ + "chaincode_id": "RUN_CHAINCODE_LABEL:6f98c4bb29414771312eddd1a813eef583df2121c235c4797792f141a46d4b45", + "peer_address": "PEER_ADDRESS", + "client_cert": "CLIENT_CERT", + "client_key": "CLIENT_KEY", + "root_cert": "ROOT_CERT", + "mspid": "MSPID" +} diff --git a/test/testscript_helpers.go b/test/testscript_helpers.go new file mode 100644 index 0000000..7749bf8 --- /dev/null +++ b/test/testscript_helpers.go @@ -0,0 +1,225 @@ +package test + +import ( + "encoding/base32" + "encoding/hex" + "fmt" + "os" + "strconv" + "testing" + "time" + + "github.com/rogpeppe/go-internal/testscript" + batchv1 "k8s.io/api/batch/v1" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "sigs.k8s.io/e2e-framework/klient/k8s/resources" + "sigs.k8s.io/e2e-framework/klient/wait" + "sigs.k8s.io/e2e-framework/klient/wait/conditions" + "sigs.k8s.io/e2e-framework/pkg/env" +) + +const ( + waitInterval = 2 * time.Second + shortWaitTimeout = 30 * time.Second + longWaitTimeout = 5 * time.Minute +) + +type WrappedM struct { + m *testing.M + testenv env.Environment +} + +func (w WrappedM) Run() int { + return w.testenv.Run(w.m) +} + +func NewWrappedM(m *testing.M, testenv env.Environment) WrappedM { + return WrappedM{ + m: m, + testenv: testenv, + } +} + +func getEncodedHash(hash string) (string, error) { + packageHashBytes, err := hex.DecodeString(hash) + if err != nil { + return "", fmt.Errorf("error decoding chaincode package hash %s: %w", hash, err) + } + + encodedPackageHash := base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(packageHashBytes) + + return encodedPackageHash, nil +} + +func jobInfoCmd(script *testscript.TestScript, _ bool, args []string) { + if len(args) != 2 { + script.Fatalf("usage: jobinfo chaincode_label chaincode_hash") + } + + cclabel := args[0] + cchash, err := getEncodedHash(args[1]) + if err != nil { + script.Fatalf("error encoding chaincode hash %s: %v", args[1], err) + } + + testenv, ok := script.Value("testenv").(env.Environment) + if !ok { + script.Fatalf("could not convert testenv value") + } + + cfg := testenv.EnvConf() + + script.Logf("Waiting for job to be created for chaincode %s", cclabel) + + jobs := &batchv1.JobList{} + + err = wait.For(conditions.New(cfg.Client().Resources()).ResourceListN(jobs, 1, + resources.WithLabelSelector( + labels.FormatLabels(map[string]string{ + "fabric-builder-k8s-cclabel": cclabel, + "fabric-builder-k8s-cchash": cchash, + }))), wait.WithInterval(waitInterval), wait.WithTimeout(shortWaitTimeout)) + if err != nil { + script.Fatalf("failed waiting for chaincode job to be created: %v", err) + } + + job := &jobs.Items[0] + + _, err = script.Stdout().Write([]byte(fmt.Sprintf("Job name: %s\n", job.GetName()))) + script.Check(err) + + _, err = script.Stdout().Write([]byte(fmt.Sprintf("Job namespace: %s\n", job.GetNamespace()))) + script.Check(err) + + _, err = script.Stdout().Write([]byte("Job labels:\n")) + script.Check(err) + + for k, v := range job.GetLabels() { + _, err = script.Stdout().Write([]byte(fmt.Sprintf("%s=%s\n", k, v))) + script.Check(err) + } + + _, err = script.Stdout().Write([]byte("Job annotations:\n")) + script.Check(err) + + for k, v := range job.GetAnnotations() { + _, err = script.Stdout().Write([]byte(fmt.Sprintf("%s=%s\n", k, v))) + script.Check(err) + } +} + +func podInfoCmd(script *testscript.TestScript, _ bool, args []string) { + if len(args) != 2 { + script.Fatalf("usage: podinfo chaincode_label chaincode_hash") + } + + cclabel := args[0] + cchash, err := getEncodedHash(args[1]) + if err != nil { + script.Fatalf("error encoding chaincode hash %s: %v", args[1], err) + } + + testenv, ok := script.Value("testenv").(env.Environment) + if !ok { + script.Fatalf("could not convert testenv value") + } + + cfg := testenv.EnvConf() + + script.Logf("Waiting for job to be created for chaincode %s", cclabel) + + jobs := &batchv1.JobList{} + + err = wait.For(conditions.New(cfg.Client().Resources()).ResourceListN(jobs, 1, + resources.WithLabelSelector( + labels.FormatLabels(map[string]string{ + "fabric-builder-k8s-cclabel": cclabel, + "fabric-builder-k8s-cchash": cchash, + }))), + wait.WithInterval(waitInterval), wait.WithTimeout(shortWaitTimeout)) + if err != nil { + script.Fatalf("failed waiting for chaincode job to be created: %v", err) + } + + job := &jobs.Items[0] + jobname := job.GetName() + + script.Logf("Waiting for pod to be created for chaincode job %s", jobname) + + pods := &v1.PodList{} + + err = wait.For(conditions.New(cfg.Client().Resources()).ResourceListN(pods, 1, + resources.WithLabelSelector( + labels.FormatLabels(map[string]string{ + "batch.kubernetes.io/job-name": jobname, + }))), wait.WithInterval(waitInterval), wait.WithTimeout(shortWaitTimeout)) + if err != nil { + script.Fatalf("failed waiting for chaincode pod to be created: %v", err) + } + + pod := &pods.Items[0] + podname := pod.GetName() + + script.Logf("Waiting for pod %s to start", podname) + + err = wait.For(conditions.New(cfg.Client().Resources()).PodReady(pod), wait.WithInterval(waitInterval), wait.WithTimeout(longWaitTimeout)) + if err != nil { + script.Fatalf("failed to wait for chaincode pod %s to reach Ready condition: %v", podname, err) + } + + _, err = script.Stdout().Write([]byte(fmt.Sprintf("Pod name: %s\n", podname))) + script.Check(err) + + _, err = script.Stdout().Write([]byte(fmt.Sprintf("Pod namespace: %s\n", pod.GetNamespace()))) + script.Check(err) + + _, err = script.Stdout().Write([]byte(fmt.Sprintf("Pod service account: %s\n", pod.Spec.ServiceAccountName))) + script.Check(err) + + _, err = script.Stdout().Write([]byte("Pod labels:\n")) + script.Check(err) + + for k, v := range pod.GetLabels() { + _, err = script.Stdout().Write([]byte(fmt.Sprintf("%s=%s\n", k, v))) + script.Check(err) + } + + _, err = script.Stdout().Write([]byte("Pod annotations:\n")) + script.Check(err) + + for k, v := range pod.GetAnnotations() { + _, err = script.Stdout().Write([]byte(fmt.Sprintf("%s=%s\n", k, v))) + script.Check(err) + } +} + +func setupTestscriptEnv(t *testing.T, tsenv *testscript.Env, testenv env.Environment) error { + t.Helper() + + tsenv.Setenv("KUBECONFIG_PATH", testenv.EnvConf().KubeconfigFile()) + tsenv.Setenv("TESTENV_NAMESPACE", testenv.EnvConf().Namespace()) + + tsenv.Values["testenv"] = testenv + + return nil +} + +func NewTestscriptParams(t *testing.T, scriptfile string, testenv env.Environment) testscript.Params { + t.Helper() + + keepWorkDirs, _ := strconv.ParseBool(os.Getenv("KEEP_TESTSCRIPT_DIRS")) + + params := testscript.Params{ + Files: []string{scriptfile}, + RequireExplicitExec: true, + Setup: func(e *testscript.Env) error { return setupTestscriptEnv(t, e, testenv) }, + TestWork: keepWorkDirs, + Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){ + "jobinfo": jobInfoCmd, + "podinfo": podInfoCmd, + }, + } + + return params +}