From a2987675cf18ce9afecb3251edc59f09a6bea1cf Mon Sep 17 00:00:00 2001 From: wackxu Date: Tue, 21 Aug 2018 23:03:36 +0800 Subject: [PATCH] add csi-test to vendor --- Gopkg.lock | 242 ++- vendor/github.com/golang/mock/.gitignore | 17 + vendor/github.com/golang/mock/.travis.yml | 14 + vendor/github.com/golang/mock/AUTHORS | 12 + vendor/github.com/golang/mock/CONTRIBUTORS | 37 + vendor/github.com/golang/mock/LICENSE | 202 ++ vendor/github.com/golang/mock/README.md | 94 + .../github.com/golang/mock/ci/check_go_fmt.sh | 12 + .../golang/mock/ci/check_go_generate.sh | 25 + vendor/github.com/golang/mock/gomock/call.go | 428 +++++ .../golang/mock/gomock/call_test.go | 51 + .../github.com/golang/mock/gomock/callset.go | 108 ++ .../golang/mock/gomock/callset_test.go | 76 + .../golang/mock/gomock/controller.go | 217 +++ .../golang/mock/gomock/controller_test.go | 712 ++++++++ .../github.com/golang/mock/gomock/matchers.go | 99 + .../golang/mock/gomock/matchers_test.go | 70 + .../mock/gomock/mock_matcher/mock_matcher.go | 57 + .../github.com/golang/mock/mockgen/mockgen.go | 559 ++++++ .../golang/mock/mockgen/mockgen_test.go | 181 ++ .../golang/mock/mockgen/model/model.go | 449 +++++ .../github.com/golang/mock/mockgen/parse.go | 504 +++++ .../golang/mock/mockgen/parse_test.go | 108 ++ .../github.com/golang/mock/mockgen/reflect.go | 197 ++ .../aux_imports_embedded_interface/README.md | 36 + .../bugreport.go | 18 + .../bugreport_mock.go | 46 + .../bugreport_test.go | 18 + .../faux/faux.go | 10 + .../tests/custom_package_name/README.md | 22 + .../custom_package_name/client/v1/client.go | 13 + .../custom_package_name/greeter/greeter.go | 31 + .../greeter/greeter_mock_test.go | 46 + .../greeter/greeter_test.go | 37 + .../custom_package_name/validator/validate.go | 5 + .../mockgen/tests/empty_interface/input.go | 4 + .../mockgen/tests/empty_interface/mock.go | 32 + .../generated_identifier_conflict/README.md | 26 + .../bugreport.go | 16 + .../bugreport_mock.go | 58 + .../bugreport_test.go | 26 + .../mockgen/tests/import_source/Readme.md | 3 + .../tests/import_source/definition/source.go | 9 + .../import_source/definition/source_mock.go | 43 + .../tests/import_source/source_mock.go | 44 + .../mockgen/tests/internal_pkg/generate.go | 3 + .../internal_pkg/subdir/internal/pkg/input.go | 9 + .../internal/pkg/reflect_output/mock.go | 46 + .../subdir/internal/pkg/source_output/mock.go | 81 + .../mockgen/tests/unexported_method/README.md | 1 + .../tests/unexported_method/bugreport.go | 15 + .../tests/unexported_method/bugreport_mock.go | 45 + .../tests/unexported_method/bugreport_test.go | 17 + .../mock/mockgen/tests/vendor_dep/README.md | 2 + .../mock/mockgen/tests/vendor_dep/doc.go | 4 + .../mock/mockgen/tests/vendor_dep/mock.go | 46 + .../vendor_dep/source_mock_package/mock.go | 46 + .../mockgen/tests/vendor_dep/vendor_dep.go | 7 + .../mock/mockgen/tests/vendor_pkg/README.md | 1 + .../mock/mockgen/tests/vendor_pkg/doc.go | 3 + .../mock/mockgen/tests/vendor_pkg/mock.go | 99 + .../github.com/golang/mock/sample/README.md | 16 + .../mock/sample/concurrent/concurrent.go | 8 + .../mock/sample/concurrent/concurrent_test.go | 46 + .../sample/concurrent/mock/concurrent_mock.go | 45 + .../golang/mock/sample/imp1/imp1.go | 17 + .../golang/mock/sample/imp2/imp2.go | 3 + .../golang/mock/sample/imp3/imp3.go | 3 + .../golang/mock/sample/imp4/imp4.go | 3 + .../golang/mock/sample/mock_user/mock_user.go | 384 ++++ vendor/github.com/golang/mock/sample/user.go | 114 ++ .../golang/mock/sample/user_test.go | 161 ++ .../kubernetes-csi/csi-test/.gitignore | 13 + .../kubernetes-csi/csi-test/.travis.yml | 11 + .../kubernetes-csi/csi-test/Dockerfile.mock | 6 + .../kubernetes-csi/csi-test/Gopkg.lock | 195 ++ .../kubernetes-csi/csi-test/Gopkg.toml | 62 + .../kubernetes-csi/csi-test/LICENSE | 201 ++ .../kubernetes-csi/csi-test/Makefile | 52 + .../github.com/kubernetes-csi/csi-test/OWNERS | 4 + .../kubernetes-csi/csi-test/README.md | 29 + .../kubernetes-csi/csi-test/SECURITY_CONTACTS | 14 + .../csi-test/cmd/csi-sanity/Makefile | 61 + .../csi-test/cmd/csi-sanity/README.md | 58 + .../csi-test/cmd/csi-sanity/sanity_test.go | 56 + .../csi-test/code-of-conduct.md | 3 + .../kubernetes-csi/csi-test/driver/driver.go | 247 +++ .../csi-test/driver/driver.mock.go | 354 ++++ .../kubernetes-csi/csi-test/driver/mock.go | 83 + .../kubernetes-csi/csi-test/hack/e2e.sh | 50 + .../kubernetes-csi/csi-test/mock/AUTHORS | 2 + .../kubernetes-csi/csi-test/mock/README.md | 2 + .../csi-test/mock/cache/SnapshotCache.go | 89 + .../kubernetes-csi/csi-test/mock/main.go | 88 + .../csi-test/mock/mocksecret.yaml | 16 + .../csi-test/mock/service/controller.go | 559 ++++++ .../csi-test/mock/service/identity.go | 48 + .../csi-test/mock/service/node.go | 236 +++ .../csi-test/mock/service/service.go | 137 ++ .../csi-test/pkg/sanity/README.md | 62 + .../csi-test/pkg/sanity/cleanup.go | 134 ++ .../csi-test/pkg/sanity/controller.go | 1626 +++++++++++++++++ .../csi-test/pkg/sanity/identity.go | 99 + .../csi-test/pkg/sanity/node.go | 528 ++++++ .../csi-test/pkg/sanity/sanity.go | 163 ++ .../csi-test/pkg/sanity/tests.go | 56 + .../kubernetes-csi/csi-test/test/co_test.go | 188 ++ .../csi-test/test/driver_test.go | 127 ++ .../kubernetes-csi/csi-test/utils/grpcutil.go | 59 + .../csi-test/utils/safegoroutinetester.go | 40 + 110 files changed, 11973 insertions(+), 24 deletions(-) create mode 100644 vendor/github.com/golang/mock/.gitignore create mode 100644 vendor/github.com/golang/mock/.travis.yml create mode 100644 vendor/github.com/golang/mock/AUTHORS create mode 100644 vendor/github.com/golang/mock/CONTRIBUTORS create mode 100644 vendor/github.com/golang/mock/LICENSE create mode 100644 vendor/github.com/golang/mock/README.md create mode 100755 vendor/github.com/golang/mock/ci/check_go_fmt.sh create mode 100755 vendor/github.com/golang/mock/ci/check_go_generate.sh create mode 100644 vendor/github.com/golang/mock/gomock/call.go create mode 100644 vendor/github.com/golang/mock/gomock/call_test.go create mode 100644 vendor/github.com/golang/mock/gomock/callset.go create mode 100644 vendor/github.com/golang/mock/gomock/callset_test.go create mode 100644 vendor/github.com/golang/mock/gomock/controller.go create mode 100644 vendor/github.com/golang/mock/gomock/controller_test.go create mode 100644 vendor/github.com/golang/mock/gomock/matchers.go create mode 100644 vendor/github.com/golang/mock/gomock/matchers_test.go create mode 100644 vendor/github.com/golang/mock/gomock/mock_matcher/mock_matcher.go create mode 100644 vendor/github.com/golang/mock/mockgen/mockgen.go create mode 100644 vendor/github.com/golang/mock/mockgen/mockgen_test.go create mode 100644 vendor/github.com/golang/mock/mockgen/model/model.go create mode 100644 vendor/github.com/golang/mock/mockgen/parse.go create mode 100644 vendor/github.com/golang/mock/mockgen/parse_test.go create mode 100644 vendor/github.com/golang/mock/mockgen/reflect.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/README.md create mode 100644 vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/bugreport.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/bugreport_mock.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/bugreport_test.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/faux/faux.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/custom_package_name/README.md create mode 100644 vendor/github.com/golang/mock/mockgen/tests/custom_package_name/client/v1/client.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/custom_package_name/greeter/greeter.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/custom_package_name/greeter/greeter_mock_test.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/custom_package_name/greeter/greeter_test.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/custom_package_name/validator/validate.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/empty_interface/input.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/empty_interface/mock.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/README.md create mode 100644 vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/bugreport.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/bugreport_mock.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/bugreport_test.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/import_source/Readme.md create mode 100644 vendor/github.com/golang/mock/mockgen/tests/import_source/definition/source.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/import_source/definition/source_mock.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/import_source/source_mock.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/internal_pkg/generate.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg/input.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg/reflect_output/mock.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg/source_output/mock.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/unexported_method/README.md create mode 100644 vendor/github.com/golang/mock/mockgen/tests/unexported_method/bugreport.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/unexported_method/bugreport_mock.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/unexported_method/bugreport_test.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/vendor_dep/README.md create mode 100644 vendor/github.com/golang/mock/mockgen/tests/vendor_dep/doc.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/vendor_dep/mock.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/vendor_dep/source_mock_package/mock.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/vendor_dep/vendor_dep.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/vendor_pkg/README.md create mode 100644 vendor/github.com/golang/mock/mockgen/tests/vendor_pkg/doc.go create mode 100644 vendor/github.com/golang/mock/mockgen/tests/vendor_pkg/mock.go create mode 100644 vendor/github.com/golang/mock/sample/README.md create mode 100644 vendor/github.com/golang/mock/sample/concurrent/concurrent.go create mode 100644 vendor/github.com/golang/mock/sample/concurrent/concurrent_test.go create mode 100644 vendor/github.com/golang/mock/sample/concurrent/mock/concurrent_mock.go create mode 100644 vendor/github.com/golang/mock/sample/imp1/imp1.go create mode 100644 vendor/github.com/golang/mock/sample/imp2/imp2.go create mode 100644 vendor/github.com/golang/mock/sample/imp3/imp3.go create mode 100644 vendor/github.com/golang/mock/sample/imp4/imp4.go create mode 100644 vendor/github.com/golang/mock/sample/mock_user/mock_user.go create mode 100644 vendor/github.com/golang/mock/sample/user.go create mode 100644 vendor/github.com/golang/mock/sample/user_test.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/.gitignore create mode 100644 vendor/github.com/kubernetes-csi/csi-test/.travis.yml create mode 100644 vendor/github.com/kubernetes-csi/csi-test/Dockerfile.mock create mode 100644 vendor/github.com/kubernetes-csi/csi-test/Gopkg.lock create mode 100644 vendor/github.com/kubernetes-csi/csi-test/Gopkg.toml create mode 100644 vendor/github.com/kubernetes-csi/csi-test/LICENSE create mode 100644 vendor/github.com/kubernetes-csi/csi-test/Makefile create mode 100644 vendor/github.com/kubernetes-csi/csi-test/OWNERS create mode 100644 vendor/github.com/kubernetes-csi/csi-test/README.md create mode 100644 vendor/github.com/kubernetes-csi/csi-test/SECURITY_CONTACTS create mode 100644 vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/Makefile create mode 100644 vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/README.md create mode 100644 vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/sanity_test.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/code-of-conduct.md create mode 100644 vendor/github.com/kubernetes-csi/csi-test/driver/driver.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/driver/driver.mock.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/driver/mock.go create mode 100755 vendor/github.com/kubernetes-csi/csi-test/hack/e2e.sh create mode 100644 vendor/github.com/kubernetes-csi/csi-test/mock/AUTHORS create mode 100644 vendor/github.com/kubernetes-csi/csi-test/mock/README.md create mode 100644 vendor/github.com/kubernetes-csi/csi-test/mock/cache/SnapshotCache.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/mock/main.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/mock/mocksecret.yaml create mode 100644 vendor/github.com/kubernetes-csi/csi-test/mock/service/controller.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/mock/service/identity.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/mock/service/node.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/mock/service/service.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/README.md create mode 100644 vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/cleanup.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/controller.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/identity.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/node.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/sanity.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/tests.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/test/co_test.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/test/driver_test.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/utils/grpcutil.go create mode 100644 vendor/github.com/kubernetes-csi/csi-test/utils/safegoroutinetester.go diff --git a/Gopkg.lock b/Gopkg.lock index b79ba8e1..fb13ef79 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,202 +2,279 @@ [[projects]] + digest = "1:8e47871087b94913898333f37af26732faaab30cdb41571136cf7aec9921dae7" name = "github.com/PuerkitoBio/purell" packages = ["."] + pruneopts = "" revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4" version = "v1.1.0" [[projects]] branch = "master" + digest = "1:331a419049c2be691e5ba1d24342fc77c7e767a80c666a18fd8a9f7b82419c1c" name = "github.com/PuerkitoBio/urlesc" packages = ["."] + pruneopts = "" revision = "de5bf2ad457846296e2031421a34e2568e304e35" [[projects]] + digest = "1:cf4f5171128e62b46299b0a7cd79543f50e62f483d2ca9364e4957c7bbee7a38" name = "github.com/container-storage-interface/spec" packages = ["lib/go/csi/v0"] + pruneopts = "" revision = "2178fdeea87f1150a17a63252eee28d4d8141f72" version = "v0.3.0" [[projects]] + digest = "1:56c130d885a4aacae1dd9c7b71cfe39912c7ebc1ff7d2b46083c8812996dc43b" name = "github.com/davecgh/go-spew" packages = ["spew"] + pruneopts = "" revision = "346938d642f2ec3594ed81d874461961cd0faa76" version = "v1.1.0" [[projects]] + digest = "1:8a34d7a37b8f07239487752e14a5faafcbbc718fc385ad429a2c4ac6f27a207f" name = "github.com/emicklei/go-restful" packages = [ ".", - "log" + "log", ] + pruneopts = "" revision = "3eb9738c1697594ea6e71a7156a9bb32ed216cf0" version = "v2.8.0" [[projects]] + digest = "1:b13707423743d41665fd23f0c36b2f37bb49c30e94adb813319c44188a51ba22" name = "github.com/ghodss/yaml" packages = ["."] + pruneopts = "" revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" version = "v1.0.0" [[projects]] + digest = "1:e116a4866bffeec941056a1fcfd37e520fad1ee60e4e3579719f19a43c392e10" name = "github.com/go-openapi/jsonpointer" packages = ["."] + pruneopts = "" revision = "3a0015ad55fa9873f41605d3e8f28cd279c32ab2" version = "0.15.0" [[projects]] + digest = "1:3830527ef0f4f9b268d9286661c0f52f9115f8aefd9f45ee7352516f93489ac9" name = "github.com/go-openapi/jsonreference" packages = ["."] + pruneopts = "" revision = "3fb327e6747da3043567ee86abd02bb6376b6be2" version = "0.15.0" [[projects]] + digest = "1:6caee195f5da296689270037c5a25c0bc3cc6e54ae5a356e395aa8946356dbc9" name = "github.com/go-openapi/spec" packages = ["."] + pruneopts = "" revision = "bce47c9386f9ecd6b86f450478a80103c3fe1402" version = "0.15.0" [[projects]] + digest = "1:22da48dbccb0539f511efbbbdeba68081866892234e57a9d7c7f9848168ae30c" name = "github.com/go-openapi/swag" packages = ["."] + pruneopts = "" revision = "2b0bd4f193d011c203529df626a65d63cb8a79e8" version = "0.15.0" [[projects]] + digest = "1:0a3f6a0c68ab8f3d455f8892295503b179e571b7fefe47cc6c556405d1f83411" name = "github.com/gogo/protobuf" packages = [ "proto", - "sortkeys" + "sortkeys", ] + pruneopts = "" revision = "1adfc126b41513cc696b209667c8656ea7aac67c" version = "v1.0.0" [[projects]] branch = "master" + digest = "1:107b233e45174dbab5b1324201d092ea9448e58243ab9f039e4c0f332e121e3a" name = "github.com/golang/glog" packages = ["."] + pruneopts = "" revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998" [[projects]] branch = "master" + digest = "1:b7677b91b9250563c6851dd5f2d8083972188bfe4f8fb7b61489a2f832f19b11" name = "github.com/golang/groupcache" packages = ["lru"] + pruneopts = "" revision = "66deaeb636dff1ac7d938ce666d090556056a4b0" [[projects]] + digest = "1:73a7106c799f98af4f3da7552906efc6a2570329f4cd2d2f5fb8f9d6c053ff2f" + name = "github.com/golang/mock" + packages = ["gomock"] + pruneopts = "" + revision = "c34cdb4725f4c3844d095133c6e40e448b86589b" + version = "v1.1.1" + +[[projects]] + digest = "1:f958a1c137db276e52f0b50efee41a1a389dcdded59a69711f3e872757dab34b" name = "github.com/golang/protobuf" packages = [ "proto", + "protoc-gen-go/descriptor", "ptypes", "ptypes/any", "ptypes/duration", "ptypes/timestamp", - "ptypes/wrappers" + "ptypes/wrappers", ] + pruneopts = "" revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" version = "v1.1.0" [[projects]] branch = "master" + digest = "1:be28c0531a755f2178acf1e327e6f5a8a3968feb5f2567cdc968064253141751" name = "github.com/google/btree" packages = ["."] + pruneopts = "" revision = "e89373fe6b4a7413d7acd6da1725b83ef713e6e4" [[projects]] branch = "master" + digest = "1:754f77e9c839b24778a4b64422236d38515301d2baeb63113aa3edc42e6af692" name = "github.com/google/gofuzz" packages = ["."] + pruneopts = "" revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" [[projects]] + digest = "1:2a131706ff80636629ab6373f2944569b8252ecc018cda8040931b05d32e3c16" name = "github.com/googleapis/gnostic" packages = [ "OpenAPIv2", "compiler", - "extensions" + "extensions", ] + pruneopts = "" revision = "ee43cbb60db7bd22502942cccbc39059117352ab" version = "v0.1.0" [[projects]] branch = "master" + digest = "1:009a1928b8c096338b68b5822d838a72b4d8520715c1463614476359f3282ec8" name = "github.com/gregjones/httpcache" packages = [ ".", - "diskcache" + "diskcache", ] + pruneopts = "" revision = "9cad4c3443a7200dd6400aef47183728de563a38" [[projects]] branch = "master" + digest = "1:9c776d7d9c54b7ed89f119e449983c3f24c0023e75001d6092442412ebca6b94" name = "github.com/hashicorp/golang-lru" packages = [ ".", - "simplelru" + "simplelru", ] + pruneopts = "" revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3" [[projects]] + digest = "1:23bc0b496ba341c6e3ba24d6358ff4a40a704d9eb5f9a3bd8e8fbd57ad869013" name = "github.com/imdario/mergo" packages = ["."] + pruneopts = "" revision = "163f41321a19dd09362d4c63cc2489db2015f1f4" version = "0.3.2" [[projects]] + digest = "1:53ac4e911e12dde0ab68655e2006449d207a5a681f084974da2b06e5dbeaca72" name = "github.com/json-iterator/go" packages = ["."] + pruneopts = "" revision = "ab8a2e0c74be9d3be70b3184d9acc634935ded82" version = "1.1.4" [[projects]] branch = "master" + digest = "1:6a0b17f72d5b3f5d5edc905a3ece920ec0eb368fe0ad59499b6db2624421b460" + name = "github.com/kubernetes-csi/csi-test" + packages = [ + "driver", + "utils", + ] + pruneopts = "" + revision = "e11d328ecca7fe91939284a8e878ebe77df8756d" + +[[projects]] + branch = "master" + digest = "1:d9e483f4b9e306facf126bd90b02d512bd22ea4471e1568867e32221a8abbb16" name = "github.com/mailru/easyjson" packages = [ "buffer", "jlexer", - "jwriter" + "jwriter", ] + pruneopts = "" revision = "3fdea8d05856a0c8df22ed4bc71b3219245e4485" [[projects]] + digest = "1:76a22f13ffa6d5d0b91beecdcec5c7651a42d3c5fcc12757e578808826fe4b0a" name = "github.com/modern-go/concurrent" packages = ["."] + pruneopts = "" revision = "938152ca6a933f501bb238954eebd3cbcbf489ff" version = "1.0.2" [[projects]] + digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855" name = "github.com/modern-go/reflect2" packages = ["."] + pruneopts = "" revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" version = "1.0.1" [[projects]] branch = "master" + digest = "1:c24598ffeadd2762552269271b3b1510df2d83ee6696c1e543a0ff653af494bc" name = "github.com/petar/GoLLRB" packages = ["llrb"] + pruneopts = "" revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" [[projects]] + digest = "1:b46305723171710475f2dd37547edd57b67b9de9f2a6267cafdd98331fd6897f" name = "github.com/peterbourgon/diskv" packages = ["."] + pruneopts = "" revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" version = "v2.0.1" [[projects]] + digest = "1:261bc565833ef4f02121450d74eb88d5ae4bd74bfe5d0e862cddb8550ec35000" name = "github.com/spf13/pflag" packages = ["."] + pruneopts = "" revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66" version = "v1.0.0" [[projects]] branch = "master" + digest = "1:79b763a59bc081a752605854f75ac04d4b8fba22bab9bbb11689efd2de255864" name = "golang.org/x/crypto" packages = ["ssh/terminal"] + pruneopts = "" revision = "91a49db82a88618983a78a06c1cbd4e00ab749ab" [[projects]] branch = "master" + digest = "1:4a65e28058fde372f1febbf1bca01ee4aed7472569fd1bc81db9e91bf105f7c8" name = "golang.org/x/net" packages = [ "context", @@ -206,20 +283,24 @@ "idna", "internal/timeseries", "lex/httplex", - "trace" + "trace", ] + pruneopts = "" revision = "22ae77b79946ea320088417e4d50825671d82d57" [[projects]] branch = "master" + digest = "1:0a0c73aced706c77f4f128971976b0ee94db7bdcc95b6088bda9e72594598634" name = "golang.org/x/sys" packages = [ "unix", - "windows" + "windows", ] + pruneopts = "" revision = "dd2ff4accc098aceecb86b36eaa7829b2a17b1c9" [[projects]] + digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4" name = "golang.org/x/text" packages = [ "collate", @@ -236,34 +317,42 @@ "unicode/cldr", "unicode/norm", "unicode/rangetable", - "width" + "width", ] + pruneopts = "" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] branch = "master" + digest = "1:55a681cb66f28755765fa5fa5104cbd8dc85c55c02d206f9f89566451e3fe1aa" name = "golang.org/x/time" packages = ["rate"] + pruneopts = "" revision = "fbb02b2291d28baffd63558aa44b4b56f178d650" [[projects]] branch = "master" + digest = "1:b3123d1f332e4536a69174a97ae8333cfef1ef502942a9d956dee761314b44c9" name = "golang.org/x/tools" packages = [ "go/ast/astutil", "imports", - "internal/fastwalk" + "internal/fastwalk", ] + pruneopts = "" revision = "2087f8c10712366cfc2f4fcb1bf99eeef61ab21e" [[projects]] branch = "master" + digest = "1:02b227168a215a14f7f16af45ca649b7c1efc33919ce27a03996dfb54dcf556c" name = "google.golang.org/genproto" packages = ["googleapis/rpc/status"] + pruneopts = "" revision = "2c5e7ac708aaa719366570dd82bda44541ca2a63" [[projects]] + digest = "1:d2dc833c73202298c92b63a7e180e2b007b5a3c3c763e3b9fe1da249b5c7f5b9" name = "google.golang.org/grpc" packages = [ ".", @@ -282,30 +371,38 @@ "metadata", "naming", "peer", + "reflection", + "reflection/grpc_reflection_v1alpha", "resolver", "resolver/dns", "resolver/passthrough", "stats", "status", "tap", - "transport" + "transport", ] + pruneopts = "" revision = "8e4536a86ab602859c20df5ebfd0bd4228d08655" version = "v1.10.0" [[projects]] + digest = "1:e5d1fb981765b6f7513f793a3fcaac7158408cca77f75f7311ac82cc88e9c445" name = "gopkg.in/inf.v0" packages = ["."] + pruneopts = "" revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4" version = "v0.9.0" [[projects]] + digest = "1:5fe876313b07628905b2181e537faabe45032cb9c79c01b49b51c25a0a40040d" name = "gopkg.in/yaml.v2" packages = ["."] + pruneopts = "" revision = "7f97868eec74b32b0982dd158a51a446d1da7eb5" version = "v2.1.1" [[projects]] + digest = "1:f420c8548c93242d8e5dcfa5b34e0243883b4e660f65076e869daafac877144d" name = "k8s.io/api" packages = [ "admissionregistration/v1alpha1", @@ -336,25 +433,28 @@ "settings/v1alpha1", "storage/v1", "storage/v1alpha1", - "storage/v1beta1" + "storage/v1beta1", ] + pruneopts = "" revision = "072894a440bdee3a891dea811fe42902311cd2a3" version = "kubernetes-1.11.0" [[projects]] branch = "master" + digest = "1:3f17b5076dfd753cc5f4f21e4d569ed2e94b3a4ff3965874582939afb85ab6f1" name = "k8s.io/apiextensions-apiserver" packages = [ "pkg/apis/apiextensions", "pkg/apis/apiextensions/v1beta1", "pkg/client/clientset/clientset", "pkg/client/clientset/clientset/scheme", - "pkg/client/clientset/clientset/typed/apiextensions/v1beta1" + "pkg/client/clientset/clientset/typed/apiextensions/v1beta1", ] + pruneopts = "" revision = "29a2b5e2b48eeaba42bba7d57afe9414f1e9e40a" [[projects]] - branch = "release-1.11" + digest = "1:b6b2fb7b4da1ac973b64534ace2299a02504f16bc7820cb48edb8ca4077183e1" name = "k8s.io/apimachinery" packages = [ "pkg/api/errors", @@ -397,45 +497,79 @@ "pkg/version", "pkg/watch", "third_party/forked/golang/json", - "third_party/forked/golang/reflect" + "third_party/forked/golang/reflect", ] + pruneopts = "" revision = "103fd098999dc9c0c88536f5c9ad2e5da39373ae" + version = "kubernetes-1.11.0" [[projects]] + digest = "1:d04779a8de7d5465e0463bd986506348de5e89677c74777f695d3145a7a8d15e" name = "k8s.io/client-go" packages = [ "discovery", + "discovery/fake", "kubernetes", + "kubernetes/fake", "kubernetes/scheme", "kubernetes/typed/admissionregistration/v1alpha1", + "kubernetes/typed/admissionregistration/v1alpha1/fake", "kubernetes/typed/admissionregistration/v1beta1", + "kubernetes/typed/admissionregistration/v1beta1/fake", "kubernetes/typed/apps/v1", + "kubernetes/typed/apps/v1/fake", "kubernetes/typed/apps/v1beta1", + "kubernetes/typed/apps/v1beta1/fake", "kubernetes/typed/apps/v1beta2", + "kubernetes/typed/apps/v1beta2/fake", "kubernetes/typed/authentication/v1", + "kubernetes/typed/authentication/v1/fake", "kubernetes/typed/authentication/v1beta1", + "kubernetes/typed/authentication/v1beta1/fake", "kubernetes/typed/authorization/v1", + "kubernetes/typed/authorization/v1/fake", "kubernetes/typed/authorization/v1beta1", + "kubernetes/typed/authorization/v1beta1/fake", "kubernetes/typed/autoscaling/v1", + "kubernetes/typed/autoscaling/v1/fake", "kubernetes/typed/autoscaling/v2beta1", + "kubernetes/typed/autoscaling/v2beta1/fake", "kubernetes/typed/batch/v1", + "kubernetes/typed/batch/v1/fake", "kubernetes/typed/batch/v1beta1", + "kubernetes/typed/batch/v1beta1/fake", "kubernetes/typed/batch/v2alpha1", + "kubernetes/typed/batch/v2alpha1/fake", "kubernetes/typed/certificates/v1beta1", + "kubernetes/typed/certificates/v1beta1/fake", "kubernetes/typed/core/v1", + "kubernetes/typed/core/v1/fake", "kubernetes/typed/events/v1beta1", + "kubernetes/typed/events/v1beta1/fake", "kubernetes/typed/extensions/v1beta1", + "kubernetes/typed/extensions/v1beta1/fake", "kubernetes/typed/networking/v1", + "kubernetes/typed/networking/v1/fake", "kubernetes/typed/policy/v1beta1", + "kubernetes/typed/policy/v1beta1/fake", "kubernetes/typed/rbac/v1", + "kubernetes/typed/rbac/v1/fake", "kubernetes/typed/rbac/v1alpha1", + "kubernetes/typed/rbac/v1alpha1/fake", "kubernetes/typed/rbac/v1beta1", + "kubernetes/typed/rbac/v1beta1/fake", "kubernetes/typed/scheduling/v1alpha1", + "kubernetes/typed/scheduling/v1alpha1/fake", "kubernetes/typed/scheduling/v1beta1", + "kubernetes/typed/scheduling/v1beta1/fake", "kubernetes/typed/settings/v1alpha1", + "kubernetes/typed/settings/v1alpha1/fake", "kubernetes/typed/storage/v1", + "kubernetes/typed/storage/v1/fake", "kubernetes/typed/storage/v1alpha1", + "kubernetes/typed/storage/v1alpha1/fake", "kubernetes/typed/storage/v1beta1", + "kubernetes/typed/storage/v1beta1/fake", "pkg/apis/clientauthentication", "pkg/apis/clientauthentication/v1alpha1", "pkg/apis/clientauthentication/v1beta1", @@ -443,6 +577,7 @@ "plugin/pkg/client/auth/exec", "rest", "rest/watch", + "testing", "tools/auth", "tools/cache", "tools/clientcmd", @@ -461,13 +596,14 @@ "util/homedir", "util/integer", "util/retry", - "util/workqueue" + "util/workqueue", ] + pruneopts = "" revision = "7d04d0e2a0a1a4d4a1cd6baa432a2301492e4e65" - version = "v8.0.0" + version = "kubernetes-1.11.0" [[projects]] - branch = "release-1.11" + digest = "1:43ef9a37919f7a8948b7de4c05d20692f763adc40f15c9d330c544ae05d93947" name = "k8s.io/code-generator" packages = [ "cmd/client-gen", @@ -490,12 +626,15 @@ "cmd/lister-gen/generators", "cmd/openapi-gen", "cmd/openapi-gen/args", - "pkg/util" + "pkg/util", ] + pruneopts = "" revision = "6702109cc68eb6fe6350b83e14407c8d7309fd1a" + version = "kubernetes-1.11.0" [[projects]] branch = "master" + digest = "1:f3ce5a03c50cf794f17d331fa9d8741db6fd8aeb5ec07d2a68eb039619f22967" name = "k8s.io/gengo" packages = [ "args", @@ -505,32 +644,87 @@ "generator", "namer", "parser", - "types" + "types", ] + pruneopts = "" revision = "fdcf9f9480fdd5bf2b3c3df9bf4ecd22b25b87e2" [[projects]] branch = "master" + digest = "1:9a648ff9eb89673d2870c22fc011ec5db0fcff6c4e5174a650298e51be71bbf1" name = "k8s.io/kube-openapi" packages = [ "pkg/common", "pkg/generators", - "pkg/util/proto" + "pkg/util/proto", ] + pruneopts = "" revision = "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf" [[projects]] + digest = "1:f76bd44abec76c842b33c3ba178ace57cc5573307abd77d213d7da31fae912f5" name = "k8s.io/kubernetes" packages = [ "pkg/util/goroutinemap", - "pkg/util/goroutinemap/exponentialbackoff" + "pkg/util/goroutinemap/exponentialbackoff", ] + pruneopts = "" revision = "91e7b4fd31fcd3d5f436da26c980becec37ceefe" version = "v1.11.0" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "27055a9cf740d1ee42333652c277f01bf1b3de28cae6a62a6dcca2fa6aed9713" + input-imports = [ + "github.com/container-storage-interface/spec/lib/go/csi/v0", + "github.com/golang/glog", + "github.com/golang/mock/gomock", + "github.com/kubernetes-csi/csi-test/driver", + "google.golang.org/grpc", + "google.golang.org/grpc/codes", + "google.golang.org/grpc/connectivity", + "google.golang.org/grpc/status", + "k8s.io/api/core/v1", + "k8s.io/api/storage/v1", + "k8s.io/api/storage/v1beta1", + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1", + "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset", + "k8s.io/apimachinery/pkg/api/errors", + "k8s.io/apimachinery/pkg/api/meta", + "k8s.io/apimachinery/pkg/api/resource", + "k8s.io/apimachinery/pkg/apis/meta/v1", + "k8s.io/apimachinery/pkg/labels", + "k8s.io/apimachinery/pkg/runtime", + "k8s.io/apimachinery/pkg/runtime/schema", + "k8s.io/apimachinery/pkg/runtime/serializer", + "k8s.io/apimachinery/pkg/types", + "k8s.io/apimachinery/pkg/util/diff", + "k8s.io/apimachinery/pkg/util/sets", + "k8s.io/apimachinery/pkg/util/validation", + "k8s.io/apimachinery/pkg/util/wait", + "k8s.io/apimachinery/pkg/watch", + "k8s.io/client-go/discovery", + "k8s.io/client-go/discovery/fake", + "k8s.io/client-go/kubernetes", + "k8s.io/client-go/kubernetes/fake", + "k8s.io/client-go/kubernetes/scheme", + "k8s.io/client-go/kubernetes/typed/core/v1", + "k8s.io/client-go/rest", + "k8s.io/client-go/testing", + "k8s.io/client-go/tools/cache", + "k8s.io/client-go/tools/clientcmd", + "k8s.io/client-go/tools/record", + "k8s.io/client-go/tools/reference", + "k8s.io/client-go/util/flowcontrol", + "k8s.io/client-go/util/workqueue", + "k8s.io/code-generator/cmd/client-gen", + "k8s.io/code-generator/cmd/deepcopy-gen", + "k8s.io/code-generator/cmd/defaulter-gen", + "k8s.io/code-generator/cmd/informer-gen", + "k8s.io/code-generator/cmd/lister-gen", + "k8s.io/code-generator/cmd/openapi-gen", + "k8s.io/kubernetes/pkg/util/goroutinemap", + "k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/vendor/github.com/golang/mock/.gitignore b/vendor/github.com/golang/mock/.gitignore new file mode 100644 index 00000000..4eb2f795 --- /dev/null +++ b/vendor/github.com/golang/mock/.gitignore @@ -0,0 +1,17 @@ +# Object files and binaries from go. +*.[568] + +# Library files. +*.a + +# Any file prefixed by an underscore. +*/_* + +# Vim temporary files. +.*.swp + +# The mockgen binary. +mockgen/mockgen + +# A binary produced by gotest. +#gomock/[568]\.out diff --git a/vendor/github.com/golang/mock/.travis.yml b/vendor/github.com/golang/mock/.travis.yml new file mode 100644 index 00000000..1b89c05f --- /dev/null +++ b/vendor/github.com/golang/mock/.travis.yml @@ -0,0 +1,14 @@ +language: go + +go: + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x + +script: + - go build ./... + - go install github.com/golang/mock/mockgen + - ./ci/check_go_fmt.sh + - ./ci/check_go_generate.sh + - go test -v ./... diff --git a/vendor/github.com/golang/mock/AUTHORS b/vendor/github.com/golang/mock/AUTHORS new file mode 100644 index 00000000..660b8ccc --- /dev/null +++ b/vendor/github.com/golang/mock/AUTHORS @@ -0,0 +1,12 @@ +# This is the official list of GoMock authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as +# Name or Organization +# The email address is not required for organizations. + +# Please keep the list sorted. + +Alex Reece +Google Inc. diff --git a/vendor/github.com/golang/mock/CONTRIBUTORS b/vendor/github.com/golang/mock/CONTRIBUTORS new file mode 100644 index 00000000..def849ca --- /dev/null +++ b/vendor/github.com/golang/mock/CONTRIBUTORS @@ -0,0 +1,37 @@ +# This is the official list of people who can contribute (and typically +# have contributed) code to the gomock repository. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# The submission process automatically checks to make sure +# that people submitting code are listed in this file (by email address). +# +# Names should be added to this file only after verifying that +# the individual or the individual's organization has agreed to +# the appropriate Contributor License Agreement, found here: +# +# http://code.google.com/legal/individual-cla-v1.0.html +# http://code.google.com/legal/corporate-cla-v1.0.html +# +# The agreement for individuals can be filled out on the web. +# +# When adding J Random Contributor's name to this file, +# either J's name or J's organization's name should be +# added to the AUTHORS file, depending on whether the +# individual or corporate CLA was used. + +# Names should be added to this file like so: +# Name +# +# An entry with two email addresses specifies that the +# first address should be used in the submit logs and +# that the second address should be recognized as the +# same person when interacting with Rietveld. + +# Please keep the list sorted. + +Aaron Jacobs +Alex Reece +David Symonds +Ryan Barrett diff --git a/vendor/github.com/golang/mock/LICENSE b/vendor/github.com/golang/mock/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/vendor/github.com/golang/mock/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/golang/mock/README.md b/vendor/github.com/golang/mock/README.md new file mode 100644 index 00000000..e4387779 --- /dev/null +++ b/vendor/github.com/golang/mock/README.md @@ -0,0 +1,94 @@ +gomock [![Build Status](https://travis-ci.org/golang/mock.svg?branch=master)](https://travis-ci.org/golang/mock) +====== + +GoMock is a mocking framework for the [Go programming language][golang]. It +integrates well with Go's built-in `testing` package, but can be used in other +contexts too. + + +Installation +------------ + +Once you have [installed Go][golang-install], run these commands +to install the `gomock` package and the `mockgen` tool: + + go get github.com/golang/mock/gomock + go get github.com/golang/mock/mockgen + + +Documentation +------------- + +After installing, you can use `go doc` to get documentation: + + go doc github.com/golang/mock/gomock + +Alternatively, there is an online reference for the package hosted on GoPkgDoc +[here][gomock-ref]. + + +Running mockgen +--------------- + +`mockgen` has two modes of operation: source and reflect. +Source mode generates mock interfaces from a source file. +It is enabled by using the -source flag. Other flags that +may be useful in this mode are -imports and -aux_files. + +Example: + + mockgen -source=foo.go [other options] + +Reflect mode generates mock interfaces by building a program +that uses reflection to understand interfaces. It is enabled +by passing two non-flag arguments: an import path, and a +comma-separated list of symbols. + +Example: + + mockgen database/sql/driver Conn,Driver + +The `mockgen` command is used to generate source code for a mock +class given a Go source file containing interfaces to be mocked. +It supports the following flags: + + * `-source`: A file containing interfaces to be mocked. + + * `-destination`: A file to which to write the resulting source code. If you + don't set this, the code is printed to standard output. + + * `-package`: The package to use for the resulting mock class + source code. If you don't set this, the package name is `mock_` concatenated + with the package of the input file. + + * `-imports`: A list of explicit imports that should be used in the resulting + source code, specified as a comma-separated list of elements of the form + `foo=bar/baz`, where `bar/baz` is the package being imported and `foo` is + the identifier to use for the package in the generated source code. + + * `-aux_files`: A list of additional files that should be consulted to + resolve e.g. embedded interfaces defined in a different file. This is + specified as a comma-separated list of elements of the form + `foo=bar/baz.go`, where `bar/baz.go` is the source file and `foo` is the + package name of that file used by the -source file. + +* `-build_flags`: (reflect mode only) Flags passed verbatim to `go build`. + +* `-mock_names`: A list of custom names for generated mocks. This is specified + as a comma-separated list of elements of the form + `Repository=MockSensorRepository,Endpoint=MockSensorEndpoint`, where + `Repository` is the interface name and `MockSensorRepository` is the desired + mock name (mock factory method and mock recorder will be named after the mock). + If one of the interfaces has no custom name specified, then default naming + convention will be used. + +For an example of the use of `mockgen`, see the `sample/` directory. In simple +cases, you will need only the `-source` flag. + + +TODO: Brief overview of how to create mock objects and set up expectations, and +an example. + +[golang]: http://golang.org/ +[golang-install]: http://golang.org/doc/install.html#releases +[gomock-ref]: http://godoc.org/github.com/golang/mock/gomock diff --git a/vendor/github.com/golang/mock/ci/check_go_fmt.sh b/vendor/github.com/golang/mock/ci/check_go_fmt.sh new file mode 100755 index 00000000..ae4028ac --- /dev/null +++ b/vendor/github.com/golang/mock/ci/check_go_fmt.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# This script is used by the CI to check if the code is gofmt formatted. + +set -euo pipefail + +GOFMT_DIFF=$(IFS=$'\n'; gofmt -d $( find . -type f -name '*.go' ) ) +if [[ -n "${GOFMT_DIFF}" ]]; then + echo "${GOFMT_DIFF}" + echo + echo "The go source files aren't gofmt formatted." + exit 1 +fi diff --git a/vendor/github.com/golang/mock/ci/check_go_generate.sh b/vendor/github.com/golang/mock/ci/check_go_generate.sh new file mode 100755 index 00000000..a0212e28 --- /dev/null +++ b/vendor/github.com/golang/mock/ci/check_go_generate.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# This script is used by the CI to check if 'go generate ./...' is up to date. +# +# Note: If the generated files aren't up to date then this script updates +# them despite printing an error message so running it the second time +# might not print any errors. This isn't very useful locally during development +# but it works well with the CI that downloads a fresh version of the repo +# each time before executing this script. + +set -euo pipefail + +TEMP_DIR=$( mktemp -d ) +function cleanup() { + rm -rf "${TEMP_DIR}" +} +trap cleanup EXIT + +cp -r . "${TEMP_DIR}/" +go generate ./... +if ! diff -r . "${TEMP_DIR}"; then + echo + echo "The generated files aren't up to date." + echo "Update them with the 'go generate ./...' command." + exit 1 +fi diff --git a/vendor/github.com/golang/mock/gomock/call.go b/vendor/github.com/golang/mock/gomock/call.go new file mode 100644 index 00000000..a3fa1ae4 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/call.go @@ -0,0 +1,428 @@ +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock + +import ( + "fmt" + "reflect" + "strconv" + "strings" +) + +// Call represents an expected call to a mock. +type Call struct { + t TestReporter // for triggering test failures on invalid call setup + + receiver interface{} // the receiver of the method call + method string // the name of the method + methodType reflect.Type // the type of the method + args []Matcher // the args + origin string // file and line number of call setup + + preReqs []*Call // prerequisite calls + + // Expectations + minCalls, maxCalls int + + numCalls int // actual number made + + // actions are called when this Call is called. Each action gets the args and + // can set the return values by returning a non-nil slice. Actions run in the + // order they are created. + actions []func([]interface{}) []interface{} +} + +// newCall creates a *Call. It requires the method type in order to support +// unexported methods. +func newCall(t TestReporter, receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call { + if h, ok := t.(testHelper); ok { + h.Helper() + } + + // TODO: check arity, types. + margs := make([]Matcher, len(args)) + for i, arg := range args { + if m, ok := arg.(Matcher); ok { + margs[i] = m + } else if arg == nil { + // Handle nil specially so that passing a nil interface value + // will match the typed nils of concrete args. + margs[i] = Nil() + } else { + margs[i] = Eq(arg) + } + } + + origin := callerInfo(3) + actions := []func([]interface{}) []interface{}{func([]interface{}) []interface{} { + // Synthesize the zero value for each of the return args' types. + rets := make([]interface{}, methodType.NumOut()) + for i := 0; i < methodType.NumOut(); i++ { + rets[i] = reflect.Zero(methodType.Out(i)).Interface() + } + return rets + }} + return &Call{t: t, receiver: receiver, method: method, methodType: methodType, + args: margs, origin: origin, minCalls: 1, maxCalls: 1, actions: actions} +} + +// AnyTimes allows the expectation to be called 0 or more times +func (c *Call) AnyTimes() *Call { + c.minCalls, c.maxCalls = 0, 1e8 // close enough to infinity + return c +} + +// MinTimes requires the call to occur at least n times. If AnyTimes or MaxTimes have not been called, MinTimes also +// sets the maximum number of calls to infinity. +func (c *Call) MinTimes(n int) *Call { + c.minCalls = n + if c.maxCalls == 1 { + c.maxCalls = 1e8 + } + return c +} + +// MaxTimes limits the number of calls to n times. If AnyTimes or MinTimes have not been called, MaxTimes also +// sets the minimum number of calls to 0. +func (c *Call) MaxTimes(n int) *Call { + c.maxCalls = n + if c.minCalls == 1 { + c.minCalls = 0 + } + return c +} + +// DoAndReturn declares the action to run when the call is matched. +// The return values from this function are returned by the mocked function. +// It takes an interface{} argument to support n-arity functions. +func (c *Call) DoAndReturn(f interface{}) *Call { + // TODO: Check arity and types here, rather than dying badly elsewhere. + v := reflect.ValueOf(f) + + c.addAction(func(args []interface{}) []interface{} { + vargs := make([]reflect.Value, len(args)) + ft := v.Type() + for i := 0; i < len(args); i++ { + if args[i] != nil { + vargs[i] = reflect.ValueOf(args[i]) + } else { + // Use the zero value for the arg. + vargs[i] = reflect.Zero(ft.In(i)) + } + } + vrets := v.Call(vargs) + rets := make([]interface{}, len(vrets)) + for i, ret := range vrets { + rets[i] = ret.Interface() + } + return rets + }) + return c +} + +// Do declares the action to run when the call is matched. The function's +// return values are ignored to retain backward compatibility. To use the +// return values call DoAndReturn. +// It takes an interface{} argument to support n-arity functions. +func (c *Call) Do(f interface{}) *Call { + // TODO: Check arity and types here, rather than dying badly elsewhere. + v := reflect.ValueOf(f) + + c.addAction(func(args []interface{}) []interface{} { + vargs := make([]reflect.Value, len(args)) + ft := v.Type() + for i := 0; i < len(args); i++ { + if args[i] != nil { + vargs[i] = reflect.ValueOf(args[i]) + } else { + // Use the zero value for the arg. + vargs[i] = reflect.Zero(ft.In(i)) + } + } + v.Call(vargs) + return nil + }) + return c +} + +// Return declares the values to be returned by the mocked function call. +func (c *Call) Return(rets ...interface{}) *Call { + if h, ok := c.t.(testHelper); ok { + h.Helper() + } + + mt := c.methodType + if len(rets) != mt.NumOut() { + c.t.Fatalf("wrong number of arguments to Return for %T.%v: got %d, want %d [%s]", + c.receiver, c.method, len(rets), mt.NumOut(), c.origin) + } + for i, ret := range rets { + if got, want := reflect.TypeOf(ret), mt.Out(i); got == want { + // Identical types; nothing to do. + } else if got == nil { + // Nil needs special handling. + switch want.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + // ok + default: + c.t.Fatalf("argument %d to Return for %T.%v is nil, but %v is not nillable [%s]", + i, c.receiver, c.method, want, c.origin) + } + } else if got.AssignableTo(want) { + // Assignable type relation. Make the assignment now so that the generated code + // can return the values with a type assertion. + v := reflect.New(want).Elem() + v.Set(reflect.ValueOf(ret)) + rets[i] = v.Interface() + } else { + c.t.Fatalf("wrong type of argument %d to Return for %T.%v: %v is not assignable to %v [%s]", + i, c.receiver, c.method, got, want, c.origin) + } + } + + c.addAction(func([]interface{}) []interface{} { + return rets + }) + + return c +} + +// Times declares the exact number of times a function call is expected to be executed. +func (c *Call) Times(n int) *Call { + c.minCalls, c.maxCalls = n, n + return c +} + +// SetArg declares an action that will set the nth argument's value, +// indirected through a pointer. Or, in the case of a slice, SetArg +// will copy value's elements into the nth argument. +func (c *Call) SetArg(n int, value interface{}) *Call { + if h, ok := c.t.(testHelper); ok { + h.Helper() + } + + mt := c.methodType + // TODO: This will break on variadic methods. + // We will need to check those at invocation time. + if n < 0 || n >= mt.NumIn() { + c.t.Fatalf("SetArg(%d, ...) called for a method with %d args [%s]", + n, mt.NumIn(), c.origin) + } + // Permit setting argument through an interface. + // In the interface case, we don't (nay, can't) check the type here. + at := mt.In(n) + switch at.Kind() { + case reflect.Ptr: + dt := at.Elem() + if vt := reflect.TypeOf(value); !vt.AssignableTo(dt) { + c.t.Fatalf("SetArg(%d, ...) argument is a %v, not assignable to %v [%s]", + n, vt, dt, c.origin) + } + case reflect.Interface: + // nothing to do + case reflect.Slice: + // nothing to do + default: + c.t.Fatalf("SetArg(%d, ...) referring to argument of non-pointer non-interface non-slice type %v [%s]", + n, at, c.origin) + } + + c.addAction(func(args []interface{}) []interface{} { + v := reflect.ValueOf(value) + switch reflect.TypeOf(args[n]).Kind() { + case reflect.Slice: + setSlice(args[n], v) + default: + reflect.ValueOf(args[n]).Elem().Set(v) + } + return nil + }) + return c +} + +// isPreReq returns true if other is a direct or indirect prerequisite to c. +func (c *Call) isPreReq(other *Call) bool { + for _, preReq := range c.preReqs { + if other == preReq || preReq.isPreReq(other) { + return true + } + } + return false +} + +// After declares that the call may only match after preReq has been exhausted. +func (c *Call) After(preReq *Call) *Call { + if h, ok := c.t.(testHelper); ok { + h.Helper() + } + + if c == preReq { + c.t.Fatalf("A call isn't allowed to be its own prerequisite") + } + if preReq.isPreReq(c) { + c.t.Fatalf("Loop in call order: %v is a prerequisite to %v (possibly indirectly).", c, preReq) + } + + c.preReqs = append(c.preReqs, preReq) + return c +} + +// Returns true if the minimum number of calls have been made. +func (c *Call) satisfied() bool { + return c.numCalls >= c.minCalls +} + +// Returns true iff the maximum number of calls have been made. +func (c *Call) exhausted() bool { + return c.numCalls >= c.maxCalls +} + +func (c *Call) String() string { + args := make([]string, len(c.args)) + for i, arg := range c.args { + args[i] = arg.String() + } + arguments := strings.Join(args, ", ") + return fmt.Sprintf("%T.%v(%s) %s", c.receiver, c.method, arguments, c.origin) +} + +// Tests if the given call matches the expected call. +// If yes, returns nil. If no, returns error with message explaining why it does not match. +func (c *Call) matches(args []interface{}) error { + if !c.methodType.IsVariadic() { + if len(args) != len(c.args) { + return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: %d", + c.origin, len(args), len(c.args)) + } + + for i, m := range c.args { + if !m.Matches(args[i]) { + return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", + c.origin, strconv.Itoa(i), args[i], m) + } + } + } else { + if len(c.args) < c.methodType.NumIn()-1 { + return fmt.Errorf("Expected call at %s has the wrong number of matchers. Got: %d, want: %d", + c.origin, len(c.args), c.methodType.NumIn()-1) + } + if len(c.args) != c.methodType.NumIn() && len(args) != len(c.args) { + return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: %d", + c.origin, len(args), len(c.args)) + } + if len(args) < len(c.args)-1 { + return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: greater than or equal to %d", + c.origin, len(args), len(c.args)-1) + } + + for i, m := range c.args { + if i < c.methodType.NumIn()-1 { + // Non-variadic args + if !m.Matches(args[i]) { + return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", + c.origin, strconv.Itoa(i), args[i], m) + } + continue + } + // The last arg has a possibility of a variadic argument, so let it branch + + // sample: Foo(a int, b int, c ...int) + if i < len(c.args) && i < len(args) { + if m.Matches(args[i]) { + // Got Foo(a, b, c) want Foo(matcherA, matcherB, gomock.Any()) + // Got Foo(a, b, c) want Foo(matcherA, matcherB, someSliceMatcher) + // Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC) + // Got Foo(a, b) want Foo(matcherA, matcherB) + // Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD) + continue + } + } + + // The number of actual args don't match the number of matchers, + // or the last matcher is a slice and the last arg is not. + // If this function still matches it is because the last matcher + // matches all the remaining arguments or the lack of any. + // Convert the remaining arguments, if any, into a slice of the + // expected type. + vargsType := c.methodType.In(c.methodType.NumIn() - 1) + vargs := reflect.MakeSlice(vargsType, 0, len(args)-i) + for _, arg := range args[i:] { + vargs = reflect.Append(vargs, reflect.ValueOf(arg)) + } + if m.Matches(vargs.Interface()) { + // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, gomock.Any()) + // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, someSliceMatcher) + // Got Foo(a, b) want Foo(matcherA, matcherB, gomock.Any()) + // Got Foo(a, b) want Foo(matcherA, matcherB, someEmptySliceMatcher) + break + } + // Wrong number of matchers or not match. Fail. + // Got Foo(a, b) want Foo(matcherA, matcherB, matcherC, matcherD) + // Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC, matcherD) + // Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD, matcherE) + // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, matcherC, matcherD) + // Got Foo(a, b, c) want Foo(matcherA, matcherB) + return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", + c.origin, strconv.Itoa(i), args[i:], c.args[i]) + + } + } + + // Check that all prerequisite calls have been satisfied. + for _, preReqCall := range c.preReqs { + if !preReqCall.satisfied() { + return fmt.Errorf("Expected call at %s doesn't have a prerequisite call satisfied:\n%v\nshould be called before:\n%v", + c.origin, preReqCall, c) + } + } + + // Check that the call is not exhausted. + if c.exhausted() { + return fmt.Errorf("Expected call at %s has already been called the max number of times.", c.origin) + } + + return nil +} + +// dropPrereqs tells the expected Call to not re-check prerequisite calls any +// longer, and to return its current set. +func (c *Call) dropPrereqs() (preReqs []*Call) { + preReqs = c.preReqs + c.preReqs = nil + return +} + +func (c *Call) call(args []interface{}) []func([]interface{}) []interface{} { + c.numCalls++ + return c.actions +} + +// InOrder declares that the given calls should occur in order. +func InOrder(calls ...*Call) { + for i := 1; i < len(calls); i++ { + calls[i].After(calls[i-1]) + } +} + +func setSlice(arg interface{}, v reflect.Value) { + va := reflect.ValueOf(arg) + for i := 0; i < v.Len(); i++ { + va.Index(i).Set(v.Index(i)) + } +} + +func (c *Call) addAction(action func([]interface{}) []interface{}) { + c.actions = append(c.actions, action) +} diff --git a/vendor/github.com/golang/mock/gomock/call_test.go b/vendor/github.com/golang/mock/gomock/call_test.go new file mode 100644 index 00000000..3a8315b3 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/call_test.go @@ -0,0 +1,51 @@ +package gomock + +import ( + "testing" +) + +type mockTestReporter struct { + errorCalls int + fatalCalls int +} + +func (o *mockTestReporter) Errorf(format string, args ...interface{}) { + o.errorCalls++ +} + +func (o *mockTestReporter) Fatalf(format string, args ...interface{}) { + o.fatalCalls++ +} + +func (o *mockTestReporter) Helper() {} + +func TestCall_After(t *testing.T) { + t.Run("SelfPrereqCallsFatalf", func(t *testing.T) { + tr1 := &mockTestReporter{} + + c := &Call{t: tr1} + c.After(c) + + if tr1.fatalCalls != 1 { + t.Errorf("number of fatal calls == %v, want 1", tr1.fatalCalls) + } + }) + + t.Run("LoopInCallOrderCallsFatalf", func(t *testing.T) { + tr1 := &mockTestReporter{} + tr2 := &mockTestReporter{} + + c1 := &Call{t: tr1} + c2 := &Call{t: tr2} + c1.After(c2) + c2.After(c1) + + if tr1.errorCalls != 0 || tr1.fatalCalls != 0 { + t.Error("unexpected errors") + } + + if tr2.fatalCalls != 1 { + t.Errorf("number of fatal calls == %v, want 1", tr2.fatalCalls) + } + }) +} diff --git a/vendor/github.com/golang/mock/gomock/callset.go b/vendor/github.com/golang/mock/gomock/callset.go new file mode 100644 index 00000000..c44a8a58 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/callset.go @@ -0,0 +1,108 @@ +// Copyright 2011 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock + +import ( + "bytes" + "fmt" +) + +// callSet represents a set of expected calls, indexed by receiver and method +// name. +type callSet struct { + // Calls that are still expected. + expected map[callSetKey][]*Call + // Calls that have been exhausted. + exhausted map[callSetKey][]*Call +} + +// callSetKey is the key in the maps in callSet +type callSetKey struct { + receiver interface{} + fname string +} + +func newCallSet() *callSet { + return &callSet{make(map[callSetKey][]*Call), make(map[callSetKey][]*Call)} +} + +// Add adds a new expected call. +func (cs callSet) Add(call *Call) { + key := callSetKey{call.receiver, call.method} + m := cs.expected + if call.exhausted() { + m = cs.exhausted + } + m[key] = append(m[key], call) +} + +// Remove removes an expected call. +func (cs callSet) Remove(call *Call) { + key := callSetKey{call.receiver, call.method} + calls := cs.expected[key] + for i, c := range calls { + if c == call { + // maintain order for remaining calls + cs.expected[key] = append(calls[:i], calls[i+1:]...) + cs.exhausted[key] = append(cs.exhausted[key], call) + break + } + } +} + +// FindMatch searches for a matching call. Returns error with explanation message if no call matched. +func (cs callSet) FindMatch(receiver interface{}, method string, args []interface{}) (*Call, error) { + key := callSetKey{receiver, method} + + // Search through the expected calls. + expected := cs.expected[key] + var callsErrors bytes.Buffer + for _, call := range expected { + err := call.matches(args) + if err != nil { + fmt.Fprintf(&callsErrors, "\n%v", err) + } else { + return call, nil + } + } + + // If we haven't found a match then search through the exhausted calls so we + // get useful error messages. + exhausted := cs.exhausted[key] + for _, call := range exhausted { + if err := call.matches(args); err != nil { + fmt.Fprintf(&callsErrors, "\n%v", err) + } + } + + if len(expected)+len(exhausted) == 0 { + fmt.Fprintf(&callsErrors, "there are no expected calls of the method %q for that receiver", method) + } + + return nil, fmt.Errorf(callsErrors.String()) +} + +// Failures returns the calls that are not satisfied. +func (cs callSet) Failures() []*Call { + failures := make([]*Call, 0, len(cs.expected)) + for _, calls := range cs.expected { + for _, call := range calls { + if !call.satisfied() { + failures = append(failures, call) + } + } + } + return failures +} diff --git a/vendor/github.com/golang/mock/gomock/callset_test.go b/vendor/github.com/golang/mock/gomock/callset_test.go new file mode 100644 index 00000000..7fc711a4 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/callset_test.go @@ -0,0 +1,76 @@ +// Copyright 2011 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock + +import ( + "reflect" + "testing" +) + +type receiverType struct{} + +func (receiverType) Func() {} + +func TestCallSetAdd(t *testing.T) { + method := "TestMethod" + var receiver interface{} = "TestReceiver" + cs := newCallSet() + + numCalls := 10 + for i := 0; i < numCalls; i++ { + cs.Add(newCall(t, receiver, method, reflect.TypeOf(receiverType{}.Func))) + } + + call, err := cs.FindMatch(receiver, method, []interface{}{}) + if err != nil { + t.Fatalf("FindMatch: %v", err) + } + if call == nil { + t.Fatalf("FindMatch: Got nil, want non-nil *Call") + } +} + +func TestCallSetRemove(t *testing.T) { + method := "TestMethod" + var receiver interface{} = "TestReceiver" + + cs := newCallSet() + ourCalls := []*Call{} + + numCalls := 10 + for i := 0; i < numCalls; i++ { + // NOTE: abuse the `numCalls` value to convey initial ordering of mocked calls + generatedCall := &Call{receiver: receiver, method: method, numCalls: i} + cs.Add(generatedCall) + ourCalls = append(ourCalls, generatedCall) + } + + // validateOrder validates that the calls in the array are ordered as they were added + validateOrder := func(calls []*Call) { + // lastNum tracks the last `numCalls` (call order) value seen + lastNum := -1 + for _, c := range calls { + if lastNum >= c.numCalls { + t.Errorf("found call %d after call %d", c.numCalls, lastNum) + } + lastNum = c.numCalls + } + } + + for _, c := range ourCalls { + validateOrder(cs.expected[callSetKey{receiver, method}]) + cs.Remove(c) + } +} diff --git a/vendor/github.com/golang/mock/gomock/controller.go b/vendor/github.com/golang/mock/gomock/controller.go new file mode 100644 index 00000000..a7b79188 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/controller.go @@ -0,0 +1,217 @@ +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// GoMock - a mock framework for Go. +// +// Standard usage: +// (1) Define an interface that you wish to mock. +// type MyInterface interface { +// SomeMethod(x int64, y string) +// } +// (2) Use mockgen to generate a mock from the interface. +// (3) Use the mock in a test: +// func TestMyThing(t *testing.T) { +// mockCtrl := gomock.NewController(t) +// defer mockCtrl.Finish() +// +// mockObj := something.NewMockMyInterface(mockCtrl) +// mockObj.EXPECT().SomeMethod(4, "blah") +// // pass mockObj to a real object and play with it. +// } +// +// By default, expected calls are not enforced to run in any particular order. +// Call order dependency can be enforced by use of InOrder and/or Call.After. +// Call.After can create more varied call order dependencies, but InOrder is +// often more convenient. +// +// The following examples create equivalent call order dependencies. +// +// Example of using Call.After to chain expected call order: +// +// firstCall := mockObj.EXPECT().SomeMethod(1, "first") +// secondCall := mockObj.EXPECT().SomeMethod(2, "second").After(firstCall) +// mockObj.EXPECT().SomeMethod(3, "third").After(secondCall) +// +// Example of using InOrder to declare expected call order: +// +// gomock.InOrder( +// mockObj.EXPECT().SomeMethod(1, "first"), +// mockObj.EXPECT().SomeMethod(2, "second"), +// mockObj.EXPECT().SomeMethod(3, "third"), +// ) +// +// TODO: +// - Handle different argument/return types (e.g. ..., chan, map, interface). +package gomock + +import ( + "fmt" + "golang.org/x/net/context" + "reflect" + "runtime" + "sync" +) + +// A TestReporter is something that can be used to report test failures. +// It is satisfied by the standard library's *testing.T. +type TestReporter interface { + Errorf(format string, args ...interface{}) + Fatalf(format string, args ...interface{}) +} + +// A Controller represents the top-level control of a mock ecosystem. +// It defines the scope and lifetime of mock objects, as well as their expectations. +// It is safe to call Controller's methods from multiple goroutines. +type Controller struct { + mu sync.Mutex + t TestReporter + expectedCalls *callSet + finished bool +} + +func NewController(t TestReporter) *Controller { + return &Controller{ + t: t, + expectedCalls: newCallSet(), + } +} + +type cancelReporter struct { + t TestReporter + cancel func() +} + +func (r *cancelReporter) Errorf(format string, args ...interface{}) { r.t.Errorf(format, args...) } +func (r *cancelReporter) Fatalf(format string, args ...interface{}) { + defer r.cancel() + r.t.Fatalf(format, args...) +} + +// WithContext returns a new Controller and a Context, which is cancelled on any +// fatal failure. +func WithContext(ctx context.Context, t TestReporter) (*Controller, context.Context) { + ctx, cancel := context.WithCancel(ctx) + return NewController(&cancelReporter{t, cancel}), ctx +} + +func (ctrl *Controller) RecordCall(receiver interface{}, method string, args ...interface{}) *Call { + if h, ok := ctrl.t.(testHelper); ok { + h.Helper() + } + + recv := reflect.ValueOf(receiver) + for i := 0; i < recv.Type().NumMethod(); i++ { + if recv.Type().Method(i).Name == method { + return ctrl.RecordCallWithMethodType(receiver, method, recv.Method(i).Type(), args...) + } + } + ctrl.t.Fatalf("gomock: failed finding method %s on %T", method, receiver) + panic("unreachable") +} + +func (ctrl *Controller) RecordCallWithMethodType(receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call { + if h, ok := ctrl.t.(testHelper); ok { + h.Helper() + } + + call := newCall(ctrl.t, receiver, method, methodType, args...) + + ctrl.mu.Lock() + defer ctrl.mu.Unlock() + ctrl.expectedCalls.Add(call) + + return call +} + +func (ctrl *Controller) Call(receiver interface{}, method string, args ...interface{}) []interface{} { + if h, ok := ctrl.t.(testHelper); ok { + h.Helper() + } + + // Nest this code so we can use defer to make sure the lock is released. + actions := func() []func([]interface{}) []interface{} { + ctrl.mu.Lock() + defer ctrl.mu.Unlock() + + expected, err := ctrl.expectedCalls.FindMatch(receiver, method, args) + if err != nil { + origin := callerInfo(2) + ctrl.t.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", receiver, method, args, origin, err) + } + + // Two things happen here: + // * the matching call no longer needs to check prerequite calls, + // * and the prerequite calls are no longer expected, so remove them. + preReqCalls := expected.dropPrereqs() + for _, preReqCall := range preReqCalls { + ctrl.expectedCalls.Remove(preReqCall) + } + + actions := expected.call(args) + if expected.exhausted() { + ctrl.expectedCalls.Remove(expected) + } + return actions + }() + + var rets []interface{} + for _, action := range actions { + if r := action(args); r != nil { + rets = r + } + } + + return rets +} + +func (ctrl *Controller) Finish() { + if h, ok := ctrl.t.(testHelper); ok { + h.Helper() + } + + ctrl.mu.Lock() + defer ctrl.mu.Unlock() + + if ctrl.finished { + ctrl.t.Fatalf("Controller.Finish was called more than once. It has to be called exactly once.") + } + ctrl.finished = true + + // If we're currently panicking, probably because this is a deferred call, + // pass through the panic. + if err := recover(); err != nil { + panic(err) + } + + // Check that all remaining expected calls are satisfied. + failures := ctrl.expectedCalls.Failures() + for _, call := range failures { + ctrl.t.Errorf("missing call(s) to %v", call) + } + if len(failures) != 0 { + ctrl.t.Fatalf("aborting test due to missing call(s)") + } +} + +func callerInfo(skip int) string { + if _, file, line, ok := runtime.Caller(skip + 1); ok { + return fmt.Sprintf("%s:%d", file, line) + } + return "unknown file" +} + +type testHelper interface { + TestReporter + Helper() +} diff --git a/vendor/github.com/golang/mock/gomock/controller_test.go b/vendor/github.com/golang/mock/gomock/controller_test.go new file mode 100644 index 00000000..b3bb4de2 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/controller_test.go @@ -0,0 +1,712 @@ +// Copyright 2011 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock_test + +import ( + "fmt" + "reflect" + "testing" + + "strings" + + "github.com/golang/mock/gomock" +) + +type ErrorReporter struct { + t *testing.T + log []string + failed bool + fatalToken struct{} +} + +func NewErrorReporter(t *testing.T) *ErrorReporter { + return &ErrorReporter{t: t} +} + +func (e *ErrorReporter) reportLog() { + for _, entry := range e.log { + e.t.Log(entry) + } +} + +func (e *ErrorReporter) assertPass(msg string) { + if e.failed { + e.t.Errorf("Expected pass, but got failure(s): %s", msg) + e.reportLog() + } +} + +func (e *ErrorReporter) assertFail(msg string) { + if !e.failed { + e.t.Errorf("Expected failure, but got pass: %s", msg) + } +} + +// Use to check that code triggers a fatal test failure. +func (e *ErrorReporter) assertFatal(fn func(), expectedErrMsgs ...string) { + defer func() { + err := recover() + if err == nil { + var actual string + if e.failed { + actual = "non-fatal failure" + } else { + actual = "pass" + } + e.t.Error("Expected fatal failure, but got a", actual) + } else if token, ok := err.(*struct{}); ok && token == &e.fatalToken { + // This is okay - the panic is from Fatalf(). + if expectedErrMsgs != nil { + // assert that the actual error message + // contains expectedErrMsgs + + // check the last actualErrMsg, because the previous messages come from previous errors + actualErrMsg := e.log[len(e.log)-1] + for _, expectedErrMsg := range expectedErrMsgs { + if !strings.Contains(actualErrMsg, expectedErrMsg) { + e.t.Errorf("Error message:\ngot: %q\nwant to contain: %q\n", actualErrMsg, expectedErrMsg) + } + } + } + return + } else { + // Some other panic. + panic(err) + } + }() + + fn() +} + +// recoverUnexpectedFatal can be used as a deferred call in test cases to +// recover from and display a call to ErrorReporter.Fatalf(). +func (e *ErrorReporter) recoverUnexpectedFatal() { + err := recover() + if err == nil { + // No panic. + } else if token, ok := err.(*struct{}); ok && token == &e.fatalToken { + // Unexpected fatal error happened. + e.t.Error("Got unexpected fatal error(s). All errors up to this point:") + e.reportLog() + return + } else { + // Some other panic. + panic(err) + } +} + +func (e *ErrorReporter) Logf(format string, args ...interface{}) { + e.log = append(e.log, fmt.Sprintf(format, args...)) +} + +func (e *ErrorReporter) Errorf(format string, args ...interface{}) { + e.Logf(format, args...) + e.failed = true +} + +func (e *ErrorReporter) Fatalf(format string, args ...interface{}) { + e.Logf(format, args...) + e.failed = true + panic(&e.fatalToken) +} + +// A type purely for use as a receiver in testing the Controller. +type Subject struct{} + +func (s *Subject) FooMethod(arg string) int { + return 0 +} + +func (s *Subject) BarMethod(arg string) int { + return 0 +} + +func (s *Subject) VariadicMethod(arg int, vararg ...string) {} + +// A type purely for ActOnTestStructMethod +type TestStruct struct { + Number int + Message string +} + +func (s *Subject) ActOnTestStructMethod(arg TestStruct, arg1 int) int { + return 0 +} + +func (s *Subject) SetArgMethod(sliceArg []byte, ptrArg *int) {} + +func assertEqual(t *testing.T, expected interface{}, actual interface{}) { + if !reflect.DeepEqual(expected, actual) { + t.Errorf("Expected %+v, but got %+v", expected, actual) + } +} + +func createFixtures(t *testing.T) (reporter *ErrorReporter, ctrl *gomock.Controller) { + // reporter acts as a testing.T-like object that we pass to the + // Controller. We use it to test that the mock considered tests + // successful or failed. + reporter = NewErrorReporter(t) + ctrl = gomock.NewController(reporter) + return +} + +func TestNoCalls(t *testing.T) { + reporter, ctrl := createFixtures(t) + ctrl.Finish() + reporter.assertPass("No calls expected or made.") +} + +func TestNoRecordedCallsForAReceiver(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + reporter.assertFatal(func() { + ctrl.Call(subject, "NotRecordedMethod", "argument") + }, "Unexpected call to", "there are no expected calls of the method \"NotRecordedMethod\" for that receiver") + ctrl.Finish() +} + +func TestNoRecordedMatchingMethodNameForAReceiver(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + ctrl.RecordCall(subject, "FooMethod", "argument") + reporter.assertFatal(func() { + ctrl.Call(subject, "NotRecordedMethod", "argument") + }, "Unexpected call to", "there are no expected calls of the method \"NotRecordedMethod\" for that receiver") + reporter.assertFatal(func() { + // The expected call wasn't made. + ctrl.Finish() + }) +} + +// This tests that a call with an arguments of some primitive type matches a recorded call. +func TestExpectedMethodCall(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + ctrl.RecordCall(subject, "FooMethod", "argument") + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Finish() + + reporter.assertPass("Expected method call made.") +} + +func TestUnexpectedMethodCall(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + reporter.assertFatal(func() { + ctrl.Call(subject, "FooMethod", "argument") + }) + + ctrl.Finish() +} + +func TestRepeatedCall(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + ctrl.RecordCall(subject, "FooMethod", "argument").Times(3) + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Call(subject, "FooMethod", "argument") + reporter.assertPass("After expected repeated method calls.") + reporter.assertFatal(func() { + ctrl.Call(subject, "FooMethod", "argument") + }) + ctrl.Finish() + reporter.assertFail("After calling one too many times.") +} + +func TestUnexpectedArgCount(t *testing.T) { + reporter, ctrl := createFixtures(t) + defer reporter.recoverUnexpectedFatal() + subject := new(Subject) + + ctrl.RecordCall(subject, "FooMethod", "argument") + reporter.assertFatal(func() { + // This call is made with the wrong number of arguments... + ctrl.Call(subject, "FooMethod", "argument", "extra_argument") + }, "Unexpected call to", "wrong number of arguments", "Got: 2, want: 1") + reporter.assertFatal(func() { + // ... so is this. + ctrl.Call(subject, "FooMethod") + }, "Unexpected call to", "wrong number of arguments", "Got: 0, want: 1") + reporter.assertFatal(func() { + // The expected call wasn't made. + ctrl.Finish() + }) +} + +// This tests that a call with complex arguments (a struct and some primitive type) matches a recorded call. +func TestExpectedMethodCall_CustomStruct(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + expectedArg0 := TestStruct{Number: 123, Message: "hello"} + ctrl.RecordCall(subject, "ActOnTestStructMethod", expectedArg0, 15) + ctrl.Call(subject, "ActOnTestStructMethod", expectedArg0, 15) + + reporter.assertPass("Expected method call made.") +} + +func TestUnexpectedArgValue_FirstArg(t *testing.T) { + reporter, ctrl := createFixtures(t) + defer reporter.recoverUnexpectedFatal() + subject := new(Subject) + + expectedArg0 := TestStruct{Number: 123, Message: "hello"} + ctrl.RecordCall(subject, "ActOnTestStructMethod", expectedArg0, 15) + + reporter.assertFatal(func() { + // the method argument (of TestStruct type) has 1 unexpected value (for the Message field) + ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 123, Message: "no message"}, 15) + }, "Unexpected call to", "doesn't match the argument at index 0", + "Got: {123 no message}\nWant: is equal to {123 hello}") + + reporter.assertFatal(func() { + // the method argument (of TestStruct type) has 2 unexpected values (for both fields) + ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 11, Message: "no message"}, 15) + }, "Unexpected call to", "doesn't match the argument at index 0", + "Got: {11 no message}\nWant: is equal to {123 hello}") + + reporter.assertFatal(func() { + // The expected call wasn't made. + ctrl.Finish() + }) +} + +func TestUnexpectedArgValue_SecondtArg(t *testing.T) { + reporter, ctrl := createFixtures(t) + defer reporter.recoverUnexpectedFatal() + subject := new(Subject) + + expectedArg0 := TestStruct{Number: 123, Message: "hello"} + ctrl.RecordCall(subject, "ActOnTestStructMethod", expectedArg0, 15) + + reporter.assertFatal(func() { + ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 123, Message: "hello"}, 3) + }, "Unexpected call to", "doesn't match the argument at index 1", + "Got: 3\nWant: is equal to 15") + + reporter.assertFatal(func() { + // The expected call wasn't made. + ctrl.Finish() + }) +} + +func TestAnyTimes(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + ctrl.RecordCall(subject, "FooMethod", "argument").AnyTimes() + for i := 0; i < 100; i++ { + ctrl.Call(subject, "FooMethod", "argument") + } + reporter.assertPass("After 100 method calls.") + ctrl.Finish() +} + +func TestMinTimes1(t *testing.T) { + // It fails if there are no calls + reporter, ctrl := createFixtures(t) + subject := new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1) + reporter.assertFatal(func() { + ctrl.Finish() + }) + + // It succeeds if there is one call + reporter, ctrl = createFixtures(t) + subject = new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1) + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Finish() + + // It succeeds if there are many calls + reporter, ctrl = createFixtures(t) + subject = new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1) + for i := 0; i < 100; i++ { + ctrl.Call(subject, "FooMethod", "argument") + } + ctrl.Finish() +} + +func TestMaxTimes1(t *testing.T) { + // It succeeds if there are no calls + _, ctrl := createFixtures(t) + subject := new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(1) + ctrl.Finish() + + // It succeeds if there is one call + _, ctrl = createFixtures(t) + subject = new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(1) + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Finish() + + //It fails if there are more + reporter, ctrl := createFixtures(t) + subject = new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(1) + ctrl.Call(subject, "FooMethod", "argument") + reporter.assertFatal(func() { + ctrl.Call(subject, "FooMethod", "argument") + }) + ctrl.Finish() +} + +func TestMinMaxTimes(t *testing.T) { + // It fails if there are less calls than specified + reporter, ctrl := createFixtures(t) + subject := new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(2).MaxTimes(2) + ctrl.Call(subject, "FooMethod", "argument") + reporter.assertFatal(func() { + ctrl.Finish() + }) + + // It fails if there are more calls than specified + reporter, ctrl = createFixtures(t) + subject = new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(2).MaxTimes(2) + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Call(subject, "FooMethod", "argument") + reporter.assertFatal(func() { + ctrl.Call(subject, "FooMethod", "argument") + }) + + // It succeeds if there is just the right number of calls + reporter, ctrl = createFixtures(t) + subject = new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(2).MinTimes(2) + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Finish() +} + +func TestDo(t *testing.T) { + _, ctrl := createFixtures(t) + subject := new(Subject) + + doCalled := false + var argument string + ctrl.RecordCall(subject, "FooMethod", "argument").Do( + func(arg string) { + doCalled = true + argument = arg + }) + if doCalled { + t.Error("Do() callback called too early.") + } + + ctrl.Call(subject, "FooMethod", "argument") + + if !doCalled { + t.Error("Do() callback not called.") + } + if "argument" != argument { + t.Error("Do callback received wrong argument.") + } + + ctrl.Finish() +} + +func TestDoAndReturn(t *testing.T) { + _, ctrl := createFixtures(t) + subject := new(Subject) + + doCalled := false + var argument string + ctrl.RecordCall(subject, "FooMethod", "argument").DoAndReturn( + func(arg string) int { + doCalled = true + argument = arg + return 5 + }) + if doCalled { + t.Error("Do() callback called too early.") + } + + rets := ctrl.Call(subject, "FooMethod", "argument") + + if !doCalled { + t.Error("Do() callback not called.") + } + if "argument" != argument { + t.Error("Do callback received wrong argument.") + } + if len(rets) != 1 { + t.Fatalf("Return values from Call: got %d, want 1", len(rets)) + } + if ret, ok := rets[0].(int); !ok { + t.Fatalf("Return value is not an int") + } else if ret != 5 { + t.Errorf("DoAndReturn return value: got %d, want 5", ret) + } + + ctrl.Finish() +} + +func TestSetArgSlice(t *testing.T) { + _, ctrl := createFixtures(t) + subject := new(Subject) + + var in = []byte{4, 5, 6} + var set = []byte{1, 2, 3} + ctrl.RecordCall(subject, "SetArgMethod", in, nil).SetArg(0, set) + ctrl.Call(subject, "SetArgMethod", in, nil) + + if !reflect.DeepEqual(in, set) { + t.Error("Expected SetArg() to modify input slice argument") + } + + ctrl.Finish() +} + +func TestSetArgPtr(t *testing.T) { + _, ctrl := createFixtures(t) + subject := new(Subject) + + var in int = 43 + const set = 42 + ctrl.RecordCall(subject, "SetArgMethod", nil, &in).SetArg(1, set) + ctrl.Call(subject, "SetArgMethod", nil, &in) + + if in != set { + t.Error("Expected SetArg() to modify value pointed to by argument") + } + + ctrl.Finish() +} + +func TestReturn(t *testing.T) { + _, ctrl := createFixtures(t) + subject := new(Subject) + + // Unspecified return should produce "zero" result. + ctrl.RecordCall(subject, "FooMethod", "zero") + ctrl.RecordCall(subject, "FooMethod", "five").Return(5) + + assertEqual( + t, + []interface{}{0}, + ctrl.Call(subject, "FooMethod", "zero")) + + assertEqual( + t, + []interface{}{5}, + ctrl.Call(subject, "FooMethod", "five")) + ctrl.Finish() +} + +func TestUnorderedCalls(t *testing.T) { + reporter, ctrl := createFixtures(t) + defer reporter.recoverUnexpectedFatal() + subjectTwo := new(Subject) + subjectOne := new(Subject) + + ctrl.RecordCall(subjectOne, "FooMethod", "1") + ctrl.RecordCall(subjectOne, "BarMethod", "2") + ctrl.RecordCall(subjectTwo, "FooMethod", "3") + ctrl.RecordCall(subjectTwo, "BarMethod", "4") + + // Make the calls in a different order, which should be fine. + ctrl.Call(subjectOne, "BarMethod", "2") + ctrl.Call(subjectTwo, "FooMethod", "3") + ctrl.Call(subjectTwo, "BarMethod", "4") + ctrl.Call(subjectOne, "FooMethod", "1") + + reporter.assertPass("After making all calls in different order") + + ctrl.Finish() + + reporter.assertPass("After finish") +} + +func commonTestOrderedCalls(t *testing.T) (reporter *ErrorReporter, ctrl *gomock.Controller, subjectOne, subjectTwo *Subject) { + reporter, ctrl = createFixtures(t) + + subjectOne = new(Subject) + subjectTwo = new(Subject) + + gomock.InOrder( + ctrl.RecordCall(subjectOne, "FooMethod", "1").AnyTimes(), + ctrl.RecordCall(subjectTwo, "FooMethod", "2"), + ctrl.RecordCall(subjectTwo, "BarMethod", "3"), + ) + + return +} + +func TestOrderedCallsCorrect(t *testing.T) { + reporter, ctrl, subjectOne, subjectTwo := commonTestOrderedCalls(t) + + ctrl.Call(subjectOne, "FooMethod", "1") + ctrl.Call(subjectTwo, "FooMethod", "2") + ctrl.Call(subjectTwo, "BarMethod", "3") + + ctrl.Finish() + + reporter.assertPass("After finish") +} + +func TestOrderedCallsInCorrect(t *testing.T) { + reporter, ctrl, subjectOne, subjectTwo := commonTestOrderedCalls(t) + + ctrl.Call(subjectOne, "FooMethod", "1") + reporter.assertFatal(func() { + // FooMethod(2) should be called before BarMethod(3) + ctrl.Call(subjectTwo, "BarMethod", "3") + }, "Unexpected call to", "Subject.BarMethod([3])", "doesn't have a prerequisite call satisfied") +} + +// Test that calls that are prerequisites to other calls but have maxCalls > +// minCalls are removed from the expected call set. +func TestOrderedCallsWithPreReqMaxUnbounded(t *testing.T) { + reporter, ctrl, subjectOne, subjectTwo := commonTestOrderedCalls(t) + + // Initially we should be able to call FooMethod("1") as many times as we + // want. + ctrl.Call(subjectOne, "FooMethod", "1") + ctrl.Call(subjectOne, "FooMethod", "1") + + // But calling something that has it as a prerequite should remove it from + // the expected call set. This allows tests to ensure that FooMethod("1") is + // *not* called after FooMethod("2"). + ctrl.Call(subjectTwo, "FooMethod", "2") + + // Therefore this call should fail: + reporter.assertFatal(func() { + ctrl.Call(subjectOne, "FooMethod", "1") + }) +} + +func TestCallAfterLoopPanic(t *testing.T) { + _, ctrl := createFixtures(t) + + subject := new(Subject) + + firstCall := ctrl.RecordCall(subject, "FooMethod", "1") + secondCall := ctrl.RecordCall(subject, "FooMethod", "2") + thirdCall := ctrl.RecordCall(subject, "FooMethod", "3") + + gomock.InOrder(firstCall, secondCall, thirdCall) + + defer func() { + err := recover() + if err == nil { + t.Error("Call.After creation of dependency loop did not panic.") + } + }() + + // This should panic due to dependency loop. + firstCall.After(thirdCall) +} + +func TestPanicOverridesExpectationChecks(t *testing.T) { + ctrl := gomock.NewController(t) + reporter := NewErrorReporter(t) + + reporter.assertFatal(func() { + ctrl.RecordCall(new(Subject), "FooMethod", "1") + defer ctrl.Finish() + reporter.Fatalf("Intentional panic") + }) +} + +func TestSetArgWithBadType(t *testing.T) { + rep, ctrl := createFixtures(t) + defer ctrl.Finish() + + s := new(Subject) + // This should catch a type error: + rep.assertFatal(func() { + ctrl.RecordCall(s, "FooMethod", "1").SetArg(0, "blah") + }) + ctrl.Call(s, "FooMethod", "1") +} + +func TestTimes0(t *testing.T) { + rep, ctrl := createFixtures(t) + defer ctrl.Finish() + + s := new(Subject) + ctrl.RecordCall(s, "FooMethod", "arg").Times(0) + rep.assertFatal(func() { + ctrl.Call(s, "FooMethod", "arg") + }) +} + +func TestVariadicMatching(t *testing.T) { + rep, ctrl := createFixtures(t) + defer rep.recoverUnexpectedFatal() + + s := new(Subject) + ctrl.RecordCall(s, "VariadicMethod", 0, "1", "2") + ctrl.Call(s, "VariadicMethod", 0, "1", "2") + ctrl.Finish() + rep.assertPass("variadic matching works") +} + +func TestVariadicNoMatch(t *testing.T) { + rep, ctrl := createFixtures(t) + defer rep.recoverUnexpectedFatal() + + s := new(Subject) + ctrl.RecordCall(s, "VariadicMethod", 0) + rep.assertFatal(func() { + ctrl.Call(s, "VariadicMethod", 1) + }, "Expected call at", "doesn't match the argument at index 0", + "Got: 1\nWant: is equal to 0") + ctrl.Call(s, "VariadicMethod", 0) + ctrl.Finish() +} + +func TestVariadicMatchingWithSlice(t *testing.T) { + testCases := [][]string{ + {"1"}, + {"1", "2"}, + } + for _, tc := range testCases { + t.Run(fmt.Sprintf("%d arguments", len(tc)), func(t *testing.T) { + rep, ctrl := createFixtures(t) + defer rep.recoverUnexpectedFatal() + + s := new(Subject) + ctrl.RecordCall(s, "VariadicMethod", 1, tc) + args := make([]interface{}, len(tc)+1) + args[0] = 1 + for i, arg := range tc { + args[i+1] = arg + } + ctrl.Call(s, "VariadicMethod", args...) + ctrl.Finish() + rep.assertPass("slices can be used as matchers for variadic arguments") + }) + } +} + +func TestDuplicateFinishCallFails(t *testing.T) { + rep, ctrl := createFixtures(t) + + ctrl.Finish() + rep.assertPass("the first Finish call should succeed") + + rep.assertFatal(ctrl.Finish, "Controller.Finish was called more than once. It has to be called exactly once.") +} diff --git a/vendor/github.com/golang/mock/gomock/matchers.go b/vendor/github.com/golang/mock/gomock/matchers.go new file mode 100644 index 00000000..e8b1ddcc --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/matchers.go @@ -0,0 +1,99 @@ +//go:generate mockgen -destination mock_matcher/mock_matcher.go github.com/golang/mock/gomock Matcher + +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock + +import ( + "fmt" + "reflect" +) + +// A Matcher is a representation of a class of values. +// It is used to represent the valid or expected arguments to a mocked method. +type Matcher interface { + // Matches returns whether x is a match. + Matches(x interface{}) bool + + // String describes what the matcher matches. + String() string +} + +type anyMatcher struct{} + +func (anyMatcher) Matches(x interface{}) bool { + return true +} + +func (anyMatcher) String() string { + return "is anything" +} + +type eqMatcher struct { + x interface{} +} + +func (e eqMatcher) Matches(x interface{}) bool { + return reflect.DeepEqual(e.x, x) +} + +func (e eqMatcher) String() string { + return fmt.Sprintf("is equal to %v", e.x) +} + +type nilMatcher struct{} + +func (nilMatcher) Matches(x interface{}) bool { + if x == nil { + return true + } + + v := reflect.ValueOf(x) + switch v.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, + reflect.Ptr, reflect.Slice: + return v.IsNil() + } + + return false +} + +func (nilMatcher) String() string { + return "is nil" +} + +type notMatcher struct { + m Matcher +} + +func (n notMatcher) Matches(x interface{}) bool { + return !n.m.Matches(x) +} + +func (n notMatcher) String() string { + // TODO: Improve this if we add a NotString method to the Matcher interface. + return "not(" + n.m.String() + ")" +} + +// Constructors +func Any() Matcher { return anyMatcher{} } +func Eq(x interface{}) Matcher { return eqMatcher{x} } +func Nil() Matcher { return nilMatcher{} } +func Not(x interface{}) Matcher { + if m, ok := x.(Matcher); ok { + return notMatcher{m} + } + return notMatcher{Eq(x)} +} diff --git a/vendor/github.com/golang/mock/gomock/matchers_test.go b/vendor/github.com/golang/mock/gomock/matchers_test.go new file mode 100644 index 00000000..29b97fb9 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/matchers_test.go @@ -0,0 +1,70 @@ +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock_test + +import ( + "errors" + "testing" + + "github.com/golang/mock/gomock" + mock_matcher "github.com/golang/mock/gomock/mock_matcher" +) + +func TestMatchers(t *testing.T) { + type e interface{} + type testCase struct { + matcher gomock.Matcher + yes, no []e + } + tests := []testCase{ + testCase{gomock.Any(), []e{3, nil, "foo"}, nil}, + testCase{gomock.Eq(4), []e{4}, []e{3, "blah", nil, int64(4)}}, + testCase{gomock.Nil(), + []e{nil, (error)(nil), (chan bool)(nil), (*int)(nil)}, + []e{"", 0, make(chan bool), errors.New("err"), new(int)}}, + testCase{gomock.Not(gomock.Eq(4)), []e{3, "blah", nil, int64(4)}, []e{4}}, + } + for i, test := range tests { + for _, x := range test.yes { + if !test.matcher.Matches(x) { + t.Errorf(`test %d: "%v %s" should be true.`, i, x, test.matcher) + } + } + for _, x := range test.no { + if test.matcher.Matches(x) { + t.Errorf(`test %d: "%v %s" should be false.`, i, x, test.matcher) + } + } + } +} + +// A more thorough test of notMatcher +func TestNotMatcher(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockMatcher := mock_matcher.NewMockMatcher(ctrl) + notMatcher := gomock.Not(mockMatcher) + + mockMatcher.EXPECT().Matches(4).Return(true) + if match := notMatcher.Matches(4); match { + t.Errorf("notMatcher should not match 4") + } + + mockMatcher.EXPECT().Matches(5).Return(false) + if match := notMatcher.Matches(5); !match { + t.Errorf("notMatcher should match 5") + } +} diff --git a/vendor/github.com/golang/mock/gomock/mock_matcher/mock_matcher.go b/vendor/github.com/golang/mock/gomock/mock_matcher/mock_matcher.go new file mode 100644 index 00000000..7e4b4c8a --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/mock_matcher/mock_matcher.go @@ -0,0 +1,57 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/golang/mock/gomock (interfaces: Matcher) + +// Package mock_gomock is a generated GoMock package. +package mock_gomock + +import ( + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockMatcher is a mock of Matcher interface +type MockMatcher struct { + ctrl *gomock.Controller + recorder *MockMatcherMockRecorder +} + +// MockMatcherMockRecorder is the mock recorder for MockMatcher +type MockMatcherMockRecorder struct { + mock *MockMatcher +} + +// NewMockMatcher creates a new mock instance +func NewMockMatcher(ctrl *gomock.Controller) *MockMatcher { + mock := &MockMatcher{ctrl: ctrl} + mock.recorder = &MockMatcherMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockMatcher) EXPECT() *MockMatcherMockRecorder { + return m.recorder +} + +// Matches mocks base method +func (m *MockMatcher) Matches(arg0 interface{}) bool { + ret := m.ctrl.Call(m, "Matches", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// Matches indicates an expected call of Matches +func (mr *MockMatcherMockRecorder) Matches(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Matches", reflect.TypeOf((*MockMatcher)(nil).Matches), arg0) +} + +// String mocks base method +func (m *MockMatcher) String() string { + ret := m.ctrl.Call(m, "String") + ret0, _ := ret[0].(string) + return ret0 +} + +// String indicates an expected call of String +func (mr *MockMatcherMockRecorder) String() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockMatcher)(nil).String)) +} diff --git a/vendor/github.com/golang/mock/mockgen/mockgen.go b/vendor/github.com/golang/mock/mockgen/mockgen.go new file mode 100644 index 00000000..67481a64 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/mockgen.go @@ -0,0 +1,559 @@ +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// MockGen generates mock implementations of Go interfaces. +package main + +// TODO: This does not support recursive embedded interfaces. +// TODO: This does not support embedding package-local interfaces in a separate file. + +import ( + "bytes" + "flag" + "fmt" + "go/build" + "go/format" + "go/token" + "io" + "log" + "os" + "path" + "path/filepath" + "sort" + "strconv" + "strings" + "unicode" + + "github.com/golang/mock/mockgen/model" +) + +const ( + gomockImportPath = "github.com/golang/mock/gomock" +) + +var ( + source = flag.String("source", "", "(source mode) Input Go source file; enables source mode.") + destination = flag.String("destination", "", "Output file; defaults to stdout.") + mockNames = flag.String("mock_names", "", "Comma-separated interfaceName=mockName pairs of explicit mock names to use. Mock names default to 'Mock'+ interfaceName suffix.") + packageOut = flag.String("package", "", "Package of the generated code; defaults to the package of the input with a 'mock_' prefix.") + selfPackage = flag.String("self_package", "", "The full package import path for the generated code. The purpose of this flag is to prevent import cycles in the generated code by trying to include its own package. This can happen if the mock's package is set to one of its inputs (usually the main one) and the output is stdio so mockgen cannot detect the final output package. Setting this flag will then tell mockgen which import to exclude.") + writePkgComment = flag.Bool("write_package_comment", true, "Writes package documentation comment (godoc) if true.") + + debugParser = flag.Bool("debug_parser", false, "Print out parser results only.") +) + +func main() { + flag.Usage = usage + flag.Parse() + + var pkg *model.Package + var err error + if *source != "" { + pkg, err = ParseFile(*source) + } else { + if flag.NArg() != 2 { + usage() + log.Fatal("Expected exactly two arguments") + } + pkg, err = Reflect(flag.Arg(0), strings.Split(flag.Arg(1), ",")) + } + if err != nil { + log.Fatalf("Loading input failed: %v", err) + } + + if *debugParser { + pkg.Print(os.Stdout) + return + } + + dst := os.Stdout + if len(*destination) > 0 { + f, err := os.Create(*destination) + if err != nil { + log.Fatalf("Failed opening destination file: %v", err) + } + defer f.Close() + dst = f + } + + packageName := *packageOut + if packageName == "" { + // pkg.Name in reflect mode is the base name of the import path, + // which might have characters that are illegal to have in package names. + packageName = "mock_" + sanitize(pkg.Name) + } + + // outputPackagePath represents the fully qualified name of the package of + // the generated code. Its purposes are to prevent the module from importing + // itself and to prevent qualifying type names that come from its own + // package (i.e. if there is a type called X then we want to print "X" not + // "package.X" since "package" is this package). This can happen if the mock + // is output into an already existing package. + outputPackagePath := *selfPackage + if len(outputPackagePath) == 0 && len(*destination) > 0 { + dst, _ := filepath.Abs(filepath.Dir(*destination)) + for _, prefix := range build.Default.SrcDirs() { + if strings.HasPrefix(dst, prefix) { + if rel, err := filepath.Rel(prefix, dst); err == nil { + outputPackagePath = rel + break + } + } + } + } + + g := new(generator) + if *source != "" { + g.filename = *source + } else { + g.srcPackage = flag.Arg(0) + g.srcInterfaces = flag.Arg(1) + } + + if *mockNames != "" { + g.mockNames = parseMockNames(*mockNames) + } + if err := g.Generate(pkg, packageName, outputPackagePath); err != nil { + log.Fatalf("Failed generating mock: %v", err) + } + if _, err := dst.Write(g.Output()); err != nil { + log.Fatalf("Failed writing to destination: %v", err) + } +} +func parseMockNames(names string) map[string]string { + mocksMap := make(map[string]string) + for _, kv := range strings.Split(names, ",") { + parts := strings.SplitN(kv, "=", 2) + if len(parts) != 2 || parts[1] == "" { + log.Fatalf("bad mock names spec: %v", kv) + } + mocksMap[parts[0]] = parts[1] + } + return mocksMap +} + +func usage() { + io.WriteString(os.Stderr, usageText) + flag.PrintDefaults() +} + +const usageText = `mockgen has two modes of operation: source and reflect. + +Source mode generates mock interfaces from a source file. +It is enabled by using the -source flag. Other flags that +may be useful in this mode are -imports and -aux_files. +Example: + mockgen -source=foo.go [other options] + +Reflect mode generates mock interfaces by building a program +that uses reflection to understand interfaces. It is enabled +by passing two non-flag arguments: an import path, and a +comma-separated list of symbols. +Example: + mockgen database/sql/driver Conn,Driver + +` + +type generator struct { + buf bytes.Buffer + indent string + mockNames map[string]string //may be empty + filename string // may be empty + srcPackage, srcInterfaces string // may be empty + + packageMap map[string]string // map from import path to package name +} + +func (g *generator) p(format string, args ...interface{}) { + fmt.Fprintf(&g.buf, g.indent+format+"\n", args...) +} + +func (g *generator) in() { + g.indent += "\t" +} + +func (g *generator) out() { + if len(g.indent) > 0 { + g.indent = g.indent[0 : len(g.indent)-1] + } +} + +func removeDot(s string) string { + if len(s) > 0 && s[len(s)-1] == '.' { + return s[0 : len(s)-1] + } + return s +} + +// sanitize cleans up a string to make a suitable package name. +func sanitize(s string) string { + t := "" + for _, r := range s { + if t == "" { + if unicode.IsLetter(r) || r == '_' { + t += string(r) + continue + } + } else { + if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' { + t += string(r) + continue + } + } + t += "_" + } + if t == "_" { + t = "x" + } + return t +} + +func (g *generator) Generate(pkg *model.Package, pkgName string, outputPackagePath string) error { + g.p("// Code generated by MockGen. DO NOT EDIT.") + if g.filename != "" { + g.p("// Source: %v", g.filename) + } else { + g.p("// Source: %v (interfaces: %v)", g.srcPackage, g.srcInterfaces) + } + g.p("") + + // Get all required imports, and generate unique names for them all. + im := pkg.Imports() + im[gomockImportPath] = true + + // Only import reflect if it's used. We only use reflect in mocked methods + // so only import if any of the mocked interfaces have methods. + for _, intf := range pkg.Interfaces { + if len(intf.Methods) > 0 { + im["reflect"] = true + break + } + } + + // Sort keys to make import alias generation predictable + sorted_paths := make([]string, len(im), len(im)) + x := 0 + for pth := range im { + sorted_paths[x] = pth + x++ + } + sort.Strings(sorted_paths) + + g.packageMap = make(map[string]string, len(im)) + localNames := make(map[string]bool, len(im)) + for _, pth := range sorted_paths { + base := sanitize(path.Base(pth)) + + // Local names for an imported package can usually be the basename of the import path. + // A couple of situations don't permit that, such as duplicate local names + // (e.g. importing "html/template" and "text/template"), or where the basename is + // a keyword (e.g. "foo/case"). + // try base0, base1, ... + pkgName := base + i := 0 + for localNames[pkgName] || token.Lookup(pkgName).IsKeyword() { + pkgName = base + strconv.Itoa(i) + i++ + } + + g.packageMap[pth] = pkgName + localNames[pkgName] = true + } + + if *writePkgComment { + g.p("// Package %v is a generated GoMock package.", pkgName) + } + g.p("package %v", pkgName) + g.p("") + g.p("import (") + g.in() + for path, pkg := range g.packageMap { + if path == outputPackagePath { + continue + } + g.p("%v %q", pkg, path) + } + for _, path := range pkg.DotImports { + g.p(". %q", path) + } + g.out() + g.p(")") + + for _, intf := range pkg.Interfaces { + if err := g.GenerateMockInterface(intf, outputPackagePath); err != nil { + return err + } + } + + return nil +} + +// The name of the mock type to use for the given interface identifier. +func (g *generator) mockName(typeName string) string { + if mockName, ok := g.mockNames[typeName]; ok { + return mockName + } + + return "Mock" + typeName +} + +func (g *generator) GenerateMockInterface(intf *model.Interface, outputPackagePath string) error { + mockType := g.mockName(intf.Name) + + g.p("") + g.p("// %v is a mock of %v interface", mockType, intf.Name) + g.p("type %v struct {", mockType) + g.in() + g.p("ctrl *gomock.Controller") + g.p("recorder *%vMockRecorder", mockType) + g.out() + g.p("}") + g.p("") + + g.p("// %vMockRecorder is the mock recorder for %v", mockType, mockType) + g.p("type %vMockRecorder struct {", mockType) + g.in() + g.p("mock *%v", mockType) + g.out() + g.p("}") + g.p("") + + // TODO: Re-enable this if we can import the interface reliably. + //g.p("// Verify that the mock satisfies the interface at compile time.") + //g.p("var _ %v = (*%v)(nil)", typeName, mockType) + //g.p("") + + g.p("// New%v creates a new mock instance", mockType) + g.p("func New%v(ctrl *gomock.Controller) *%v {", mockType, mockType) + g.in() + g.p("mock := &%v{ctrl: ctrl}", mockType) + g.p("mock.recorder = &%vMockRecorder{mock}", mockType) + g.p("return mock") + g.out() + g.p("}") + g.p("") + + // XXX: possible name collision here if someone has EXPECT in their interface. + g.p("// EXPECT returns an object that allows the caller to indicate expected use") + g.p("func (m *%v) EXPECT() *%vMockRecorder {", mockType, mockType) + g.in() + g.p("return m.recorder") + g.out() + g.p("}") + + g.GenerateMockMethods(mockType, intf, outputPackagePath) + + return nil +} + +func (g *generator) GenerateMockMethods(mockType string, intf *model.Interface, pkgOverride string) { + for _, m := range intf.Methods { + g.p("") + g.GenerateMockMethod(mockType, m, pkgOverride) + g.p("") + g.GenerateMockRecorderMethod(mockType, m) + } +} + +func makeArgString(argNames, argTypes []string) string { + args := make([]string, len(argNames)) + for i, name := range argNames { + // specify the type only once for consecutive args of the same type + if i+1 < len(argTypes) && argTypes[i] == argTypes[i+1] { + args[i] = name + } else { + args[i] = name + " " + argTypes[i] + } + } + return strings.Join(args, ", ") +} + +// GenerateMockMethod generates a mock method implementation. +// If non-empty, pkgOverride is the package in which unqualified types reside. +func (g *generator) GenerateMockMethod(mockType string, m *model.Method, pkgOverride string) error { + argNames := g.getArgNames(m) + argTypes := g.getArgTypes(m, pkgOverride) + argString := makeArgString(argNames, argTypes) + + rets := make([]string, len(m.Out)) + for i, p := range m.Out { + rets[i] = p.Type.String(g.packageMap, pkgOverride) + } + retString := strings.Join(rets, ", ") + if len(rets) > 1 { + retString = "(" + retString + ")" + } + if retString != "" { + retString = " " + retString + } + + ia := newIdentifierAllocator(argNames) + idRecv := ia.allocateIdentifier("m") + + g.p("// %v mocks base method", m.Name) + g.p("func (%v *%v) %v(%v)%v {", idRecv, mockType, m.Name, argString, retString) + g.in() + + var callArgs string + if m.Variadic == nil { + if len(argNames) > 0 { + callArgs = ", " + strings.Join(argNames, ", ") + } + } else { + // Non-trivial. The generated code must build a []interface{}, + // but the variadic argument may be any type. + idVarArgs := ia.allocateIdentifier("varargs") + idVArg := ia.allocateIdentifier("a") + g.p("%s := []interface{}{%s}", idVarArgs, strings.Join(argNames[:len(argNames)-1], ", ")) + g.p("for _, %s := range %s {", idVArg, argNames[len(argNames)-1]) + g.in() + g.p("%s = append(%s, %s)", idVarArgs, idVarArgs, idVArg) + g.out() + g.p("}") + callArgs = ", " + idVarArgs + "..." + } + if len(m.Out) == 0 { + g.p(`%v.ctrl.Call(%v, %q%v)`, idRecv, idRecv, m.Name, callArgs) + } else { + idRet := ia.allocateIdentifier("ret") + g.p(`%v := %v.ctrl.Call(%v, %q%v)`, idRet, idRecv, idRecv, m.Name, callArgs) + + // Go does not allow "naked" type assertions on nil values, so we use the two-value form here. + // The value of that is either (x.(T), true) or (Z, false), where Z is the zero value for T. + // Happily, this coincides with the semantics we want here. + retNames := make([]string, len(rets)) + for i, t := range rets { + retNames[i] = ia.allocateIdentifier(fmt.Sprintf("ret%d", i)) + g.p("%s, _ := %s[%d].(%s)", retNames[i], idRet, i, t) + } + g.p("return " + strings.Join(retNames, ", ")) + } + + g.out() + g.p("}") + return nil +} + +func (g *generator) GenerateMockRecorderMethod(mockType string, m *model.Method) error { + argNames := g.getArgNames(m) + + var argString string + if m.Variadic == nil { + argString = strings.Join(argNames, ", ") + } else { + argString = strings.Join(argNames[:len(argNames)-1], ", ") + } + if argString != "" { + argString += " interface{}" + } + + if m.Variadic != nil { + if argString != "" { + argString += ", " + } + argString += fmt.Sprintf("%s ...interface{}", argNames[len(argNames)-1]) + } + + ia := newIdentifierAllocator(argNames) + idRecv := ia.allocateIdentifier("mr") + + g.p("// %v indicates an expected call of %v", m.Name, m.Name) + g.p("func (%s *%vMockRecorder) %v(%v) *gomock.Call {", idRecv, mockType, m.Name, argString) + g.in() + + var callArgs string + if m.Variadic == nil { + if len(argNames) > 0 { + callArgs = ", " + strings.Join(argNames, ", ") + } + } else { + if len(argNames) == 1 { + // Easy: just use ... to push the arguments through. + callArgs = ", " + argNames[0] + "..." + } else { + // Hard: create a temporary slice. + idVarArgs := ia.allocateIdentifier("varargs") + g.p("%s := append([]interface{}{%s}, %s...)", + idVarArgs, + strings.Join(argNames[:len(argNames)-1], ", "), + argNames[len(argNames)-1]) + callArgs = ", " + idVarArgs + "..." + } + } + g.p(`return %s.mock.ctrl.RecordCallWithMethodType(%s.mock, "%s", reflect.TypeOf((*%s)(nil).%s)%s)`, idRecv, idRecv, m.Name, mockType, m.Name, callArgs) + + g.out() + g.p("}") + return nil +} + +func (g *generator) getArgNames(m *model.Method) []string { + argNames := make([]string, len(m.In)) + for i, p := range m.In { + name := p.Name + if name == "" { + name = fmt.Sprintf("arg%d", i) + } + argNames[i] = name + } + if m.Variadic != nil { + name := m.Variadic.Name + if name == "" { + name = fmt.Sprintf("arg%d", len(m.In)) + } + argNames = append(argNames, name) + } + return argNames +} + +func (g *generator) getArgTypes(m *model.Method, pkgOverride string) []string { + argTypes := make([]string, len(m.In)) + for i, p := range m.In { + argTypes[i] = p.Type.String(g.packageMap, pkgOverride) + } + if m.Variadic != nil { + argTypes = append(argTypes, "..."+m.Variadic.Type.String(g.packageMap, pkgOverride)) + } + return argTypes +} + +type identifierAllocator map[string]struct{} + +func newIdentifierAllocator(taken []string) identifierAllocator { + a := make(identifierAllocator, len(taken)) + for _, s := range taken { + a[s] = struct{}{} + } + return a +} + +func (o identifierAllocator) allocateIdentifier(want string) string { + id := want + for i := 2; ; i++ { + if _, ok := o[id]; !ok { + o[id] = struct{}{} + return id + } + id = want + "_" + strconv.Itoa(i) + } +} + +// Output returns the generator's output, formatted in the standard Go style. +func (g *generator) Output() []byte { + src, err := format.Source(g.buf.Bytes()) + if err != nil { + log.Fatalf("Failed to format generated source code: %s\n%s", err, g.buf.String()) + } + return src +} diff --git a/vendor/github.com/golang/mock/mockgen/mockgen_test.go b/vendor/github.com/golang/mock/mockgen/mockgen_test.go new file mode 100644 index 00000000..bcb2a97f --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/mockgen_test.go @@ -0,0 +1,181 @@ +package main + +import ( + "fmt" + "testing" +) + +func TestMakeArgString(t *testing.T) { + testCases := []struct { + argNames []string + argTypes []string + argString string + }{ + { + argNames: nil, + argTypes: nil, + argString: "", + }, + { + argNames: []string{"arg0"}, + argTypes: []string{"int"}, + argString: "arg0 int", + }, + { + argNames: []string{"arg0", "arg1"}, + argTypes: []string{"int", "bool"}, + argString: "arg0 int, arg1 bool", + }, + { + argNames: []string{"arg0", "arg1"}, + argTypes: []string{"int", "int"}, + argString: "arg0, arg1 int", + }, + { + argNames: []string{"arg0", "arg1", "arg2"}, + argTypes: []string{"bool", "int", "int"}, + argString: "arg0 bool, arg1, arg2 int", + }, + { + argNames: []string{"arg0", "arg1", "arg2"}, + argTypes: []string{"int", "bool", "int"}, + argString: "arg0 int, arg1 bool, arg2 int", + }, + { + argNames: []string{"arg0", "arg1", "arg2"}, + argTypes: []string{"int", "int", "bool"}, + argString: "arg0, arg1 int, arg2 bool", + }, + { + argNames: []string{"arg0", "arg1", "arg2"}, + argTypes: []string{"int", "int", "int"}, + argString: "arg0, arg1, arg2 int", + }, + { + argNames: []string{"arg0", "arg1", "arg2", "arg3"}, + argTypes: []string{"bool", "int", "int", "int"}, + argString: "arg0 bool, arg1, arg2, arg3 int", + }, + { + argNames: []string{"arg0", "arg1", "arg2", "arg3"}, + argTypes: []string{"int", "bool", "int", "int"}, + argString: "arg0 int, arg1 bool, arg2, arg3 int", + }, + { + argNames: []string{"arg0", "arg1", "arg2", "arg3"}, + argTypes: []string{"int", "int", "bool", "int"}, + argString: "arg0, arg1 int, arg2 bool, arg3 int", + }, + { + argNames: []string{"arg0", "arg1", "arg2", "arg3"}, + argTypes: []string{"int", "int", "int", "bool"}, + argString: "arg0, arg1, arg2 int, arg3 bool", + }, + { + argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"}, + argTypes: []string{"bool", "int", "int", "int", "bool"}, + argString: "arg0 bool, arg1, arg2, arg3 int, arg4 bool", + }, + { + argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"}, + argTypes: []string{"int", "bool", "int", "int", "bool"}, + argString: "arg0 int, arg1 bool, arg2, arg3 int, arg4 bool", + }, + { + argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"}, + argTypes: []string{"int", "int", "bool", "int", "bool"}, + argString: "arg0, arg1 int, arg2 bool, arg3 int, arg4 bool", + }, + { + argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"}, + argTypes: []string{"int", "int", "int", "bool", "bool"}, + argString: "arg0, arg1, arg2 int, arg3, arg4 bool", + }, + { + argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"}, + argTypes: []string{"int", "int", "bool", "bool", "int"}, + argString: "arg0, arg1 int, arg2, arg3 bool, arg4 int", + }, + } + + for i, tc := range testCases { + t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { + s := makeArgString(tc.argNames, tc.argTypes) + if s != tc.argString { + t.Errorf("result == %q, want %q", s, tc.argString) + } + }) + } +} + +func TestNewIdentifierAllocator(t *testing.T) { + a := newIdentifierAllocator([]string{"taken1", "taken2"}) + if len(a) != 2 { + t.Fatalf("expected 2 items, got %v", len(a)) + } + + _, ok := a["taken1"] + if !ok { + t.Errorf("allocator doesn't contain 'taken1': %#v", a) + } + + _, ok = a["taken2"] + if !ok { + t.Errorf("allocator doesn't contain 'taken2': %#v", a) + } +} + +func allocatorContainsIdentifiers(a identifierAllocator, ids []string) bool { + if len(a) != len(ids) { + return false + } + + for _, id := range ids { + _, ok := a[id] + if !ok { + return false + } + } + + return true +} + +func TestIdentifierAllocator_allocateIdentifier(t *testing.T) { + a := newIdentifierAllocator([]string{"taken"}) + + t2 := a.allocateIdentifier("taken_2") + if t2 != "taken_2" { + t.Fatalf("expected 'taken_2', got %q", t2) + } + expected := []string{"taken", "taken_2"} + if !allocatorContainsIdentifiers(a, expected) { + t.Fatalf("allocator doesn't contain the expected items - allocator: %#v, expected items: %#v", a, expected) + } + + t3 := a.allocateIdentifier("taken") + if t3 != "taken_3" { + t.Fatalf("expected 'taken_3', got %q", t3) + } + expected = []string{"taken", "taken_2", "taken_3"} + if !allocatorContainsIdentifiers(a, expected) { + t.Fatalf("allocator doesn't contain the expected items - allocator: %#v, expected items: %#v", a, expected) + } + + t4 := a.allocateIdentifier("taken") + if t4 != "taken_4" { + t.Fatalf("expected 'taken_4', got %q", t4) + } + expected = []string{"taken", "taken_2", "taken_3", "taken_4"} + if !allocatorContainsIdentifiers(a, expected) { + t.Fatalf("allocator doesn't contain the expected items - allocator: %#v, expected items: %#v", a, expected) + } + + id := a.allocateIdentifier("id") + if id != "id" { + t.Fatalf("expected 'id', got %q", id) + } + expected = []string{"taken", "taken_2", "taken_3", "taken_4", "id"} + if !allocatorContainsIdentifiers(a, expected) { + t.Fatalf("allocator doesn't contain the expected items - allocator: %#v, expected items: %#v", a, expected) + } +} diff --git a/vendor/github.com/golang/mock/mockgen/model/model.go b/vendor/github.com/golang/mock/mockgen/model/model.go new file mode 100644 index 00000000..c8af9a34 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/model/model.go @@ -0,0 +1,449 @@ +// Copyright 2012 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package model contains the data model necessary for generating mock implementations. +package model + +import ( + "encoding/gob" + "fmt" + "io" + "reflect" + "strings" +) + +// pkgPath is the importable path for package model +const pkgPath = "github.com/golang/mock/mockgen/model" + +// Package is a Go package. It may be a subset. +type Package struct { + Name string + Interfaces []*Interface + DotImports []string +} + +func (pkg *Package) Print(w io.Writer) { + fmt.Fprintf(w, "package %s\n", pkg.Name) + for _, intf := range pkg.Interfaces { + intf.Print(w) + } +} + +// Imports returns the imports needed by the Package as a set of import paths. +func (pkg *Package) Imports() map[string]bool { + im := make(map[string]bool) + for _, intf := range pkg.Interfaces { + intf.addImports(im) + } + return im +} + +// Interface is a Go interface. +type Interface struct { + Name string + Methods []*Method +} + +func (intf *Interface) Print(w io.Writer) { + fmt.Fprintf(w, "interface %s\n", intf.Name) + for _, m := range intf.Methods { + m.Print(w) + } +} + +func (intf *Interface) addImports(im map[string]bool) { + for _, m := range intf.Methods { + m.addImports(im) + } +} + +// Method is a single method of an interface. +type Method struct { + Name string + In, Out []*Parameter + Variadic *Parameter // may be nil +} + +func (m *Method) Print(w io.Writer) { + fmt.Fprintf(w, " - method %s\n", m.Name) + if len(m.In) > 0 { + fmt.Fprintf(w, " in:\n") + for _, p := range m.In { + p.Print(w) + } + } + if m.Variadic != nil { + fmt.Fprintf(w, " ...:\n") + m.Variadic.Print(w) + } + if len(m.Out) > 0 { + fmt.Fprintf(w, " out:\n") + for _, p := range m.Out { + p.Print(w) + } + } +} + +func (m *Method) addImports(im map[string]bool) { + for _, p := range m.In { + p.Type.addImports(im) + } + if m.Variadic != nil { + m.Variadic.Type.addImports(im) + } + for _, p := range m.Out { + p.Type.addImports(im) + } +} + +// Parameter is an argument or return parameter of a method. +type Parameter struct { + Name string // may be empty + Type Type +} + +func (p *Parameter) Print(w io.Writer) { + n := p.Name + if n == "" { + n = `""` + } + fmt.Fprintf(w, " - %v: %v\n", n, p.Type.String(nil, "")) +} + +// Type is a Go type. +type Type interface { + String(pm map[string]string, pkgOverride string) string + addImports(im map[string]bool) +} + +func init() { + gob.Register(&ArrayType{}) + gob.Register(&ChanType{}) + gob.Register(&FuncType{}) + gob.Register(&MapType{}) + gob.Register(&NamedType{}) + gob.Register(&PointerType{}) + + // Call gob.RegisterName to make sure it has the consistent name registered + // for both gob decoder and encoder. + // + // For a non-pointer type, gob.Register will try to get package full path by + // calling rt.PkgPath() for a name to register. If your project has vendor + // directory, it is possible that PkgPath will get a path like this: + // ../../../vendor/github.com/golang/mock/mockgen/model + gob.RegisterName(pkgPath+".PredeclaredType", PredeclaredType("")) +} + +// ArrayType is an array or slice type. +type ArrayType struct { + Len int // -1 for slices, >= 0 for arrays + Type Type +} + +func (at *ArrayType) String(pm map[string]string, pkgOverride string) string { + s := "[]" + if at.Len > -1 { + s = fmt.Sprintf("[%d]", at.Len) + } + return s + at.Type.String(pm, pkgOverride) +} + +func (at *ArrayType) addImports(im map[string]bool) { at.Type.addImports(im) } + +// ChanType is a channel type. +type ChanType struct { + Dir ChanDir // 0, 1 or 2 + Type Type +} + +func (ct *ChanType) String(pm map[string]string, pkgOverride string) string { + s := ct.Type.String(pm, pkgOverride) + if ct.Dir == RecvDir { + return "<-chan " + s + } + if ct.Dir == SendDir { + return "chan<- " + s + } + return "chan " + s +} + +func (ct *ChanType) addImports(im map[string]bool) { ct.Type.addImports(im) } + +// ChanDir is a channel direction. +type ChanDir int + +const ( + RecvDir ChanDir = 1 + SendDir ChanDir = 2 +) + +// FuncType is a function type. +type FuncType struct { + In, Out []*Parameter + Variadic *Parameter // may be nil +} + +func (ft *FuncType) String(pm map[string]string, pkgOverride string) string { + args := make([]string, len(ft.In)) + for i, p := range ft.In { + args[i] = p.Type.String(pm, pkgOverride) + } + if ft.Variadic != nil { + args = append(args, "..."+ft.Variadic.Type.String(pm, pkgOverride)) + } + rets := make([]string, len(ft.Out)) + for i, p := range ft.Out { + rets[i] = p.Type.String(pm, pkgOverride) + } + retString := strings.Join(rets, ", ") + if nOut := len(ft.Out); nOut == 1 { + retString = " " + retString + } else if nOut > 1 { + retString = " (" + retString + ")" + } + return "func(" + strings.Join(args, ", ") + ")" + retString +} + +func (ft *FuncType) addImports(im map[string]bool) { + for _, p := range ft.In { + p.Type.addImports(im) + } + if ft.Variadic != nil { + ft.Variadic.Type.addImports(im) + } + for _, p := range ft.Out { + p.Type.addImports(im) + } +} + +// MapType is a map type. +type MapType struct { + Key, Value Type +} + +func (mt *MapType) String(pm map[string]string, pkgOverride string) string { + return "map[" + mt.Key.String(pm, pkgOverride) + "]" + mt.Value.String(pm, pkgOverride) +} + +func (mt *MapType) addImports(im map[string]bool) { + mt.Key.addImports(im) + mt.Value.addImports(im) +} + +// NamedType is an exported type in a package. +type NamedType struct { + Package string // may be empty + Type string // TODO: should this be typed Type? +} + +func (nt *NamedType) String(pm map[string]string, pkgOverride string) string { + // TODO: is this right? + if pkgOverride == nt.Package { + return nt.Type + } + return pm[nt.Package] + "." + nt.Type +} +func (nt *NamedType) addImports(im map[string]bool) { + if nt.Package != "" { + im[nt.Package] = true + } +} + +// PointerType is a pointer to another type. +type PointerType struct { + Type Type +} + +func (pt *PointerType) String(pm map[string]string, pkgOverride string) string { + return "*" + pt.Type.String(pm, pkgOverride) +} +func (pt *PointerType) addImports(im map[string]bool) { pt.Type.addImports(im) } + +// PredeclaredType is a predeclared type such as "int". +type PredeclaredType string + +func (pt PredeclaredType) String(pm map[string]string, pkgOverride string) string { return string(pt) } +func (pt PredeclaredType) addImports(im map[string]bool) {} + +// The following code is intended to be called by the program generated by ../reflect.go. + +func InterfaceFromInterfaceType(it reflect.Type) (*Interface, error) { + if it.Kind() != reflect.Interface { + return nil, fmt.Errorf("%v is not an interface", it) + } + intf := &Interface{} + + for i := 0; i < it.NumMethod(); i++ { + mt := it.Method(i) + // TODO: need to skip unexported methods? or just raise an error? + m := &Method{ + Name: mt.Name, + } + + var err error + m.In, m.Variadic, m.Out, err = funcArgsFromType(mt.Type) + if err != nil { + return nil, err + } + + intf.Methods = append(intf.Methods, m) + } + + return intf, nil +} + +// t's Kind must be a reflect.Func. +func funcArgsFromType(t reflect.Type) (in []*Parameter, variadic *Parameter, out []*Parameter, err error) { + nin := t.NumIn() + if t.IsVariadic() { + nin-- + } + var p *Parameter + for i := 0; i < nin; i++ { + p, err = parameterFromType(t.In(i)) + if err != nil { + return + } + in = append(in, p) + } + if t.IsVariadic() { + p, err = parameterFromType(t.In(nin).Elem()) + if err != nil { + return + } + variadic = p + } + for i := 0; i < t.NumOut(); i++ { + p, err = parameterFromType(t.Out(i)) + if err != nil { + return + } + out = append(out, p) + } + return +} + +func parameterFromType(t reflect.Type) (*Parameter, error) { + tt, err := typeFromType(t) + if err != nil { + return nil, err + } + return &Parameter{Type: tt}, nil +} + +var errorType = reflect.TypeOf((*error)(nil)).Elem() + +var byteType = reflect.TypeOf(byte(0)) + +func typeFromType(t reflect.Type) (Type, error) { + // Hack workaround for https://golang.org/issue/3853. + // This explicit check should not be necessary. + if t == byteType { + return PredeclaredType("byte"), nil + } + + if imp := t.PkgPath(); imp != "" { + // PkgPath might return a path that includes "vendor" + // These paths do not compile, so we need to remove everything + // up to and including "/vendor/" + // see https://github.com/golang/go/issues/12019 + if i := strings.LastIndex(imp, "/vendor/"); i != -1 { + imp = imp[i+len("/vendor/"):] + } + return &NamedType{ + Package: imp, + Type: t.Name(), + }, nil + } + + // only unnamed or predeclared types after here + + // Lots of types have element types. Let's do the parsing and error checking for all of them. + var elemType Type + switch t.Kind() { + case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice: + var err error + elemType, err = typeFromType(t.Elem()) + if err != nil { + return nil, err + } + } + + switch t.Kind() { + case reflect.Array: + return &ArrayType{ + Len: t.Len(), + Type: elemType, + }, nil + case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, + reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String: + return PredeclaredType(t.Kind().String()), nil + case reflect.Chan: + var dir ChanDir + switch t.ChanDir() { + case reflect.RecvDir: + dir = RecvDir + case reflect.SendDir: + dir = SendDir + } + return &ChanType{ + Dir: dir, + Type: elemType, + }, nil + case reflect.Func: + in, variadic, out, err := funcArgsFromType(t) + if err != nil { + return nil, err + } + return &FuncType{ + In: in, + Out: out, + Variadic: variadic, + }, nil + case reflect.Interface: + // Two special interfaces. + if t.NumMethod() == 0 { + return PredeclaredType("interface{}"), nil + } + if t == errorType { + return PredeclaredType("error"), nil + } + case reflect.Map: + kt, err := typeFromType(t.Key()) + if err != nil { + return nil, err + } + return &MapType{ + Key: kt, + Value: elemType, + }, nil + case reflect.Ptr: + return &PointerType{ + Type: elemType, + }, nil + case reflect.Slice: + return &ArrayType{ + Len: -1, + Type: elemType, + }, nil + case reflect.Struct: + if t.NumField() == 0 { + return PredeclaredType("struct{}"), nil + } + } + + // TODO: Struct, UnsafePointer + return nil, fmt.Errorf("can't yet turn %v (%v) into a model.Type", t, t.Kind()) +} diff --git a/vendor/github.com/golang/mock/mockgen/parse.go b/vendor/github.com/golang/mock/mockgen/parse.go new file mode 100644 index 00000000..3060c481 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/parse.go @@ -0,0 +1,504 @@ +// Copyright 2012 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +// This file contains the model construction by parsing source files. + +import ( + "flag" + "fmt" + "go/ast" + "go/build" + "go/parser" + "go/token" + "log" + "path" + "path/filepath" + "strconv" + "strings" + + "github.com/golang/mock/mockgen/model" +) + +var ( + imports = flag.String("imports", "", "(source mode) Comma-separated name=path pairs of explicit imports to use.") + auxFiles = flag.String("aux_files", "", "(source mode) Comma-separated pkg=path pairs of auxiliary Go source files.") +) + +// TODO: simplify error reporting + +func ParseFile(source string) (*model.Package, error) { + srcDir, err := filepath.Abs(filepath.Dir(source)) + if err != nil { + return nil, fmt.Errorf("failed getting source directory: %v", err) + } + + var packageImport string + if p, err := build.ImportDir(srcDir, 0); err == nil { + packageImport = p.ImportPath + } // TODO: should we fail if this returns an error? + + fs := token.NewFileSet() + file, err := parser.ParseFile(fs, source, nil, 0) + if err != nil { + return nil, fmt.Errorf("failed parsing source file %v: %v", source, err) + } + + p := &fileParser{ + fileSet: fs, + imports: make(map[string]string), + importedInterfaces: make(map[string]map[string]*ast.InterfaceType), + auxInterfaces: make(map[string]map[string]*ast.InterfaceType), + srcDir: srcDir, + } + + // Handle -imports. + dotImports := make(map[string]bool) + if *imports != "" { + for _, kv := range strings.Split(*imports, ",") { + eq := strings.Index(kv, "=") + k, v := kv[:eq], kv[eq+1:] + if k == "." { + // TODO: Catch dupes? + dotImports[v] = true + } else { + // TODO: Catch dupes? + p.imports[k] = v + } + } + } + + // Handle -aux_files. + if err := p.parseAuxFiles(*auxFiles); err != nil { + return nil, err + } + p.addAuxInterfacesFromFile(packageImport, file) // this file + + pkg, err := p.parseFile(packageImport, file) + if err != nil { + return nil, err + } + pkg.DotImports = make([]string, 0, len(dotImports)) + for path := range dotImports { + pkg.DotImports = append(pkg.DotImports, path) + } + return pkg, nil +} + +type fileParser struct { + fileSet *token.FileSet + imports map[string]string // package name => import path + importedInterfaces map[string]map[string]*ast.InterfaceType // package (or "") => name => interface + + auxFiles []*ast.File + auxInterfaces map[string]map[string]*ast.InterfaceType // package (or "") => name => interface + + srcDir string +} + +func (p *fileParser) errorf(pos token.Pos, format string, args ...interface{}) error { + ps := p.fileSet.Position(pos) + format = "%s:%d:%d: " + format + args = append([]interface{}{ps.Filename, ps.Line, ps.Column}, args...) + return fmt.Errorf(format, args...) +} + +func (p *fileParser) parseAuxFiles(auxFiles string) error { + auxFiles = strings.TrimSpace(auxFiles) + if auxFiles == "" { + return nil + } + for _, kv := range strings.Split(auxFiles, ",") { + parts := strings.SplitN(kv, "=", 2) + if len(parts) != 2 { + return fmt.Errorf("bad aux file spec: %v", kv) + } + pkg, fpath := parts[0], parts[1] + + file, err := parser.ParseFile(p.fileSet, fpath, nil, 0) + if err != nil { + return err + } + p.auxFiles = append(p.auxFiles, file) + p.addAuxInterfacesFromFile(pkg, file) + } + return nil +} + +func (p *fileParser) addAuxInterfacesFromFile(pkg string, file *ast.File) { + if _, ok := p.auxInterfaces[pkg]; !ok { + p.auxInterfaces[pkg] = make(map[string]*ast.InterfaceType) + } + for ni := range iterInterfaces(file) { + p.auxInterfaces[pkg][ni.name.Name] = ni.it + } +} + +// parseFile loads all file imports and auxiliary files import into the +// fileParser, parses all file interfaces and returns package model. +func (p *fileParser) parseFile(importPath string, file *ast.File) (*model.Package, error) { + allImports := importsOfFile(file) + // Don't stomp imports provided by -imports. Those should take precedence. + for pkg, path := range allImports { + if _, ok := p.imports[pkg]; !ok { + p.imports[pkg] = path + } + } + // Add imports from auxiliary files, which might be needed for embedded interfaces. + // Don't stomp any other imports. + for _, f := range p.auxFiles { + for pkg, path := range importsOfFile(f) { + if _, ok := p.imports[pkg]; !ok { + p.imports[pkg] = path + } + } + } + + var is []*model.Interface + for ni := range iterInterfaces(file) { + i, err := p.parseInterface(ni.name.String(), importPath, ni.it) + if err != nil { + return nil, err + } + is = append(is, i) + } + return &model.Package{ + Name: file.Name.String(), + Interfaces: is, + }, nil +} + +// parsePackage loads package specified by path, parses it and populates +// corresponding imports and importedInterfaces into the fileParser. +func (p *fileParser) parsePackage(path string) error { + var pkgs map[string]*ast.Package + if imp, err := build.Import(path, p.srcDir, build.FindOnly); err != nil { + return err + } else if pkgs, err = parser.ParseDir(p.fileSet, imp.Dir, nil, 0); err != nil { + return err + } + for _, pkg := range pkgs { + file := ast.MergePackageFiles(pkg, ast.FilterFuncDuplicates|ast.FilterUnassociatedComments|ast.FilterImportDuplicates) + if _, ok := p.importedInterfaces[path]; !ok { + p.importedInterfaces[path] = make(map[string]*ast.InterfaceType) + } + for ni := range iterInterfaces(file) { + p.importedInterfaces[path][ni.name.Name] = ni.it + } + for pkgName, pkgPath := range importsOfFile(file) { + if _, ok := p.imports[pkgName]; !ok { + p.imports[pkgName] = pkgPath + } + } + } + return nil +} + +func (p *fileParser) parseInterface(name, pkg string, it *ast.InterfaceType) (*model.Interface, error) { + intf := &model.Interface{Name: name} + for _, field := range it.Methods.List { + switch v := field.Type.(type) { + case *ast.FuncType: + if nn := len(field.Names); nn != 1 { + return nil, fmt.Errorf("expected one name for interface %v, got %d", intf.Name, nn) + } + m := &model.Method{ + Name: field.Names[0].String(), + } + var err error + m.In, m.Variadic, m.Out, err = p.parseFunc(pkg, v) + if err != nil { + return nil, err + } + intf.Methods = append(intf.Methods, m) + case *ast.Ident: + // Embedded interface in this package. + ei := p.auxInterfaces[pkg][v.String()] + if ei == nil { + if ei = p.importedInterfaces[pkg][v.String()]; ei == nil { + return nil, p.errorf(v.Pos(), "unknown embedded interface %s", v.String()) + } + } + eintf, err := p.parseInterface(v.String(), pkg, ei) + if err != nil { + return nil, err + } + // Copy the methods. + // TODO: apply shadowing rules. + for _, m := range eintf.Methods { + intf.Methods = append(intf.Methods, m) + } + case *ast.SelectorExpr: + // Embedded interface in another package. + fpkg, sel := v.X.(*ast.Ident).String(), v.Sel.String() + epkg, ok := p.imports[fpkg] + if !ok { + return nil, p.errorf(v.X.Pos(), "unknown package %s", fpkg) + } + ei := p.auxInterfaces[fpkg][sel] + if ei == nil { + fpkg = epkg + if _, ok = p.importedInterfaces[epkg]; !ok { + if err := p.parsePackage(epkg); err != nil { + return nil, p.errorf(v.Pos(), "could not parse package %s: %v", fpkg, err) + } + } + if ei = p.importedInterfaces[epkg][sel]; ei == nil { + return nil, p.errorf(v.Pos(), "unknown embedded interface %s.%s", fpkg, sel) + } + } + eintf, err := p.parseInterface(sel, fpkg, ei) + if err != nil { + return nil, err + } + // Copy the methods. + // TODO: apply shadowing rules. + for _, m := range eintf.Methods { + intf.Methods = append(intf.Methods, m) + } + default: + return nil, fmt.Errorf("don't know how to mock method of type %T", field.Type) + } + } + return intf, nil +} + +func (p *fileParser) parseFunc(pkg string, f *ast.FuncType) (in []*model.Parameter, variadic *model.Parameter, out []*model.Parameter, err error) { + if f.Params != nil { + regParams := f.Params.List + if isVariadic(f) { + n := len(regParams) + varParams := regParams[n-1:] + regParams = regParams[:n-1] + vp, err := p.parseFieldList(pkg, varParams) + if err != nil { + return nil, nil, nil, p.errorf(varParams[0].Pos(), "failed parsing variadic argument: %v", err) + } + variadic = vp[0] + } + in, err = p.parseFieldList(pkg, regParams) + if err != nil { + return nil, nil, nil, p.errorf(f.Pos(), "failed parsing arguments: %v", err) + } + } + if f.Results != nil { + out, err = p.parseFieldList(pkg, f.Results.List) + if err != nil { + return nil, nil, nil, p.errorf(f.Pos(), "failed parsing returns: %v", err) + } + } + return +} + +func (p *fileParser) parseFieldList(pkg string, fields []*ast.Field) ([]*model.Parameter, error) { + nf := 0 + for _, f := range fields { + nn := len(f.Names) + if nn == 0 { + nn = 1 // anonymous parameter + } + nf += nn + } + if nf == 0 { + return nil, nil + } + ps := make([]*model.Parameter, nf) + i := 0 // destination index + for _, f := range fields { + t, err := p.parseType(pkg, f.Type) + if err != nil { + return nil, err + } + + if len(f.Names) == 0 { + // anonymous arg + ps[i] = &model.Parameter{Type: t} + i++ + continue + } + for _, name := range f.Names { + ps[i] = &model.Parameter{Name: name.Name, Type: t} + i++ + } + } + return ps, nil +} + +func (p *fileParser) parseType(pkg string, typ ast.Expr) (model.Type, error) { + switch v := typ.(type) { + case *ast.ArrayType: + ln := -1 + if v.Len != nil { + x, err := strconv.Atoi(v.Len.(*ast.BasicLit).Value) + if err != nil { + return nil, p.errorf(v.Len.Pos(), "bad array size: %v", err) + } + ln = x + } + t, err := p.parseType(pkg, v.Elt) + if err != nil { + return nil, err + } + return &model.ArrayType{Len: ln, Type: t}, nil + case *ast.ChanType: + t, err := p.parseType(pkg, v.Value) + if err != nil { + return nil, err + } + var dir model.ChanDir + if v.Dir == ast.SEND { + dir = model.SendDir + } + if v.Dir == ast.RECV { + dir = model.RecvDir + } + return &model.ChanType{Dir: dir, Type: t}, nil + case *ast.Ellipsis: + // assume we're parsing a variadic argument + return p.parseType(pkg, v.Elt) + case *ast.FuncType: + in, variadic, out, err := p.parseFunc(pkg, v) + if err != nil { + return nil, err + } + return &model.FuncType{In: in, Out: out, Variadic: variadic}, nil + case *ast.Ident: + if v.IsExported() { + // `pkg` may be an aliased imported pkg + // if so, patch the import w/ the fully qualified import + maybeImportedPkg, ok := p.imports[pkg] + if ok { + pkg = maybeImportedPkg + } + // assume type in this package + return &model.NamedType{Package: pkg, Type: v.Name}, nil + } else { + // assume predeclared type + return model.PredeclaredType(v.Name), nil + } + case *ast.InterfaceType: + if v.Methods != nil && len(v.Methods.List) > 0 { + return nil, p.errorf(v.Pos(), "can't handle non-empty unnamed interface types") + } + return model.PredeclaredType("interface{}"), nil + case *ast.MapType: + key, err := p.parseType(pkg, v.Key) + if err != nil { + return nil, err + } + value, err := p.parseType(pkg, v.Value) + if err != nil { + return nil, err + } + return &model.MapType{Key: key, Value: value}, nil + case *ast.SelectorExpr: + pkgName := v.X.(*ast.Ident).String() + pkg, ok := p.imports[pkgName] + if !ok { + return nil, p.errorf(v.Pos(), "unknown package %q", pkgName) + } + return &model.NamedType{Package: pkg, Type: v.Sel.String()}, nil + case *ast.StarExpr: + t, err := p.parseType(pkg, v.X) + if err != nil { + return nil, err + } + return &model.PointerType{Type: t}, nil + case *ast.StructType: + if v.Fields != nil && len(v.Fields.List) > 0 { + return nil, p.errorf(v.Pos(), "can't handle non-empty unnamed struct types") + } + return model.PredeclaredType("struct{}"), nil + } + + return nil, fmt.Errorf("don't know how to parse type %T", typ) +} + +// importsOfFile returns a map of package name to import path +// of the imports in file. +func importsOfFile(file *ast.File) map[string]string { + m := make(map[string]string) + for _, is := range file.Imports { + var pkgName string + importPath := is.Path.Value[1 : len(is.Path.Value)-1] // remove quotes + + if is.Name != nil { + // Named imports are always certain. + if is.Name.Name == "_" { + continue + } + pkgName = removeDot(is.Name.Name) + } else { + pkg, err := build.Import(importPath, "", 0) + if err != nil { + // Fallback to import path suffix. Note that this is uncertain. + _, last := path.Split(importPath) + // If the last path component has dots, the first dot-delimited + // field is used as the name. + pkgName = strings.SplitN(last, ".", 2)[0] + } else { + pkgName = pkg.Name + } + } + + if _, ok := m[pkgName]; ok { + log.Fatalf("imported package collision: %q imported twice", pkgName) + } + m[pkgName] = importPath + } + return m +} + +type namedInterface struct { + name *ast.Ident + it *ast.InterfaceType +} + +// Create an iterator over all interfaces in file. +func iterInterfaces(file *ast.File) <-chan namedInterface { + ch := make(chan namedInterface) + go func() { + for _, decl := range file.Decls { + gd, ok := decl.(*ast.GenDecl) + if !ok || gd.Tok != token.TYPE { + continue + } + for _, spec := range gd.Specs { + ts, ok := spec.(*ast.TypeSpec) + if !ok { + continue + } + it, ok := ts.Type.(*ast.InterfaceType) + if !ok { + continue + } + + ch <- namedInterface{ts.Name, it} + } + } + close(ch) + }() + return ch +} + +// isVariadic returns whether the function is variadic. +func isVariadic(f *ast.FuncType) bool { + nargs := len(f.Params.List) + if nargs == 0 { + return false + } + _, ok := f.Params.List[nargs-1].Type.(*ast.Ellipsis) + return ok +} diff --git a/vendor/github.com/golang/mock/mockgen/parse_test.go b/vendor/github.com/golang/mock/mockgen/parse_test.go new file mode 100644 index 00000000..47e4d79c --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/parse_test.go @@ -0,0 +1,108 @@ +package main + +import ( + "go/ast" + "go/parser" + "go/token" + "testing" +) + +func TestFileParser_ParseFile(t *testing.T) { + fs := token.NewFileSet() + file, err := parser.ParseFile(fs, "tests/custom_package_name/greeter/greeter.go", nil, 0) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + p := fileParser{ + fileSet: fs, + imports: make(map[string]string), + importedInterfaces: make(map[string]map[string]*ast.InterfaceType), + } + + pkg, err := p.parseFile("", file) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + checkGreeterImports(t, p.imports) + + expectedName := "greeter" + if pkg.Name != expectedName { + t.Fatalf("Expected name to be %v but got %v", expectedName, pkg.Name) + } + + expectedInterfaceName := "InputMaker" + if pkg.Interfaces[0].Name != expectedInterfaceName { + t.Fatalf("Expected interface name to be %v but got %v", expectedInterfaceName, pkg.Interfaces[0].Name) + } +} + +func TestFileParser_ParsePackage(t *testing.T) { + fs := token.NewFileSet() + _, err := parser.ParseFile(fs, "tests/custom_package_name/greeter/greeter.go", nil, 0) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + p := fileParser{ + fileSet: fs, + imports: make(map[string]string), + importedInterfaces: make(map[string]map[string]*ast.InterfaceType), + } + + err = p.parsePackage("github.com/golang/mock/mockgen/tests/custom_package_name/greeter") + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + checkGreeterImports(t, p.imports) +} + +func TestImportsOfFile(t *testing.T) { + fs := token.NewFileSet() + file, err := parser.ParseFile(fs, "tests/custom_package_name/greeter/greeter.go", nil, 0) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + imports := importsOfFile(file) + checkGreeterImports(t, imports) +} + +func checkGreeterImports(t *testing.T, imports map[string]string) { + // check that imports have stdlib package "fmt" + if fmtPackage, ok := imports["fmt"]; !ok { + t.Errorf("Expected imports to have key \"fmt\"") + } else { + expectedFmtPackage := "fmt" + if fmtPackage != expectedFmtPackage { + t.Errorf("Expected fmt key to have value %s but got %s", expectedFmtPackage, fmtPackage) + } + } + + // check that imports have package named "validator" + if validatorPackage, ok := imports["validator"]; !ok { + t.Errorf("Expected imports to have key \"fmt\"") + } else { + expectedValidatorPackage := "github.com/golang/mock/mockgen/tests/custom_package_name/validator" + if validatorPackage != expectedValidatorPackage { + t.Errorf("Expected validator key to have value %s but got %s", expectedValidatorPackage, validatorPackage) + } + } + + // check that imports have package named "client" + if clientPackage, ok := imports["client"]; !ok { + t.Errorf("Expected imports to have key \"client\"") + } else { + expectedClientPackage := "github.com/golang/mock/mockgen/tests/custom_package_name/client/v1" + if clientPackage != expectedClientPackage { + t.Errorf("Expected client key to have value %s but got %s", expectedClientPackage, clientPackage) + } + } + + // check that imports don't have package named "v1" + if _, ok := imports["v1"]; ok { + t.Errorf("Expected import not to have key \"v1\"") + } +} diff --git a/vendor/github.com/golang/mock/mockgen/reflect.go b/vendor/github.com/golang/mock/mockgen/reflect.go new file mode 100644 index 00000000..915f1331 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/reflect.go @@ -0,0 +1,197 @@ +// Copyright 2012 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +// This file contains the model construction by reflection. + +import ( + "bytes" + "encoding/gob" + "flag" + "go/build" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "text/template" + + "github.com/golang/mock/mockgen/model" +) + +var ( + progOnly = flag.Bool("prog_only", false, "(reflect mode) Only generate the reflection program; write it to stdout and exit.") + execOnly = flag.String("exec_only", "", "(reflect mode) If set, execute this reflection program.") + buildFlags = flag.String("build_flags", "", "(reflect mode) Additional flags for go build.") +) + +func writeProgram(importPath string, symbols []string) ([]byte, error) { + var program bytes.Buffer + data := reflectData{ + ImportPath: importPath, + Symbols: symbols, + } + if err := reflectProgram.Execute(&program, &data); err != nil { + return nil, err + } + return program.Bytes(), nil +} + +// run the given command and parse the output as a model.Package. +func run(command string) (*model.Package, error) { + // Run the program. + cmd := exec.Command(command) + var stdout bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return nil, err + } + + // Process output. + var pkg model.Package + if err := gob.NewDecoder(&stdout).Decode(&pkg); err != nil { + return nil, err + } + return &pkg, nil +} + +// runInDir writes the given program into the given dir, runs it there, and +// parses the output as a model.Package. +func runInDir(program []byte, dir string) (*model.Package, error) { + // We use TempDir instead of TempFile so we can control the filename. + tmpDir, err := ioutil.TempDir(dir, "gomock_reflect_") + if err != nil { + return nil, err + } + defer func() { os.RemoveAll(tmpDir) }() + const progSource = "prog.go" + var progBinary = "prog.bin" + if runtime.GOOS == "windows" { + // Windows won't execute a program unless it has a ".exe" suffix. + progBinary += ".exe" + } + + if err := ioutil.WriteFile(filepath.Join(tmpDir, progSource), program, 0600); err != nil { + return nil, err + } + + cmdArgs := []string{} + cmdArgs = append(cmdArgs, "build") + if *buildFlags != "" { + cmdArgs = append(cmdArgs, *buildFlags) + } + cmdArgs = append(cmdArgs, "-o", progBinary, progSource) + + // Build the program. + cmd := exec.Command("go", cmdArgs...) + cmd.Dir = tmpDir + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return nil, err + } + return run(filepath.Join(tmpDir, progBinary)) +} + +func Reflect(importPath string, symbols []string) (*model.Package, error) { + // TODO: sanity check arguments + + if *execOnly != "" { + return run(*execOnly) + } + + program, err := writeProgram(importPath, symbols) + if err != nil { + return nil, err + } + + if *progOnly { + os.Stdout.Write(program) + os.Exit(0) + } + + wd, _ := os.Getwd() + + // Try to run the program in the same directory as the input package. + if p, err := build.Import(importPath, wd, build.FindOnly); err == nil { + dir := p.Dir + if p, err := runInDir(program, dir); err == nil { + return p, nil + } + } + + // Since that didn't work, try to run it in the current working directory. + if p, err := runInDir(program, wd); err == nil { + return p, nil + } + // Since that didn't work, try to run it in a standard temp directory. + return runInDir(program, "") +} + +type reflectData struct { + ImportPath string + Symbols []string +} + +// This program reflects on an interface value, and prints the +// gob encoding of a model.Package to standard output. +// JSON doesn't work because of the model.Type interface. +var reflectProgram = template.Must(template.New("program").Parse(` +package main + +import ( + "encoding/gob" + "fmt" + "os" + "path" + "reflect" + + "github.com/golang/mock/mockgen/model" + + pkg_ {{printf "%q" .ImportPath}} +) + +func main() { + its := []struct{ + sym string + typ reflect.Type + }{ + {{range .Symbols}} + { {{printf "%q" .}}, reflect.TypeOf((*pkg_.{{.}})(nil)).Elem()}, + {{end}} + } + pkg := &model.Package{ + // NOTE: This behaves contrary to documented behaviour if the + // package name is not the final component of the import path. + // The reflect package doesn't expose the package name, though. + Name: path.Base({{printf "%q" .ImportPath}}), + } + + for _, it := range its { + intf, err := model.InterfaceFromInterfaceType(it.typ) + if err != nil { + fmt.Fprintf(os.Stderr, "Reflection: %v\n", err) + os.Exit(1) + } + intf.Name = it.sym + pkg.Interfaces = append(pkg.Interfaces, intf) + } + if err := gob.NewEncoder(os.Stdout).Encode(pkg); err != nil { + fmt.Fprintf(os.Stderr, "gob encode: %v\n", err) + os.Exit(1) + } +} +`)) diff --git a/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/README.md b/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/README.md new file mode 100644 index 00000000..63955f6a --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/README.md @@ -0,0 +1,36 @@ +Embedded interfaces in `aux_files` generate `unknown embedded interface XXX` errors. +See below for example of the problem: +``` +// source +import ( + alias "some.org/package/imported" +) + +type Source interface { + alias.Foreign +} +``` + +``` +// some.org/package/imported +type Foreign interface { + Embedded +} + +type Embedded interface {} +``` + +Attempting to generate a mock will result in an `unknown embedded interface Embedded`. +The issue is that the `fileParser` stores `auxInterfaces` underneath the package name +explicitly specified in the `aux_files` flag. + +In the `parseInterface` method, there is an incorrect assumption about an embedded interface +always being in the source file. +``` +case *ast.Ident: + // Embedded interface in this package. + ei := p.auxInterfaces[""][v.String()] + if ei == nil { + return nil, p.errorf(v.Pos(), "unknown embedded interface %s", v.String()) + } +``` diff --git a/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/bugreport.go b/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/bugreport.go new file mode 100644 index 00000000..618a7fd3 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/bugreport.go @@ -0,0 +1,18 @@ +//go:generate mockgen -aux_files faux=faux/faux.go -destination bugreport_mock.go -package bugreport -source=bugreport.go Example + +package bugreport + +import ( + "log" + + "github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/faux" +) + +// Source is an interface w/ an embedded foreign interface +type Source interface { + faux.Foreign +} + +func CallForeignMethod(s Source) { + log.Println(s.Method()) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/bugreport_mock.go b/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/bugreport_mock.go new file mode 100644 index 00000000..0feb02ab --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/bugreport_mock.go @@ -0,0 +1,46 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: bugreport.go + +// Package bugreport is a generated GoMock package. +package bugreport + +import ( + gomock "github.com/golang/mock/gomock" + faux "github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/faux" + reflect "reflect" +) + +// MockSource is a mock of Source interface +type MockSource struct { + ctrl *gomock.Controller + recorder *MockSourceMockRecorder +} + +// MockSourceMockRecorder is the mock recorder for MockSource +type MockSourceMockRecorder struct { + mock *MockSource +} + +// NewMockSource creates a new mock instance +func NewMockSource(ctrl *gomock.Controller) *MockSource { + mock := &MockSource{ctrl: ctrl} + mock.recorder = &MockSourceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockSource) EXPECT() *MockSourceMockRecorder { + return m.recorder +} + +// Method mocks base method +func (m *MockSource) Method() faux.Return { + ret := m.ctrl.Call(m, "Method") + ret0, _ := ret[0].(faux.Return) + return ret0 +} + +// Method indicates an expected call of Method +func (mr *MockSourceMockRecorder) Method() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Method", reflect.TypeOf((*MockSource)(nil).Method)) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/bugreport_test.go b/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/bugreport_test.go new file mode 100644 index 00000000..acfca322 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/bugreport_test.go @@ -0,0 +1,18 @@ +package bugreport + +import ( + "testing" + + "github.com/golang/mock/gomock" +) + +// TestValidInterface assesses whether or not the generated mock is valid +func TestValidInterface(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + s := NewMockSource(ctrl) + s.EXPECT().Method().Return("") + + CallForeignMethod(s) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/faux/faux.go b/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/faux/faux.go new file mode 100644 index 00000000..bafd034f --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/aux_imports_embedded_interface/faux/faux.go @@ -0,0 +1,10 @@ +package faux + +type Foreign interface { + Method() Return + Embedded +} + +type Embedded interface{} + +type Return interface{} diff --git a/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/README.md b/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/README.md new file mode 100644 index 00000000..b16da215 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/README.md @@ -0,0 +1,22 @@ +# Tests for custom package names + +This directory contains test for mockgen generating mocks when imported package +name does not match import path suffix. For example, package with name "client" +is located under import path "github.com/golang/mock/mockgen/tests/custom_package_name/client/v1". + +Prior to this patch: + + $ go generate greeter/greeter.go + 2018/03/05 22:44:52 Loading input failed: greeter.go:17:11: failed parsing returns: greeter.go:17:14: unknown package "client" + greeter/greeter.go:1: running "mockgen": exit status 1 + +This can be fixed by manually providing `-imports` flag, like `-imports client=github.com/golang/mock/mockgen/tests/custom_package_name/client/v1`. +But, mockgen should be able to automatically resolve package names in such situations. + +With this patch applied: + + $ go generate greeter/greeter.go + $ echo $? + 0 + +Mockgen runs successfully, produced output is equal to [greeter_mock_test.go](greeter/greeter_mock_test.go) content. diff --git a/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/client/v1/client.go b/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/client/v1/client.go new file mode 100644 index 00000000..fc799d9c --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/client/v1/client.go @@ -0,0 +1,13 @@ +package client + +import "fmt" + +type Client struct{} + +func (c *Client) Greet(in GreetInput) string { + return fmt.Sprintf("Hello, %s!", in.Name) +} + +type GreetInput struct { + Name string +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/greeter/greeter.go b/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/greeter/greeter.go new file mode 100644 index 00000000..8c2d2937 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/greeter/greeter.go @@ -0,0 +1,31 @@ +//go:generate mockgen -source greeter.go -destination greeter_mock_test.go -package greeter + +package greeter + +import ( + // stdlib import + "fmt" + + // non-matching import suffix and package name + "github.com/golang/mock/mockgen/tests/custom_package_name/client/v1" + + // matching import suffix and package name + "github.com/golang/mock/mockgen/tests/custom_package_name/validator" +) + +type InputMaker interface { + MakeInput() client.GreetInput +} + +type Greeter struct { + InputMaker InputMaker + Client *client.Client +} + +func (g *Greeter) Greet() (string, error) { + in := g.InputMaker.MakeInput() + if err := validator.Validate(in.Name); err != nil { + return "", fmt.Errorf("validation failed: %v", err) + } + return g.Client.Greet(in), nil +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/greeter/greeter_mock_test.go b/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/greeter/greeter_mock_test.go new file mode 100644 index 00000000..0bf0f46f --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/greeter/greeter_mock_test.go @@ -0,0 +1,46 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: greeter.go + +// Package greeter is a generated GoMock package. +package greeter + +import ( + gomock "github.com/golang/mock/gomock" + v1 "github.com/golang/mock/mockgen/tests/custom_package_name/client/v1" + reflect "reflect" +) + +// MockInputMaker is a mock of InputMaker interface +type MockInputMaker struct { + ctrl *gomock.Controller + recorder *MockInputMakerMockRecorder +} + +// MockInputMakerMockRecorder is the mock recorder for MockInputMaker +type MockInputMakerMockRecorder struct { + mock *MockInputMaker +} + +// NewMockInputMaker creates a new mock instance +func NewMockInputMaker(ctrl *gomock.Controller) *MockInputMaker { + mock := &MockInputMaker{ctrl: ctrl} + mock.recorder = &MockInputMakerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockInputMaker) EXPECT() *MockInputMakerMockRecorder { + return m.recorder +} + +// MakeInput mocks base method +func (m *MockInputMaker) MakeInput() v1.GreetInput { + ret := m.ctrl.Call(m, "MakeInput") + ret0, _ := ret[0].(v1.GreetInput) + return ret0 +} + +// MakeInput indicates an expected call of MakeInput +func (mr *MockInputMakerMockRecorder) MakeInput() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MakeInput", reflect.TypeOf((*MockInputMaker)(nil).MakeInput)) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/greeter/greeter_test.go b/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/greeter/greeter_test.go new file mode 100644 index 00000000..f056ec81 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/greeter/greeter_test.go @@ -0,0 +1,37 @@ +package greeter + +import ( + "testing" + + "github.com/golang/mock/gomock" + "github.com/golang/mock/mockgen/tests/custom_package_name/client/v1" +) + +func TestGreeter_Greet(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + input := client.GreetInput{ + Name: "Foo", + } + + inputMaker := NewMockInputMaker(ctrl) + inputMaker.EXPECT(). + MakeInput(). + Return(input) + + g := &Greeter{ + InputMaker: inputMaker, + Client: &client.Client{}, + } + + greeting, err := g.Greet() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + expected := "Hello, Foo!" + if greeting != expected { + t.Fatalf("Expected greeting to be %v but got %v", expected, greeting) + } +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/validator/validate.go b/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/validator/validate.go new file mode 100644 index 00000000..0617c4be --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/custom_package_name/validator/validate.go @@ -0,0 +1,5 @@ +package validator + +func Validate(s string) error { + return nil +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/empty_interface/input.go b/vendor/github.com/golang/mock/mockgen/tests/empty_interface/input.go new file mode 100644 index 00000000..bbcb3fc8 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/empty_interface/input.go @@ -0,0 +1,4 @@ +//go:generate mockgen -package empty_interface -destination mock.go -source input.go +package empty_interface + +type Empty interface{} diff --git a/vendor/github.com/golang/mock/mockgen/tests/empty_interface/mock.go b/vendor/github.com/golang/mock/mockgen/tests/empty_interface/mock.go new file mode 100644 index 00000000..0fc5b0c7 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/empty_interface/mock.go @@ -0,0 +1,32 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: input.go + +// Package empty_interface is a generated GoMock package. +package empty_interface + +import ( + gomock "github.com/golang/mock/gomock" +) + +// MockEmpty is a mock of Empty interface +type MockEmpty struct { + ctrl *gomock.Controller + recorder *MockEmptyMockRecorder +} + +// MockEmptyMockRecorder is the mock recorder for MockEmpty +type MockEmptyMockRecorder struct { + mock *MockEmpty +} + +// NewMockEmpty creates a new mock instance +func NewMockEmpty(ctrl *gomock.Controller) *MockEmpty { + mock := &MockEmpty{ctrl: ctrl} + mock.recorder = &MockEmptyMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockEmpty) EXPECT() *MockEmptyMockRecorder { + return m.recorder +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/README.md b/vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/README.md new file mode 100644 index 00000000..ffb5f9f0 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/README.md @@ -0,0 +1,26 @@ +The generated mock methods use some hardcoded variable/receiver names that can +have conflicts with the argument names that are defined by the code for which +the mock is generated when using the source generation method. + +Example: + +```go +type Example interface { + Method(_m, _mr, m, mr int) +} +``` + +```go +// Method mocks base method +func (_m *MockExample) Method(_m int, _mr int, m int, mr int) { + _m.ctrl.Call(_m, "Method", _m, _mr, m, mr) +} +``` + +In the above example one of the interface method parameters is called `_m` +but unfortunately the generated receiver name is also called `_m` so the +mock code won't compile. + +The generator has to make sure that generated identifiers (e.g.: the receiver +names) are always different from the arg names that might come from external +sources. diff --git a/vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/bugreport.go b/vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/bugreport.go new file mode 100644 index 00000000..77af43de --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/bugreport.go @@ -0,0 +1,16 @@ +//go:generate mockgen -destination bugreport_mock.go -package bugreport -source=bugreport.go + +package bugreport + +type Example interface { + // _m and _mr were used by the buggy code: the '_' prefix was there hoping + // that no one will use method argument names starting with '_' reducing + // the chance of collision with generated identifiers. + // m and mr are used by the bugfixed new code, the '_' prefix has been + // removed because the new code generator changes the names of the + // generated identifiers in case they would collide with identifiers + // coming from argument names. + Method(_m, _mr, m, mr int) + + VarargMethod(_s, _x, a, ret int, varargs ...int) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/bugreport_mock.go b/vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/bugreport_mock.go new file mode 100644 index 00000000..114f967c --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/bugreport_mock.go @@ -0,0 +1,58 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: bugreport.go + +// Package bugreport is a generated GoMock package. +package bugreport + +import ( + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockExample is a mock of Example interface +type MockExample struct { + ctrl *gomock.Controller + recorder *MockExampleMockRecorder +} + +// MockExampleMockRecorder is the mock recorder for MockExample +type MockExampleMockRecorder struct { + mock *MockExample +} + +// NewMockExample creates a new mock instance +func NewMockExample(ctrl *gomock.Controller) *MockExample { + mock := &MockExample{ctrl: ctrl} + mock.recorder = &MockExampleMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockExample) EXPECT() *MockExampleMockRecorder { + return m.recorder +} + +// Method mocks base method +func (m_2 *MockExample) Method(_m, _mr, m, mr int) { + m_2.ctrl.Call(m_2, "Method", _m, _mr, m, mr) +} + +// Method indicates an expected call of Method +func (mr_2 *MockExampleMockRecorder) Method(_m, _mr, m, mr interface{}) *gomock.Call { + return mr_2.mock.ctrl.RecordCallWithMethodType(mr_2.mock, "Method", reflect.TypeOf((*MockExample)(nil).Method), _m, _mr, m, mr) +} + +// VarargMethod mocks base method +func (m *MockExample) VarargMethod(_s, _x, a, ret int, varargs ...int) { + varargs_2 := []interface{}{_s, _x, a, ret} + for _, a_2 := range varargs { + varargs_2 = append(varargs_2, a_2) + } + m.ctrl.Call(m, "VarargMethod", varargs_2...) +} + +// VarargMethod indicates an expected call of VarargMethod +func (mr *MockExampleMockRecorder) VarargMethod(_s, _x, a, ret interface{}, varargs ...interface{}) *gomock.Call { + varargs_2 := append([]interface{}{_s, _x, a, ret}, varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VarargMethod", reflect.TypeOf((*MockExample)(nil).VarargMethod), varargs_2...) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/bugreport_test.go b/vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/bugreport_test.go new file mode 100644 index 00000000..3ca9807d --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/generated_identifier_conflict/bugreport_test.go @@ -0,0 +1,26 @@ +package bugreport + +import ( + "github.com/golang/mock/gomock" + "testing" +) + +func TestExample_Method(t *testing.T) { + ctrl := gomock.NewController(t) + m := NewMockExample(ctrl) + m.EXPECT().Method(1, 2, 3, 4) + + m.Method(1, 2, 3, 4) + + ctrl.Finish() +} + +func TestExample_VarargMethod(t *testing.T) { + ctrl := gomock.NewController(t) + m := NewMockExample(ctrl) + m.EXPECT().VarargMethod(1, 2, 3, 4, 6, 7) + + m.VarargMethod(1, 2, 3, 4, 6, 7) + + ctrl.Finish() +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/import_source/Readme.md b/vendor/github.com/golang/mock/mockgen/tests/import_source/Readme.md new file mode 100644 index 00000000..b755968d --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/import_source/Readme.md @@ -0,0 +1,3 @@ +Test the case where the generated code uses a type defined in the source package (in source mode). There are two test cases: +- the output is in a new package +- the output is in the same package as the input \ No newline at end of file diff --git a/vendor/github.com/golang/mock/mockgen/tests/import_source/definition/source.go b/vendor/github.com/golang/mock/mockgen/tests/import_source/definition/source.go new file mode 100644 index 00000000..493134de --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/import_source/definition/source.go @@ -0,0 +1,9 @@ +//go:generate mockgen -destination ../source_mock.go -source=source.go +//go:generate mockgen -package source -destination source_mock.go -source=source.go +package source + +type X struct{} + +type S interface { + F(X) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/import_source/definition/source_mock.go b/vendor/github.com/golang/mock/mockgen/tests/import_source/definition/source_mock.go new file mode 100644 index 00000000..e8c99966 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/import_source/definition/source_mock.go @@ -0,0 +1,43 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: source.go + +// Package source is a generated GoMock package. +package source + +import ( + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockS is a mock of S interface +type MockS struct { + ctrl *gomock.Controller + recorder *MockSMockRecorder +} + +// MockSMockRecorder is the mock recorder for MockS +type MockSMockRecorder struct { + mock *MockS +} + +// NewMockS creates a new mock instance +func NewMockS(ctrl *gomock.Controller) *MockS { + mock := &MockS{ctrl: ctrl} + mock.recorder = &MockSMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockS) EXPECT() *MockSMockRecorder { + return m.recorder +} + +// F mocks base method +func (m *MockS) F(arg0 X) { + m.ctrl.Call(m, "F", arg0) +} + +// F indicates an expected call of F +func (mr *MockSMockRecorder) F(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "F", reflect.TypeOf((*MockS)(nil).F), arg0) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/import_source/source_mock.go b/vendor/github.com/golang/mock/mockgen/tests/import_source/source_mock.go new file mode 100644 index 00000000..6789ba3a --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/import_source/source_mock.go @@ -0,0 +1,44 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: source.go + +// Package mock_source is a generated GoMock package. +package mock_source + +import ( + gomock "github.com/golang/mock/gomock" + definition "github.com/golang/mock/mockgen/tests/import_source/definition" + reflect "reflect" +) + +// MockS is a mock of S interface +type MockS struct { + ctrl *gomock.Controller + recorder *MockSMockRecorder +} + +// MockSMockRecorder is the mock recorder for MockS +type MockSMockRecorder struct { + mock *MockS +} + +// NewMockS creates a new mock instance +func NewMockS(ctrl *gomock.Controller) *MockS { + mock := &MockS{ctrl: ctrl} + mock.recorder = &MockSMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockS) EXPECT() *MockSMockRecorder { + return m.recorder +} + +// F mocks base method +func (m *MockS) F(arg0 definition.X) { + m.ctrl.Call(m, "F", arg0) +} + +// F indicates an expected call of F +func (mr *MockSMockRecorder) F(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "F", reflect.TypeOf((*MockS)(nil).F), arg0) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/internal_pkg/generate.go b/vendor/github.com/golang/mock/mockgen/tests/internal_pkg/generate.go new file mode 100644 index 00000000..541ed647 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/internal_pkg/generate.go @@ -0,0 +1,3 @@ +//go:generate mockgen -destination subdir/internal/pkg/reflect_output/mock.go github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg Intf +//go:generate mockgen -source subdir/internal/pkg/input.go -destination subdir/internal/pkg/source_output/mock.go +package test diff --git a/vendor/github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg/input.go b/vendor/github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg/input.go new file mode 100644 index 00000000..d05f6a7f --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg/input.go @@ -0,0 +1,9 @@ +package pkg + +type Arg interface { + Foo() int +} + +type Intf interface { + F() Arg +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg/reflect_output/mock.go b/vendor/github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg/reflect_output/mock.go new file mode 100644 index 00000000..47ccf0c5 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg/reflect_output/mock.go @@ -0,0 +1,46 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg (interfaces: Intf) + +// Package mock_pkg is a generated GoMock package. +package mock_pkg + +import ( + gomock "github.com/golang/mock/gomock" + pkg "github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg" + reflect "reflect" +) + +// MockIntf is a mock of Intf interface +type MockIntf struct { + ctrl *gomock.Controller + recorder *MockIntfMockRecorder +} + +// MockIntfMockRecorder is the mock recorder for MockIntf +type MockIntfMockRecorder struct { + mock *MockIntf +} + +// NewMockIntf creates a new mock instance +func NewMockIntf(ctrl *gomock.Controller) *MockIntf { + mock := &MockIntf{ctrl: ctrl} + mock.recorder = &MockIntfMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockIntf) EXPECT() *MockIntfMockRecorder { + return m.recorder +} + +// F mocks base method +func (m *MockIntf) F() pkg.Arg { + ret := m.ctrl.Call(m, "F") + ret0, _ := ret[0].(pkg.Arg) + return ret0 +} + +// F indicates an expected call of F +func (mr *MockIntfMockRecorder) F() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "F", reflect.TypeOf((*MockIntf)(nil).F)) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg/source_output/mock.go b/vendor/github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg/source_output/mock.go new file mode 100644 index 00000000..32595ab1 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg/source_output/mock.go @@ -0,0 +1,81 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: subdir/internal/pkg/input.go + +// Package mock_pkg is a generated GoMock package. +package mock_pkg + +import ( + gomock "github.com/golang/mock/gomock" + pkg "github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg" + reflect "reflect" +) + +// MockArg is a mock of Arg interface +type MockArg struct { + ctrl *gomock.Controller + recorder *MockArgMockRecorder +} + +// MockArgMockRecorder is the mock recorder for MockArg +type MockArgMockRecorder struct { + mock *MockArg +} + +// NewMockArg creates a new mock instance +func NewMockArg(ctrl *gomock.Controller) *MockArg { + mock := &MockArg{ctrl: ctrl} + mock.recorder = &MockArgMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockArg) EXPECT() *MockArgMockRecorder { + return m.recorder +} + +// Foo mocks base method +func (m *MockArg) Foo() int { + ret := m.ctrl.Call(m, "Foo") + ret0, _ := ret[0].(int) + return ret0 +} + +// Foo indicates an expected call of Foo +func (mr *MockArgMockRecorder) Foo() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Foo", reflect.TypeOf((*MockArg)(nil).Foo)) +} + +// MockIntf is a mock of Intf interface +type MockIntf struct { + ctrl *gomock.Controller + recorder *MockIntfMockRecorder +} + +// MockIntfMockRecorder is the mock recorder for MockIntf +type MockIntfMockRecorder struct { + mock *MockIntf +} + +// NewMockIntf creates a new mock instance +func NewMockIntf(ctrl *gomock.Controller) *MockIntf { + mock := &MockIntf{ctrl: ctrl} + mock.recorder = &MockIntfMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockIntf) EXPECT() *MockIntfMockRecorder { + return m.recorder +} + +// F mocks base method +func (m *MockIntf) F() pkg.Arg { + ret := m.ctrl.Call(m, "F") + ret0, _ := ret[0].(pkg.Arg) + return ret0 +} + +// F indicates an expected call of F +func (mr *MockIntfMockRecorder) F() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "F", reflect.TypeOf((*MockIntf)(nil).F)) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/unexported_method/README.md b/vendor/github.com/golang/mock/mockgen/tests/unexported_method/README.md new file mode 100644 index 00000000..87f91d46 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/unexported_method/README.md @@ -0,0 +1 @@ +From #52, this tests an unexported method in the mocked interface. diff --git a/vendor/github.com/golang/mock/mockgen/tests/unexported_method/bugreport.go b/vendor/github.com/golang/mock/mockgen/tests/unexported_method/bugreport.go new file mode 100644 index 00000000..91d5baf7 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/unexported_method/bugreport.go @@ -0,0 +1,15 @@ +//go:generate mockgen -destination bugreport_mock.go -package bugreport -source=bugreport.go Example + +package bugreport + +import "fmt" + +// Example is an interface with a non exported method +type Example interface { + someMethod(string) string +} + +// CallExample is a simple function that uses the interface +func CallExample(e Example) { + fmt.Println(e.someMethod("test")) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/unexported_method/bugreport_mock.go b/vendor/github.com/golang/mock/mockgen/tests/unexported_method/bugreport_mock.go new file mode 100644 index 00000000..8ba218fc --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/unexported_method/bugreport_mock.go @@ -0,0 +1,45 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: bugreport.go + +// Package bugreport is a generated GoMock package. +package bugreport + +import ( + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockExample is a mock of Example interface +type MockExample struct { + ctrl *gomock.Controller + recorder *MockExampleMockRecorder +} + +// MockExampleMockRecorder is the mock recorder for MockExample +type MockExampleMockRecorder struct { + mock *MockExample +} + +// NewMockExample creates a new mock instance +func NewMockExample(ctrl *gomock.Controller) *MockExample { + mock := &MockExample{ctrl: ctrl} + mock.recorder = &MockExampleMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockExample) EXPECT() *MockExampleMockRecorder { + return m.recorder +} + +// someMethod mocks base method +func (m *MockExample) someMethod(arg0 string) string { + ret := m.ctrl.Call(m, "someMethod", arg0) + ret0, _ := ret[0].(string) + return ret0 +} + +// someMethod indicates an expected call of someMethod +func (mr *MockExampleMockRecorder) someMethod(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "someMethod", reflect.TypeOf((*MockExample)(nil).someMethod), arg0) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/unexported_method/bugreport_test.go b/vendor/github.com/golang/mock/mockgen/tests/unexported_method/bugreport_test.go new file mode 100644 index 00000000..d428fb4c --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/unexported_method/bugreport_test.go @@ -0,0 +1,17 @@ +package bugreport + +import ( + "testing" + + "github.com/golang/mock/gomock" +) + +func TestCallExample(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + e := NewMockExample(ctrl) + e.EXPECT().someMethod(gomock.Any()).Return("it works!") + + CallExample(e) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/README.md b/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/README.md new file mode 100644 index 00000000..9f9217d2 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/README.md @@ -0,0 +1,2 @@ +Test for [Issue#4](https://github.com/golang/mock/issues/4). +Also see discussion on [#28](https://github.com/golang/mock/pull/28). diff --git a/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/doc.go b/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/doc.go new file mode 100644 index 00000000..e751826d --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/doc.go @@ -0,0 +1,4 @@ +package vendor_dep + +//go:generate mockgen -package vendor_dep -destination mock.go github.com/golang/mock/mockgen/tests/vendor_dep VendorsDep +//go:generate mockgen -destination source_mock_package/mock.go -source=vendor_dep.go diff --git a/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/mock.go b/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/mock.go new file mode 100644 index 00000000..aace06e6 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/mock.go @@ -0,0 +1,46 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/golang/mock/mockgen/tests/vendor_dep (interfaces: VendorsDep) + +// Package vendor_dep is a generated GoMock package. +package vendor_dep + +import ( + a "a" + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockVendorsDep is a mock of VendorsDep interface +type MockVendorsDep struct { + ctrl *gomock.Controller + recorder *MockVendorsDepMockRecorder +} + +// MockVendorsDepMockRecorder is the mock recorder for MockVendorsDep +type MockVendorsDepMockRecorder struct { + mock *MockVendorsDep +} + +// NewMockVendorsDep creates a new mock instance +func NewMockVendorsDep(ctrl *gomock.Controller) *MockVendorsDep { + mock := &MockVendorsDep{ctrl: ctrl} + mock.recorder = &MockVendorsDepMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockVendorsDep) EXPECT() *MockVendorsDepMockRecorder { + return m.recorder +} + +// Foo mocks base method +func (m *MockVendorsDep) Foo() a.Ifc { + ret := m.ctrl.Call(m, "Foo") + ret0, _ := ret[0].(a.Ifc) + return ret0 +} + +// Foo indicates an expected call of Foo +func (mr *MockVendorsDepMockRecorder) Foo() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Foo", reflect.TypeOf((*MockVendorsDep)(nil).Foo)) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/source_mock_package/mock.go b/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/source_mock_package/mock.go new file mode 100644 index 00000000..b4732592 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/source_mock_package/mock.go @@ -0,0 +1,46 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: vendor_dep.go + +// Package mock_vendor_dep is a generated GoMock package. +package mock_vendor_dep + +import ( + a "a" + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockVendorsDep is a mock of VendorsDep interface +type MockVendorsDep struct { + ctrl *gomock.Controller + recorder *MockVendorsDepMockRecorder +} + +// MockVendorsDepMockRecorder is the mock recorder for MockVendorsDep +type MockVendorsDepMockRecorder struct { + mock *MockVendorsDep +} + +// NewMockVendorsDep creates a new mock instance +func NewMockVendorsDep(ctrl *gomock.Controller) *MockVendorsDep { + mock := &MockVendorsDep{ctrl: ctrl} + mock.recorder = &MockVendorsDepMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockVendorsDep) EXPECT() *MockVendorsDepMockRecorder { + return m.recorder +} + +// Foo mocks base method +func (m *MockVendorsDep) Foo() a.Ifc { + ret := m.ctrl.Call(m, "Foo") + ret0, _ := ret[0].(a.Ifc) + return ret0 +} + +// Foo indicates an expected call of Foo +func (mr *MockVendorsDepMockRecorder) Foo() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Foo", reflect.TypeOf((*MockVendorsDep)(nil).Foo)) +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/vendor_dep.go b/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/vendor_dep.go new file mode 100644 index 00000000..412636a2 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/vendor_dep/vendor_dep.go @@ -0,0 +1,7 @@ +package vendor_dep + +import "a" + +type VendorsDep interface { + Foo() a.Ifc +} diff --git a/vendor/github.com/golang/mock/mockgen/tests/vendor_pkg/README.md b/vendor/github.com/golang/mock/mockgen/tests/vendor_pkg/README.md new file mode 100644 index 00000000..1233f98c --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/vendor_pkg/README.md @@ -0,0 +1 @@ +Test for [Issue#4](https://github.com/golang/mock/issues/4). diff --git a/vendor/github.com/golang/mock/mockgen/tests/vendor_pkg/doc.go b/vendor/github.com/golang/mock/mockgen/tests/vendor_pkg/doc.go new file mode 100644 index 00000000..b5bde11c --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/vendor_pkg/doc.go @@ -0,0 +1,3 @@ +package vendor_pkg + +//go:generate mockgen -destination mock.go -package vendor_pkg a Ifc diff --git a/vendor/github.com/golang/mock/mockgen/tests/vendor_pkg/mock.go b/vendor/github.com/golang/mock/mockgen/tests/vendor_pkg/mock.go new file mode 100644 index 00000000..e5e78e51 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/tests/vendor_pkg/mock.go @@ -0,0 +1,99 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: a (interfaces: Ifc) + +// Package vendor_pkg is a generated GoMock package. +package vendor_pkg + +import ( + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockIfc is a mock of Ifc interface +type MockIfc struct { + ctrl *gomock.Controller + recorder *MockIfcMockRecorder +} + +// MockIfcMockRecorder is the mock recorder for MockIfc +type MockIfcMockRecorder struct { + mock *MockIfc +} + +// NewMockIfc creates a new mock instance +func NewMockIfc(ctrl *gomock.Controller) *MockIfc { + mock := &MockIfc{ctrl: ctrl} + mock.recorder = &MockIfcMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockIfc) EXPECT() *MockIfcMockRecorder { + return m.recorder +} + +// A mocks base method +func (m *MockIfc) A(arg0 string) string { + ret := m.ctrl.Call(m, "A", arg0) + ret0, _ := ret[0].(string) + return ret0 +} + +// A indicates an expected call of A +func (mr *MockIfcMockRecorder) A(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "A", reflect.TypeOf((*MockIfc)(nil).A), arg0) +} + +// B mocks base method +func (m *MockIfc) B(arg0 int) int { + ret := m.ctrl.Call(m, "B", arg0) + ret0, _ := ret[0].(int) + return ret0 +} + +// B indicates an expected call of B +func (mr *MockIfcMockRecorder) B(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "B", reflect.TypeOf((*MockIfc)(nil).B), arg0) +} + +// C mocks base method +func (m *MockIfc) C(arg0 chan int) chan int { + ret := m.ctrl.Call(m, "C", arg0) + ret0, _ := ret[0].(chan int) + return ret0 +} + +// C indicates an expected call of C +func (mr *MockIfcMockRecorder) C(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "C", reflect.TypeOf((*MockIfc)(nil).C), arg0) +} + +// D mocks base method +func (m *MockIfc) D(arg0 interface{}) { + m.ctrl.Call(m, "D", arg0) +} + +// D indicates an expected call of D +func (mr *MockIfcMockRecorder) D(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "D", reflect.TypeOf((*MockIfc)(nil).D), arg0) +} + +// E mocks base method +func (m *MockIfc) E(arg0 map[string]interface{}) { + m.ctrl.Call(m, "E", arg0) +} + +// E indicates an expected call of E +func (mr *MockIfcMockRecorder) E(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "E", reflect.TypeOf((*MockIfc)(nil).E), arg0) +} + +// F mocks base method +func (m *MockIfc) F(arg0 []float64) { + m.ctrl.Call(m, "F", arg0) +} + +// F indicates an expected call of F +func (mr *MockIfcMockRecorder) F(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "F", reflect.TypeOf((*MockIfc)(nil).F), arg0) +} diff --git a/vendor/github.com/golang/mock/sample/README.md b/vendor/github.com/golang/mock/sample/README.md new file mode 100644 index 00000000..7180204f --- /dev/null +++ b/vendor/github.com/golang/mock/sample/README.md @@ -0,0 +1,16 @@ +This directory contains an example of a package containing a non-trivial +interface that can be mocked with GoMock. The interesting files are: + + * `user.go`: Source code for the sample package, containing interfaces to be + mocked. This file depends on the packages named imp[1-4] for various things. + + * `user_test.go`: A test for the sample package, in which mocks of the + interfaces from `user.go` are used. This demonstrates how to create mock + objects, set up expectations, and so on. + + * `mock_user/mock_user.go`: The generated mock code. See ../update_mocks.sh + for the command used to generate it. + +To run the test, + + go test github.com/golang/mock/sample diff --git a/vendor/github.com/golang/mock/sample/concurrent/concurrent.go b/vendor/github.com/golang/mock/sample/concurrent/concurrent.go new file mode 100644 index 00000000..346cee42 --- /dev/null +++ b/vendor/github.com/golang/mock/sample/concurrent/concurrent.go @@ -0,0 +1,8 @@ +//go:generate mockgen -destination mock/concurrent_mock.go github.com/golang/mock/sample/concurrent Math + +// Package concurrent demonstrates how to use gomock with goroutines. +package concurrent + +type Math interface { + Sum(a, b int) int +} diff --git a/vendor/github.com/golang/mock/sample/concurrent/concurrent_test.go b/vendor/github.com/golang/mock/sample/concurrent/concurrent_test.go new file mode 100644 index 00000000..e4b271ea --- /dev/null +++ b/vendor/github.com/golang/mock/sample/concurrent/concurrent_test.go @@ -0,0 +1,46 @@ +package concurrent + +import ( + "testing" + + "github.com/golang/mock/gomock" + "golang.org/x/net/context" + + mock "github.com/golang/mock/sample/concurrent/mock" +) + +func call(ctx context.Context, m Math) (int, error) { + result := make(chan int) + go func() { + result <- m.Sum(1, 2) + close(result) + }() + select { + case r := <-result: + return r, nil + case <-ctx.Done(): + return 0, ctx.Err() + } +} + +// testConcurrentFails is expected to fail (and is disabled). It +// demonstrates how to use gomock.WithContext to interrupt the test +// from a different goroutine. +func testConcurrentFails(t *testing.T) { + ctrl, ctx := gomock.WithContext(context.Background(), t) + defer ctrl.Finish() + m := mock.NewMockMath(ctrl) + if _, err := call(ctx, m); err != nil { + t.Error("call failed:", err) + } +} + +func TestConcurrentWorks(t *testing.T) { + ctrl, ctx := gomock.WithContext(context.Background(), t) + defer ctrl.Finish() + m := mock.NewMockMath(ctrl) + m.EXPECT().Sum(1, 2).Return(3) + if _, err := call(ctx, m); err != nil { + t.Error("call failed:", err) + } +} diff --git a/vendor/github.com/golang/mock/sample/concurrent/mock/concurrent_mock.go b/vendor/github.com/golang/mock/sample/concurrent/mock/concurrent_mock.go new file mode 100644 index 00000000..92005631 --- /dev/null +++ b/vendor/github.com/golang/mock/sample/concurrent/mock/concurrent_mock.go @@ -0,0 +1,45 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/golang/mock/sample/concurrent (interfaces: Math) + +// Package mock_concurrent is a generated GoMock package. +package mock_concurrent + +import ( + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockMath is a mock of Math interface +type MockMath struct { + ctrl *gomock.Controller + recorder *MockMathMockRecorder +} + +// MockMathMockRecorder is the mock recorder for MockMath +type MockMathMockRecorder struct { + mock *MockMath +} + +// NewMockMath creates a new mock instance +func NewMockMath(ctrl *gomock.Controller) *MockMath { + mock := &MockMath{ctrl: ctrl} + mock.recorder = &MockMathMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockMath) EXPECT() *MockMathMockRecorder { + return m.recorder +} + +// Sum mocks base method +func (m *MockMath) Sum(arg0, arg1 int) int { + ret := m.ctrl.Call(m, "Sum", arg0, arg1) + ret0, _ := ret[0].(int) + return ret0 +} + +// Sum indicates an expected call of Sum +func (mr *MockMathMockRecorder) Sum(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sum", reflect.TypeOf((*MockMath)(nil).Sum), arg0, arg1) +} diff --git a/vendor/github.com/golang/mock/sample/imp1/imp1.go b/vendor/github.com/golang/mock/sample/imp1/imp1.go new file mode 100644 index 00000000..ef9d0144 --- /dev/null +++ b/vendor/github.com/golang/mock/sample/imp1/imp1.go @@ -0,0 +1,17 @@ +package imp1 + +import "bufio" + +type Imp1 struct{} + +type ImpT int + +type ForeignEmbedded interface { + // The return value here also makes sure that + // the generated mock picks up the "bufio" import. + ForeignEmbeddedMethod() *bufio.Reader + + // This method uses a type in this package, + // which should be qualified when this interface is embedded. + ImplicitPackage(s string, t ImpT, st []ImpT, pt *ImpT, ct chan ImpT) +} diff --git a/vendor/github.com/golang/mock/sample/imp2/imp2.go b/vendor/github.com/golang/mock/sample/imp2/imp2.go new file mode 100644 index 00000000..53bee9ad --- /dev/null +++ b/vendor/github.com/golang/mock/sample/imp2/imp2.go @@ -0,0 +1,3 @@ +package imp2 + +type Imp2 struct{} diff --git a/vendor/github.com/golang/mock/sample/imp3/imp3.go b/vendor/github.com/golang/mock/sample/imp3/imp3.go new file mode 100644 index 00000000..70f17c00 --- /dev/null +++ b/vendor/github.com/golang/mock/sample/imp3/imp3.go @@ -0,0 +1,3 @@ +package imp3 + +type Imp3 struct{} diff --git a/vendor/github.com/golang/mock/sample/imp4/imp4.go b/vendor/github.com/golang/mock/sample/imp4/imp4.go new file mode 100644 index 00000000..30a70767 --- /dev/null +++ b/vendor/github.com/golang/mock/sample/imp4/imp4.go @@ -0,0 +1,3 @@ +package imp_four + +type Imp4 struct{} diff --git a/vendor/github.com/golang/mock/sample/mock_user/mock_user.go b/vendor/github.com/golang/mock/sample/mock_user/mock_user.go new file mode 100644 index 00000000..13b74b32 --- /dev/null +++ b/vendor/github.com/golang/mock/sample/mock_user/mock_user.go @@ -0,0 +1,384 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/golang/mock/sample (interfaces: Index,Embed,Embedded) + +// Package mock_sample is a generated GoMock package. +package mock_sample + +import ( + bufio "bufio" + bytes "bytes" + gomock "github.com/golang/mock/gomock" + imp1 "github.com/golang/mock/sample/imp1" + imp2 "github.com/golang/mock/sample/imp2" + imp3 "github.com/golang/mock/sample/imp3" + imp4 "github.com/golang/mock/sample/imp4" + hash "hash" + template "html/template" + io "io" + http "net/http" + reflect "reflect" + template0 "text/template" +) + +// MockIndex is a mock of Index interface +type MockIndex struct { + ctrl *gomock.Controller + recorder *MockIndexMockRecorder +} + +// MockIndexMockRecorder is the mock recorder for MockIndex +type MockIndexMockRecorder struct { + mock *MockIndex +} + +// NewMockIndex creates a new mock instance +func NewMockIndex(ctrl *gomock.Controller) *MockIndex { + mock := &MockIndex{ctrl: ctrl} + mock.recorder = &MockIndexMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockIndex) EXPECT() *MockIndexMockRecorder { + return m.recorder +} + +// Anon mocks base method +func (m *MockIndex) Anon(arg0 string) { + m.ctrl.Call(m, "Anon", arg0) +} + +// Anon indicates an expected call of Anon +func (mr *MockIndexMockRecorder) Anon(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Anon", reflect.TypeOf((*MockIndex)(nil).Anon), arg0) +} + +// Chan mocks base method +func (m *MockIndex) Chan(arg0 chan int, arg1 chan<- hash.Hash) { + m.ctrl.Call(m, "Chan", arg0, arg1) +} + +// Chan indicates an expected call of Chan +func (mr *MockIndexMockRecorder) Chan(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Chan", reflect.TypeOf((*MockIndex)(nil).Chan), arg0, arg1) +} + +// ConcreteRet mocks base method +func (m *MockIndex) ConcreteRet() chan<- bool { + ret := m.ctrl.Call(m, "ConcreteRet") + ret0, _ := ret[0].(chan<- bool) + return ret0 +} + +// ConcreteRet indicates an expected call of ConcreteRet +func (mr *MockIndexMockRecorder) ConcreteRet() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConcreteRet", reflect.TypeOf((*MockIndex)(nil).ConcreteRet)) +} + +// Ellip mocks base method +func (m *MockIndex) Ellip(arg0 string, arg1 ...interface{}) { + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Ellip", varargs...) +} + +// Ellip indicates an expected call of Ellip +func (mr *MockIndexMockRecorder) Ellip(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ellip", reflect.TypeOf((*MockIndex)(nil).Ellip), varargs...) +} + +// EllipOnly mocks base method +func (m *MockIndex) EllipOnly(arg0 ...string) { + varargs := []interface{}{} + for _, a := range arg0 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "EllipOnly", varargs...) +} + +// EllipOnly indicates an expected call of EllipOnly +func (mr *MockIndexMockRecorder) EllipOnly(arg0 ...interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EllipOnly", reflect.TypeOf((*MockIndex)(nil).EllipOnly), arg0...) +} + +// ForeignFour mocks base method +func (m *MockIndex) ForeignFour(arg0 imp4.Imp4) { + m.ctrl.Call(m, "ForeignFour", arg0) +} + +// ForeignFour indicates an expected call of ForeignFour +func (mr *MockIndexMockRecorder) ForeignFour(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForeignFour", reflect.TypeOf((*MockIndex)(nil).ForeignFour), arg0) +} + +// ForeignOne mocks base method +func (m *MockIndex) ForeignOne(arg0 imp1.Imp1) { + m.ctrl.Call(m, "ForeignOne", arg0) +} + +// ForeignOne indicates an expected call of ForeignOne +func (mr *MockIndexMockRecorder) ForeignOne(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForeignOne", reflect.TypeOf((*MockIndex)(nil).ForeignOne), arg0) +} + +// ForeignThree mocks base method +func (m *MockIndex) ForeignThree(arg0 imp3.Imp3) { + m.ctrl.Call(m, "ForeignThree", arg0) +} + +// ForeignThree indicates an expected call of ForeignThree +func (mr *MockIndexMockRecorder) ForeignThree(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForeignThree", reflect.TypeOf((*MockIndex)(nil).ForeignThree), arg0) +} + +// ForeignTwo mocks base method +func (m *MockIndex) ForeignTwo(arg0 imp2.Imp2) { + m.ctrl.Call(m, "ForeignTwo", arg0) +} + +// ForeignTwo indicates an expected call of ForeignTwo +func (mr *MockIndexMockRecorder) ForeignTwo(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForeignTwo", reflect.TypeOf((*MockIndex)(nil).ForeignTwo), arg0) +} + +// Func mocks base method +func (m *MockIndex) Func(arg0 func(http.Request) (int, bool)) { + m.ctrl.Call(m, "Func", arg0) +} + +// Func indicates an expected call of Func +func (mr *MockIndexMockRecorder) Func(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Func", reflect.TypeOf((*MockIndex)(nil).Func), arg0) +} + +// Get mocks base method +func (m *MockIndex) Get(arg0 string) interface{} { + ret := m.ctrl.Call(m, "Get", arg0) + ret0, _ := ret[0].(interface{}) + return ret0 +} + +// Get indicates an expected call of Get +func (mr *MockIndexMockRecorder) Get(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockIndex)(nil).Get), arg0) +} + +// GetTwo mocks base method +func (m *MockIndex) GetTwo(arg0, arg1 string) (interface{}, interface{}) { + ret := m.ctrl.Call(m, "GetTwo", arg0, arg1) + ret0, _ := ret[0].(interface{}) + ret1, _ := ret[1].(interface{}) + return ret0, ret1 +} + +// GetTwo indicates an expected call of GetTwo +func (mr *MockIndexMockRecorder) GetTwo(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTwo", reflect.TypeOf((*MockIndex)(nil).GetTwo), arg0, arg1) +} + +// Map mocks base method +func (m *MockIndex) Map(arg0 map[int]hash.Hash) { + m.ctrl.Call(m, "Map", arg0) +} + +// Map indicates an expected call of Map +func (mr *MockIndexMockRecorder) Map(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Map", reflect.TypeOf((*MockIndex)(nil).Map), arg0) +} + +// NillableRet mocks base method +func (m *MockIndex) NillableRet() error { + ret := m.ctrl.Call(m, "NillableRet") + ret0, _ := ret[0].(error) + return ret0 +} + +// NillableRet indicates an expected call of NillableRet +func (mr *MockIndexMockRecorder) NillableRet() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NillableRet", reflect.TypeOf((*MockIndex)(nil).NillableRet)) +} + +// Other mocks base method +func (m *MockIndex) Other() hash.Hash { + ret := m.ctrl.Call(m, "Other") + ret0, _ := ret[0].(hash.Hash) + return ret0 +} + +// Other indicates an expected call of Other +func (mr *MockIndexMockRecorder) Other() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Other", reflect.TypeOf((*MockIndex)(nil).Other)) +} + +// Ptr mocks base method +func (m *MockIndex) Ptr(arg0 *int) { + m.ctrl.Call(m, "Ptr", arg0) +} + +// Ptr indicates an expected call of Ptr +func (mr *MockIndexMockRecorder) Ptr(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ptr", reflect.TypeOf((*MockIndex)(nil).Ptr), arg0) +} + +// Put mocks base method +func (m *MockIndex) Put(arg0 string, arg1 interface{}) { + m.ctrl.Call(m, "Put", arg0, arg1) +} + +// Put indicates an expected call of Put +func (mr *MockIndexMockRecorder) Put(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockIndex)(nil).Put), arg0, arg1) +} + +// Slice mocks base method +func (m *MockIndex) Slice(arg0 []int, arg1 []byte) [3]int { + ret := m.ctrl.Call(m, "Slice", arg0, arg1) + ret0, _ := ret[0].([3]int) + return ret0 +} + +// Slice indicates an expected call of Slice +func (mr *MockIndexMockRecorder) Slice(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Slice", reflect.TypeOf((*MockIndex)(nil).Slice), arg0, arg1) +} + +// Struct mocks base method +func (m *MockIndex) Struct(arg0 struct{}) { + m.ctrl.Call(m, "Struct", arg0) +} + +// Struct indicates an expected call of Struct +func (mr *MockIndexMockRecorder) Struct(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Struct", reflect.TypeOf((*MockIndex)(nil).Struct), arg0) +} + +// StructChan mocks base method +func (m *MockIndex) StructChan(arg0 chan struct{}) { + m.ctrl.Call(m, "StructChan", arg0) +} + +// StructChan indicates an expected call of StructChan +func (mr *MockIndexMockRecorder) StructChan(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StructChan", reflect.TypeOf((*MockIndex)(nil).StructChan), arg0) +} + +// Summary mocks base method +func (m *MockIndex) Summary(arg0 *bytes.Buffer, arg1 io.Writer) { + m.ctrl.Call(m, "Summary", arg0, arg1) +} + +// Summary indicates an expected call of Summary +func (mr *MockIndexMockRecorder) Summary(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Summary", reflect.TypeOf((*MockIndex)(nil).Summary), arg0, arg1) +} + +// Templates mocks base method +func (m *MockIndex) Templates(arg0 template.CSS, arg1 template0.FuncMap) { + m.ctrl.Call(m, "Templates", arg0, arg1) +} + +// Templates indicates an expected call of Templates +func (mr *MockIndexMockRecorder) Templates(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Templates", reflect.TypeOf((*MockIndex)(nil).Templates), arg0, arg1) +} + +// MockEmbed is a mock of Embed interface +type MockEmbed struct { + ctrl *gomock.Controller + recorder *MockEmbedMockRecorder +} + +// MockEmbedMockRecorder is the mock recorder for MockEmbed +type MockEmbedMockRecorder struct { + mock *MockEmbed +} + +// NewMockEmbed creates a new mock instance +func NewMockEmbed(ctrl *gomock.Controller) *MockEmbed { + mock := &MockEmbed{ctrl: ctrl} + mock.recorder = &MockEmbedMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockEmbed) EXPECT() *MockEmbedMockRecorder { + return m.recorder +} + +// EmbeddedMethod mocks base method +func (m *MockEmbed) EmbeddedMethod() { + m.ctrl.Call(m, "EmbeddedMethod") +} + +// EmbeddedMethod indicates an expected call of EmbeddedMethod +func (mr *MockEmbedMockRecorder) EmbeddedMethod() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EmbeddedMethod", reflect.TypeOf((*MockEmbed)(nil).EmbeddedMethod)) +} + +// ForeignEmbeddedMethod mocks base method +func (m *MockEmbed) ForeignEmbeddedMethod() *bufio.Reader { + ret := m.ctrl.Call(m, "ForeignEmbeddedMethod") + ret0, _ := ret[0].(*bufio.Reader) + return ret0 +} + +// ForeignEmbeddedMethod indicates an expected call of ForeignEmbeddedMethod +func (mr *MockEmbedMockRecorder) ForeignEmbeddedMethod() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForeignEmbeddedMethod", reflect.TypeOf((*MockEmbed)(nil).ForeignEmbeddedMethod)) +} + +// ImplicitPackage mocks base method +func (m *MockEmbed) ImplicitPackage(arg0 string, arg1 imp1.ImpT, arg2 []imp1.ImpT, arg3 *imp1.ImpT, arg4 chan imp1.ImpT) { + m.ctrl.Call(m, "ImplicitPackage", arg0, arg1, arg2, arg3, arg4) +} + +// ImplicitPackage indicates an expected call of ImplicitPackage +func (mr *MockEmbedMockRecorder) ImplicitPackage(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ImplicitPackage", reflect.TypeOf((*MockEmbed)(nil).ImplicitPackage), arg0, arg1, arg2, arg3, arg4) +} + +// RegularMethod mocks base method +func (m *MockEmbed) RegularMethod() { + m.ctrl.Call(m, "RegularMethod") +} + +// RegularMethod indicates an expected call of RegularMethod +func (mr *MockEmbedMockRecorder) RegularMethod() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegularMethod", reflect.TypeOf((*MockEmbed)(nil).RegularMethod)) +} + +// MockEmbedded is a mock of Embedded interface +type MockEmbedded struct { + ctrl *gomock.Controller + recorder *MockEmbeddedMockRecorder +} + +// MockEmbeddedMockRecorder is the mock recorder for MockEmbedded +type MockEmbeddedMockRecorder struct { + mock *MockEmbedded +} + +// NewMockEmbedded creates a new mock instance +func NewMockEmbedded(ctrl *gomock.Controller) *MockEmbedded { + mock := &MockEmbedded{ctrl: ctrl} + mock.recorder = &MockEmbeddedMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockEmbedded) EXPECT() *MockEmbeddedMockRecorder { + return m.recorder +} + +// EmbeddedMethod mocks base method +func (m *MockEmbedded) EmbeddedMethod() { + m.ctrl.Call(m, "EmbeddedMethod") +} + +// EmbeddedMethod indicates an expected call of EmbeddedMethod +func (mr *MockEmbeddedMockRecorder) EmbeddedMethod() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EmbeddedMethod", reflect.TypeOf((*MockEmbedded)(nil).EmbeddedMethod)) +} diff --git a/vendor/github.com/golang/mock/sample/user.go b/vendor/github.com/golang/mock/sample/user.go new file mode 100644 index 00000000..0e4a8142 --- /dev/null +++ b/vendor/github.com/golang/mock/sample/user.go @@ -0,0 +1,114 @@ +//go:generate mockgen -destination mock_user/mock_user.go github.com/golang/mock/sample Index,Embed,Embedded + +// An example package with an interface. +package user + +// Random bunch of imports to test mockgen. +import "io" +import ( + btz "bytes" + "hash" + "log" + "net" + "net/http" + + // Two imports with the same base name. + t1 "html/template" + t2 "text/template" +) + +// Dependencies outside the standard library. +import ( + "github.com/golang/mock/sample/imp1" + renamed2 "github.com/golang/mock/sample/imp2" + . "github.com/golang/mock/sample/imp3" + "github.com/golang/mock/sample/imp4" // calls itself "imp_four" +) + +// A bizarre interface to test corner cases in mockgen. +// This would normally be in its own file or package, +// separate from the user of it (e.g. io.Reader). +type Index interface { + Get(key string) interface{} + GetTwo(key1, key2 string) (v1, v2 interface{}) + Put(key string, value interface{}) + + // Check that imports are handled correctly. + Summary(buf *btz.Buffer, w io.Writer) + Other() hash.Hash + Templates(a t1.CSS, b t2.FuncMap) + + // A method with an anonymous argument. + Anon(string) + + // Methods using foreign types outside the standard library. + ForeignOne(imp1.Imp1) + ForeignTwo(renamed2.Imp2) + ForeignThree(Imp3) + ForeignFour(imp_four.Imp4) + + // A method that returns a nillable type. + NillableRet() error + // A method that returns a non-interface type. + ConcreteRet() chan<- bool + + // Methods with an ellipsis argument. + Ellip(fmt string, args ...interface{}) + EllipOnly(...string) + + // A method with a pointer argument that we will set. + Ptr(arg *int) + + // A method with a slice argument and an array return. + Slice(a []int, b []byte) [3]int + + // A method with channel arguments. + Chan(a chan int, b chan<- hash.Hash) + + // A method with a function argument. + Func(f func(http.Request) (int, bool)) + + // A method with a map argument. + Map(a map[int]hash.Hash) + + // Methods with an unnamed empty struct argument. + Struct(a struct{}) // not so likely + StructChan(a chan struct{}) // a bit more common +} + +// An interface with an embedded interface. +type Embed interface { + RegularMethod() + Embedded + imp1.ForeignEmbedded +} + +type Embedded interface { + EmbeddedMethod() +} + +// some random use of another package that isn't needed by the interface. +var _ net.Addr + +// A function that we will test that uses the above interface. +// It takes a list of keys and values, and puts them in the index. +func Remember(index Index, keys []string, values []interface{}) { + for i, k := range keys { + index.Put(k, values[i]) + } + err := index.NillableRet() + if err != nil { + log.Fatalf("Woah! %v", err) + } + if len(keys) > 0 && keys[0] == "a" { + index.Ellip("%d", 0, 1, 1, 2, 3) + index.Ellip("%d", 1, 3, 6, 10, 15) + index.EllipOnly("arg") + } +} + +func GrabPointer(index Index) int { + var a int + index.Ptr(&a) + return a +} diff --git a/vendor/github.com/golang/mock/sample/user_test.go b/vendor/github.com/golang/mock/sample/user_test.go new file mode 100644 index 00000000..d1de99cd --- /dev/null +++ b/vendor/github.com/golang/mock/sample/user_test.go @@ -0,0 +1,161 @@ +// A test that uses a mock. +package user_test + +import ( + "testing" + + "github.com/golang/mock/gomock" + "github.com/golang/mock/sample" + "github.com/golang/mock/sample/imp1" + mock_user "github.com/golang/mock/sample/mock_user" +) + +func TestRemember(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockIndex := mock_user.NewMockIndex(ctrl) + mockIndex.EXPECT().Put("a", 1) // literals work + mockIndex.EXPECT().Put("b", gomock.Eq(2)) // matchers work too + + // NillableRet returns error. Not declaring it should result in a nil return. + mockIndex.EXPECT().NillableRet() + // Calls that returns something assignable to the return type. + boolc := make(chan bool) + // In this case, "chan bool" is assignable to "chan<- bool". + mockIndex.EXPECT().ConcreteRet().Return(boolc) + // In this case, nil is assignable to "chan<- bool". + mockIndex.EXPECT().ConcreteRet().Return(nil) + + // Should be able to place expectations on variadic methods. + mockIndex.EXPECT().Ellip("%d", 0, 1, 1, 2, 3) // direct args + tri := []interface{}{1, 3, 6, 10, 15} + mockIndex.EXPECT().Ellip("%d", tri...) // args from slice + mockIndex.EXPECT().EllipOnly(gomock.Eq("arg")) + + user.Remember(mockIndex, []string{"a", "b"}, []interface{}{1, 2}) + // Check the ConcreteRet calls. + if c := mockIndex.ConcreteRet(); c != boolc { + t.Errorf("ConcreteRet: got %v, want %v", c, boolc) + } + if c := mockIndex.ConcreteRet(); c != nil { + t.Errorf("ConcreteRet: got %v, want nil", c) + } + + // Try one with an action. + calledString := "" + mockIndex.EXPECT().Put(gomock.Any(), gomock.Any()).Do(func(key string, _ interface{}) { + calledString = key + }) + mockIndex.EXPECT().NillableRet() + user.Remember(mockIndex, []string{"blah"}, []interface{}{7}) + if calledString != "blah" { + t.Fatalf(`Uh oh. %q != "blah"`, calledString) + } + + // Use Do with a nil arg. + mockIndex.EXPECT().Put("nil-key", gomock.Any()).Do(func(key string, value interface{}) { + if value != nil { + t.Errorf("Put did not pass through nil; got %v", value) + } + }) + mockIndex.EXPECT().NillableRet() + user.Remember(mockIndex, []string{"nil-key"}, []interface{}{nil}) +} + +func TestVariadicFunction(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockIndex := mock_user.NewMockIndex(ctrl) + mockIndex.EXPECT().Ellip("%d", 5, 6, 7, 8).Do(func(format string, nums ...int) { + sum := 0 + for _, value := range nums { + sum += value + } + if sum != 26 { + t.Errorf("Expected 7, got %d", sum) + } + }) + mockIndex.EXPECT().Ellip("%d", gomock.Any()).Do(func(format string, nums ...int) { + sum := 0 + for _, value := range nums { + sum += value + } + if sum != 10 { + t.Errorf("Expected 7, got %d", sum) + } + }) + mockIndex.EXPECT().Ellip("%d", gomock.Any()).Do(func(format string, nums ...int) { + sum := 0 + for _, value := range nums { + sum += value + } + if sum != 0 { + t.Errorf("Expected 0, got %d", sum) + } + }) + mockIndex.EXPECT().Ellip("%d", gomock.Any()).Do(func(format string, nums ...int) { + sum := 0 + for _, value := range nums { + sum += value + } + if sum != 0 { + t.Errorf("Expected 0, got %d", sum) + } + }) + mockIndex.EXPECT().Ellip("%d").Do(func(format string, nums ...int) { + sum := 0 + for _, value := range nums { + sum += value + } + if sum != 0 { + t.Errorf("Expected 0, got %d", sum) + } + }) + + mockIndex.Ellip("%d", 1, 2, 3, 4) // Match second matcher. + mockIndex.Ellip("%d", 5, 6, 7, 8) // Match first matcher. + mockIndex.Ellip("%d", 0) + mockIndex.Ellip("%d") + mockIndex.Ellip("%d") +} + +func TestGrabPointer(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockIndex := mock_user.NewMockIndex(ctrl) + mockIndex.EXPECT().Ptr(gomock.Any()).SetArg(0, 7) // set first argument to 7 + + i := user.GrabPointer(mockIndex) + if i != 7 { + t.Errorf("Expected 7, got %d", i) + } +} + +func TestEmbeddedInterface(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockEmbed := mock_user.NewMockEmbed(ctrl) + mockEmbed.EXPECT().RegularMethod() + mockEmbed.EXPECT().EmbeddedMethod() + mockEmbed.EXPECT().ForeignEmbeddedMethod() + + mockEmbed.RegularMethod() + mockEmbed.EmbeddedMethod() + var emb imp1.ForeignEmbedded = mockEmbed // also does interface check + emb.ForeignEmbeddedMethod() +} + +func TestExpectTrueNil(t *testing.T) { + // Make sure that passing "nil" to EXPECT (thus as a nil interface value), + // will correctly match a nil concrete type. + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockIndex := mock_user.NewMockIndex(ctrl) + mockIndex.EXPECT().Ptr(nil) // this nil is a nil interface{} + mockIndex.Ptr(nil) // this nil is a nil *int +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/.gitignore b/vendor/github.com/kubernetes-csi/csi-test/.gitignore new file mode 100644 index 00000000..984ec0fb --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/.gitignore @@ -0,0 +1,13 @@ +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out +bin/mock +cmd/csi-sanity/csi-sanity diff --git a/vendor/github.com/kubernetes-csi/csi-test/.travis.yml b/vendor/github.com/kubernetes-csi/csi-test/.travis.yml new file mode 100644 index 00000000..261662d3 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/.travis.yml @@ -0,0 +1,11 @@ +language: go +matrix: + include: + - go: 1.10.3 +script: +- make test +after_success: + - if [ "${TRAVIS_BRANCH}" == "master" ] && [ "${TRAVIS_PULL_REQUEST}" == "false" ]; then + docker login -u "${DOCKER_USERNAME}" -p "${DOCKER_PASSWORD}" quay.io; + make push; + fi diff --git a/vendor/github.com/kubernetes-csi/csi-test/Dockerfile.mock b/vendor/github.com/kubernetes-csi/csi-test/Dockerfile.mock new file mode 100644 index 00000000..72697712 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/Dockerfile.mock @@ -0,0 +1,6 @@ +FROM alpine +LABEL maintainers="Kubernetes Authors" +LABEL description="CSI Mock Driver" + +COPY ./bin/mock mock +ENTRYPOINT ["/mock"] diff --git a/vendor/github.com/kubernetes-csi/csi-test/Gopkg.lock b/vendor/github.com/kubernetes-csi/csi-test/Gopkg.lock new file mode 100644 index 00000000..2737ba71 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/Gopkg.lock @@ -0,0 +1,195 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/container-storage-interface/spec" + packages = ["lib/go/csi/v0"] + revision = "2178fdeea87f1150a17a63252eee28d4d8141f72" + version = "v0.3.0" + +[[projects]] + name = "github.com/golang/mock" + packages = ["gomock"] + revision = "c34cdb4725f4c3844d095133c6e40e448b86589b" + version = "v1.1.1" + +[[projects]] + name = "github.com/golang/protobuf" + packages = [ + "proto", + "protoc-gen-go/descriptor", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/timestamp", + "ptypes/wrappers" + ] + revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" + version = "v1.1.0" + +[[projects]] + name = "github.com/onsi/ginkgo" + packages = [ + ".", + "config", + "internal/codelocation", + "internal/containernode", + "internal/failer", + "internal/leafnodes", + "internal/remote", + "internal/spec", + "internal/spec_iterator", + "internal/specrunner", + "internal/suite", + "internal/testingtproxy", + "internal/writer", + "reporters", + "reporters/stenographer", + "reporters/stenographer/support/go-colorable", + "reporters/stenographer/support/go-isatty", + "types" + ] + revision = "fa5fabab2a1bfbd924faf4c067d07ae414e2aedf" + version = "v1.5.0" + +[[projects]] + name = "github.com/onsi/gomega" + packages = [ + ".", + "format", + "internal/assertion", + "internal/asyncassertion", + "internal/oraclematcher", + "internal/testingtsupport", + "matchers", + "matchers/support/goraph/bipartitegraph", + "matchers/support/goraph/edge", + "matchers/support/goraph/node", + "matchers/support/goraph/util", + "types" + ] + revision = "62bff4df71bdbc266561a0caee19f0594b17c240" + version = "v1.4.0" + +[[projects]] + name = "github.com/sirupsen/logrus" + packages = ["."] + revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc" + version = "v1.0.5" + +[[projects]] + branch = "master" + name = "golang.org/x/crypto" + packages = ["ssh/terminal"] + revision = "8ac0e0d97ce45cd83d1d7243c060cb8461dda5e9" + +[[projects]] + branch = "master" + name = "golang.org/x/net" + packages = [ + "context", + "html", + "html/atom", + "html/charset", + "http/httpguts", + "http2", + "http2/hpack", + "idna", + "internal/timeseries", + "trace" + ] + revision = "1e491301e022f8f977054da4c2d852decd59571f" + +[[projects]] + branch = "master" + name = "golang.org/x/sys" + packages = [ + "unix", + "windows" + ] + revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb" + +[[projects]] + name = "golang.org/x/text" + packages = [ + "collate", + "collate/build", + "encoding", + "encoding/charmap", + "encoding/htmlindex", + "encoding/internal", + "encoding/internal/identifier", + "encoding/japanese", + "encoding/korean", + "encoding/simplifiedchinese", + "encoding/traditionalchinese", + "encoding/unicode", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "internal/utf8internal", + "language", + "runes", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable" + ] + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + branch = "master" + name = "google.golang.org/genproto" + packages = ["googleapis/rpc/status"] + revision = "32ee49c4dd805befd833990acba36cb75042378c" + +[[projects]] + name = "google.golang.org/grpc" + packages = [ + ".", + "balancer", + "balancer/base", + "balancer/roundrobin", + "channelz", + "codes", + "connectivity", + "credentials", + "encoding", + "encoding/proto", + "grpclb/grpc_lb_v1/messages", + "grpclog", + "internal", + "keepalive", + "metadata", + "naming", + "peer", + "reflection", + "reflection/grpc_reflection_v1alpha", + "resolver", + "resolver/dns", + "resolver/passthrough", + "stats", + "status", + "tap", + "transport" + ] + revision = "7a6a684ca69eb4cae85ad0a484f2e531598c047b" + version = "v1.12.2" + +[[projects]] + name = "gopkg.in/yaml.v2" + packages = ["."] + revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" + version = "v2.2.1" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "5dd480018adbb94025564b74bad8dd269cc516183b7b428317f6dd04b07726f4" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/kubernetes-csi/csi-test/Gopkg.toml b/vendor/github.com/kubernetes-csi/csi-test/Gopkg.toml new file mode 100644 index 00000000..e7312785 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/Gopkg.toml @@ -0,0 +1,62 @@ +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/container-storage-interface/spec" + version = "~0.3.0" + +[[constraint]] + name = "github.com/golang/mock" + version = "1.0.0" + +[[constraint]] + name = "github.com/golang/protobuf" + version = "v1.1.0" + +[[constraint]] + name = "github.com/onsi/ginkgo" + version = "1.4.0" + +[[constraint]] + name = "github.com/onsi/gomega" + version = "1.3.0" + +[[constraint]] + branch = "master" + name = "golang.org/x/net" + +[[constraint]] + name = "google.golang.org/grpc" + version = "1.9.2" + +[[constraint]] + name = "gopkg.in/yaml.v2" + version = "v2.1.1" + +[prune] + go-tests = true + unused-packages = true diff --git a/vendor/github.com/kubernetes-csi/csi-test/LICENSE b/vendor/github.com/kubernetes-csi/csi-test/LICENSE new file mode 100644 index 00000000..8dada3ed --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/kubernetes-csi/csi-test/Makefile b/vendor/github.com/kubernetes-csi/csi-test/Makefile new file mode 100644 index 00000000..621cec71 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/Makefile @@ -0,0 +1,52 @@ +# Copyright 2018 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +IMAGE_NAME = quay.io/k8scsi/mock-driver +IMAGE_VERSION = canary +APP := ./bin/mock + + +ifdef V +TESTARGS = -v -args -alsologtostderr -v 5 +else +TESTARGS = +endif + +all: $(APP) + +$(APP): + mkdir -p bin + CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o $(APP) ./mock/main.go + +clean: + rm -rf bin + +container: $(APP) + docker build -f Dockerfile.mock -t $(IMAGE_NAME):$(IMAGE_VERSION) . + +push: container + docker push $(IMAGE_NAME):$(IMAGE_VERSION) + +test: + files=$$(find ./ -name '*.go' | grep -v '^./vendor' ); \ + if [ $$(gofmt -d $$files | wc -l) -ne 0 ]; then \ + echo "formatting errors:"; \ + gofmt -d $$files; \ + false; \ + fi + go vet $$(go list ./... | grep -v vendor) + go test $$(go list ./... | grep -v vendor | grep -v "cmd/csi-sanity") + ./hack/e2e.sh + +.PHONY: all clean container push test diff --git a/vendor/github.com/kubernetes-csi/csi-test/OWNERS b/vendor/github.com/kubernetes-csi/csi-test/OWNERS new file mode 100644 index 00000000..a780cce6 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/OWNERS @@ -0,0 +1,4 @@ +approvers: +- saad-ali +- lpabon +- pohly diff --git a/vendor/github.com/kubernetes-csi/csi-test/README.md b/vendor/github.com/kubernetes-csi/csi-test/README.md new file mode 100644 index 00000000..61daecc0 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/README.md @@ -0,0 +1,29 @@ +[![Build Status](https://travis-ci.org/kubernetes-csi/csi-test.svg?branch=master)](https://travis-ci.org/kubernetes-csi/csi-test) +[![Docker Repository on Quay](https://quay.io/repository/k8scsi/mock-driver/status "Docker Repository on +Quay")](https://quay.io/repository/k8scsi/mock-driver) + +# csi-test +csi-test houses packages and libraries to help test CSI client and plugins. + +## For Container Orchestration Tests +CO developers can use this framework to create drivers based on the +[Golang mock](https://github.com/golang/mock) framework. Please see +[co_test.go](test/co_test.go) for an example. + +### Mock driver for testing +We also provide a container called `quay.io/k8scsi/mock-driver:canary` which can be used as an in-memory mock driver. +It follows the same release cycle as other containers, so the latest release is `quay.io/k8scsi/mock-driver:v0.3.0`. + +You will need to setup the environment variable `CSI_ENDPOINT` for the mock driver to know where to create the unix +domain socket. + +## For CSI Driver Tests +To test drivers please take a look at [pkg/sanity](https://github.com/kubernetes-csi/csi-test/tree/master/pkg/sanity). +This package and [csi-sanity](https://github.com/kubernetes-csi/csi-test/tree/master/cmd/csi-sanity) are meant to test +the CSI API capability of a driver. They are meant to be an additional test to the unit, functional, and e2e tests of a +CSI driver. + +### Note + +* Master is for CSI v0.4.0. Please see the branches for other CSI releases. +* Only Golang 1.9+ supported. See [gRPC issue](https://github.com/grpc/grpc-go/issues/711#issuecomment-326626790) diff --git a/vendor/github.com/kubernetes-csi/csi-test/SECURITY_CONTACTS b/vendor/github.com/kubernetes-csi/csi-test/SECURITY_CONTACTS new file mode 100644 index 00000000..00e28e4e --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/SECURITY_CONTACTS @@ -0,0 +1,14 @@ +# Defined below are the security contacts for this repo. +# +# They are the contact point for the Product Security Team to reach out +# to for triaging and handling of incoming issues. +# +# The below names agree to abide by the +# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy) +# and will be removed and replaced if they violate that agreement. +# +# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE +# INSTRUCTIONS AT https://kubernetes.io/security/ + +saad-ali +lpabon diff --git a/vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/Makefile b/vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/Makefile new file mode 100644 index 00000000..520c2153 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/Makefile @@ -0,0 +1,61 @@ +APP_NAME := csi-sanity +VER :=$(shell git describe) +RELEASEVER := $(shell git describe --abbrev=0) +BRANCH := $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD)) +SHA := $(shell git rev-parse --short HEAD) +ARCH := $(shell go env GOARCH) +GOOS := $(shell go env GOOS) +DIR=. + +ifdef APP_SUFFIX + VERSION = $(VER)-$(subst /,-,$(APP_SUFFIX)) +else +ifeq (master,$(BRANCH)) + VERSION = $(VER) +else + VERSION = $(VER)-$(BRANCH) +endif +endif + +LDFLAGS :=-ldflags "-w -X github.com/kubernetes-csi/csi-test/cmd/csi-sanity.VERSION=$(VERSION) -extldflags '-z relro -z now'" +PACKAGE :=$(DIR)/dist/$(APP_NAME)-$(RELEASEVER).$(GOOS).$(ARCH).tar.gz + +all: $(APP_NAME) + +$(APP_NAME): Makefile sanity_test.go + go test $(LDFLAGS) -c -o $(APP_NAME) + +install: $(APP_NAME) + cp $(APP_NAME) $(GOPATH)/bin + +clean: + rm -f csi-sanity + +dist-clean: + rm -rf $(DIR)/dist + +dist: clean $(PACKAGE) + +$(PACKAGE): $(APP_NAME) + @echo Packaging Binaries... + @mkdir -p tmp/$(APP_NAME) + @cp $(APP_NAME) tmp/$(APP_NAME)/ + @mkdir -p $(DIR)/dist/ + tar -czf $@ -C tmp $(APP_NAME); + @rm -rf tmp + @echo + @echo Package $@ saved in dist directory + +linux_amd64_dist: + GOOS=linux GOARCH=amd64 $(MAKE) dist + +linux_arm64_dist: + GOOS=linux GOARCH=arm64 $(MAKE) dist + +darwin_amd64_dist: + GOOS=darwin GOARCH=amd64 $(MAKE) dist + +release: dist-clean darwin_amd64_dist linux_amd64_dist linux_arm64_dist + +.PHONY: release darwin_amd64_dist linux_arm64_dist linux_amd64_dist \ + linux_arm_dist linux_amd64_dist clean dist-clean diff --git a/vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/README.md b/vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/README.md new file mode 100644 index 00000000..dade1018 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/README.md @@ -0,0 +1,58 @@ +# Sanity Test Command Line Program +This is the command line program that tests a CSI driver using the [`sanity`](https://github.com/kubernetes-csi/csi-test/tree/master/pkg/sanity) package test suite. + +Example: + +``` +$ csi-sanity --csi.endpoint= +``` + +If you want to specify a mount point: + +``` +$ csi-sanity --csi.endpoint= --csi.mountpoint=/mnt +``` + +For verbose type: + +``` +$ csi-sanity --ginkgo.v --csi.endpoint= +``` + +For csi-credentials, create a secrets file with all the secrets in it: +```yaml +CreateVolumeSecret: + secretKey: secretval1 +DeleteVolumeSecret: + secretKey: secretval2 +ControllerPublishVolumeSecret: + secretKey: secretval3 +ControllerUnpublishVolumeSecret: + secretKey: secretval4 +NodeStageVolumeSecret: + secretKey: secretval5 +NodePublishVolumeSecret: + secretKey: secretval6 +``` + +Pass the file path to csi-sanity as: +``` +$ csi-sanity --csi.endpoint= --csi.secrets= +``` + +Replace the keys and values of the credentials appropriately. Since the whole +secret is passed in the request, multiple key-val pairs can be used. + +### Help +The full Ginkgo and golang unit test parameters are available. Type + +``` +$ csi-sanity -h +``` + +to get more information + +### Download + +Please see the [Releases](https://github.com/kubernetes-csi/csi-test/releases) page +to download the latest version of `csi-sanity` diff --git a/vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/sanity_test.go b/vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/sanity_test.go new file mode 100644 index 00000000..a4f4707a --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/sanity_test.go @@ -0,0 +1,56 @@ +/* +Copyright 2017 Luis Pabón luis@portworx.com + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package sanity + +import ( + "flag" + "fmt" + "os" + "testing" + + "github.com/kubernetes-csi/csi-test/pkg/sanity" +) + +const ( + prefix string = "csi." +) + +var ( + VERSION = "(dev)" + version bool + config sanity.Config +) + +func init() { + flag.StringVar(&config.Address, prefix+"endpoint", "", "CSI endpoint") + flag.BoolVar(&version, prefix+"version", false, "Version of this program") + flag.StringVar(&config.TargetPath, prefix+"mountdir", os.TempDir()+"/csi", "Mount point for NodePublish") + flag.StringVar(&config.StagingPath, prefix+"stagingdir", os.TempDir()+"/csi", "Mount point for NodeStage if staging is supported") + flag.StringVar(&config.SecretsFile, prefix+"secrets", "", "CSI secrets file") + flag.Int64Var(&config.TestVolumeSize, prefix+"testvolumesize", sanity.DefTestVolumeSize, "Base volume size used for provisioned volumes") + flag.Parse() +} + +func TestSanity(t *testing.T) { + if version { + fmt.Printf("Version = %s\n", VERSION) + return + } + if len(config.Address) == 0 { + t.Fatalf("--%sendpoint must be provided with an CSI endpoint", prefix) + } + sanity.Test(t, &config) +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/code-of-conduct.md b/vendor/github.com/kubernetes-csi/csi-test/code-of-conduct.md new file mode 100644 index 00000000..0d15c00c --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/code-of-conduct.md @@ -0,0 +1,3 @@ +# Kubernetes Community Code of Conduct + +Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) diff --git a/vendor/github.com/kubernetes-csi/csi-test/driver/driver.go b/vendor/github.com/kubernetes-csi/csi-test/driver/driver.go new file mode 100644 index 00000000..a8cd796f --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/driver/driver.go @@ -0,0 +1,247 @@ +/* +Copyright 2017 Luis Pabón luis@portworx.com + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//go:generate mockgen -package=driver -destination=driver.mock.go github.com/container-storage-interface/spec/lib/go/csi/v0 IdentityServer,ControllerServer,NodeServer + +package driver + +import ( + "context" + "errors" + "net" + "sync" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/container-storage-interface/spec/lib/go/csi/v0" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +var ( + // ErrNoCredentials is the error when a secret is enabled but not passed in the request. + ErrNoCredentials = errors.New("secret must be provided") + // ErrAuthFailed is the error when the secret is incorrect. + ErrAuthFailed = errors.New("authentication failed") +) + +type CSIDriverServers struct { + Controller csi.ControllerServer + Identity csi.IdentityServer + Node csi.NodeServer +} + +// This is the key name in all the CSI secret objects. +const secretField = "secretKey" + +// CSICreds is a driver specific secret type. Drivers can have a key-val pair of +// secrets. This mock driver has a single string secret with secretField as the +// key. +type CSICreds struct { + CreateVolumeSecret string + DeleteVolumeSecret string + ControllerPublishVolumeSecret string + ControllerUnpublishVolumeSecret string + NodeStageVolumeSecret string + NodePublishVolumeSecret string + CreateSnapshotSecret string + DeleteSnapshotSecret string +} + +type CSIDriver struct { + listener net.Listener + server *grpc.Server + servers *CSIDriverServers + wg sync.WaitGroup + running bool + lock sync.Mutex + creds *CSICreds +} + +func NewCSIDriver(servers *CSIDriverServers) *CSIDriver { + return &CSIDriver{ + servers: servers, + } +} + +func (c *CSIDriver) goServe(started chan<- bool) { + c.wg.Add(1) + go func() { + defer c.wg.Done() + started <- true + err := c.server.Serve(c.listener) + if err != nil { + panic(err.Error()) + } + }() +} + +func (c *CSIDriver) Address() string { + return c.listener.Addr().String() +} +func (c *CSIDriver) Start(l net.Listener) error { + c.lock.Lock() + defer c.lock.Unlock() + + // Set listener + c.listener = l + + // Create a new grpc server + c.server = grpc.NewServer( + grpc.UnaryInterceptor(c.authInterceptor), + ) + + // Register Mock servers + if c.servers.Controller != nil { + csi.RegisterControllerServer(c.server, c.servers.Controller) + } + if c.servers.Identity != nil { + csi.RegisterIdentityServer(c.server, c.servers.Identity) + } + if c.servers.Node != nil { + csi.RegisterNodeServer(c.server, c.servers.Node) + } + reflection.Register(c.server) + + // Start listening for requests + waitForServer := make(chan bool) + c.goServe(waitForServer) + <-waitForServer + c.running = true + return nil +} + +func (c *CSIDriver) Stop() { + c.lock.Lock() + defer c.lock.Unlock() + + if !c.running { + return + } + + c.server.Stop() + c.wg.Wait() +} + +func (c *CSIDriver) Close() { + c.server.Stop() +} + +func (c *CSIDriver) IsRunning() bool { + c.lock.Lock() + defer c.lock.Unlock() + + return c.running +} + +// SetDefaultCreds sets the default secrets for CSI creds. +func (c *CSIDriver) SetDefaultCreds() { + c.creds = &CSICreds{ + CreateVolumeSecret: "secretval1", + DeleteVolumeSecret: "secretval2", + ControllerPublishVolumeSecret: "secretval3", + ControllerUnpublishVolumeSecret: "secretval4", + NodeStageVolumeSecret: "secretval5", + NodePublishVolumeSecret: "secretval6", + CreateSnapshotSecret: "secretval7", + DeleteSnapshotSecret: "secretval8", + } +} + +func (c *CSIDriver) authInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + if c.creds != nil { + authenticated, authErr := isAuthenticated(req, c.creds) + if !authenticated { + if authErr == ErrNoCredentials { + return nil, status.Error(codes.InvalidArgument, authErr.Error()) + } + if authErr == ErrAuthFailed { + return nil, status.Error(codes.Unauthenticated, authErr.Error()) + } + } + } + + h, err := handler(ctx, req) + + return h, err +} + +func isAuthenticated(req interface{}, creds *CSICreds) (bool, error) { + switch r := req.(type) { + case *csi.CreateVolumeRequest: + return authenticateCreateVolume(r, creds) + case *csi.DeleteVolumeRequest: + return authenticateDeleteVolume(r, creds) + case *csi.ControllerPublishVolumeRequest: + return authenticateControllerPublishVolume(r, creds) + case *csi.ControllerUnpublishVolumeRequest: + return authenticateControllerUnpublishVolume(r, creds) + case *csi.NodeStageVolumeRequest: + return authenticateNodeStageVolume(r, creds) + case *csi.NodePublishVolumeRequest: + return authenticateNodePublishVolume(r, creds) + case *csi.CreateSnapshotRequest: + return authenticateCreateSnapshot(r, creds) + case *csi.DeleteSnapshotRequest: + return authenticateDeleteSnapshot(r, creds) + default: + return true, nil + } +} + +func authenticateCreateVolume(req *csi.CreateVolumeRequest, creds *CSICreds) (bool, error) { + return credsCheck(req.GetControllerCreateSecrets(), creds.CreateVolumeSecret) +} + +func authenticateDeleteVolume(req *csi.DeleteVolumeRequest, creds *CSICreds) (bool, error) { + return credsCheck(req.GetControllerDeleteSecrets(), creds.DeleteVolumeSecret) +} + +func authenticateControllerPublishVolume(req *csi.ControllerPublishVolumeRequest, creds *CSICreds) (bool, error) { + return credsCheck(req.GetControllerPublishSecrets(), creds.ControllerPublishVolumeSecret) +} + +func authenticateControllerUnpublishVolume(req *csi.ControllerUnpublishVolumeRequest, creds *CSICreds) (bool, error) { + return credsCheck(req.GetControllerUnpublishSecrets(), creds.ControllerUnpublishVolumeSecret) +} + +func authenticateNodeStageVolume(req *csi.NodeStageVolumeRequest, creds *CSICreds) (bool, error) { + return credsCheck(req.GetNodeStageSecrets(), creds.NodeStageVolumeSecret) +} + +func authenticateNodePublishVolume(req *csi.NodePublishVolumeRequest, creds *CSICreds) (bool, error) { + return credsCheck(req.GetNodePublishSecrets(), creds.NodePublishVolumeSecret) +} + +func authenticateCreateSnapshot(req *csi.CreateSnapshotRequest, creds *CSICreds) (bool, error) { + return credsCheck(req.GetCreateSnapshotSecrets(), creds.CreateSnapshotSecret) +} + +func authenticateDeleteSnapshot(req *csi.DeleteSnapshotRequest, creds *CSICreds) (bool, error) { + return credsCheck(req.GetDeleteSnapshotSecrets(), creds.DeleteSnapshotSecret) +} + +func credsCheck(secrets map[string]string, secretVal string) (bool, error) { + if len(secrets) == 0 { + return false, ErrNoCredentials + } + + if secrets[secretField] != secretVal { + return false, ErrAuthFailed + } + return true, nil +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/driver/driver.mock.go b/vendor/github.com/kubernetes-csi/csi-test/driver/driver.mock.go new file mode 100644 index 00000000..f6d2b135 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/driver/driver.mock.go @@ -0,0 +1,354 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/container-storage-interface/spec/lib/go/csi/v0 (interfaces: IdentityServer,ControllerServer,NodeServer) + +// Package driver is a generated GoMock package. +package driver + +import ( + context "context" + v0 "github.com/container-storage-interface/spec/lib/go/csi/v0" + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockIdentityServer is a mock of IdentityServer interface +type MockIdentityServer struct { + ctrl *gomock.Controller + recorder *MockIdentityServerMockRecorder +} + +// MockIdentityServerMockRecorder is the mock recorder for MockIdentityServer +type MockIdentityServerMockRecorder struct { + mock *MockIdentityServer +} + +// NewMockIdentityServer creates a new mock instance +func NewMockIdentityServer(ctrl *gomock.Controller) *MockIdentityServer { + mock := &MockIdentityServer{ctrl: ctrl} + mock.recorder = &MockIdentityServerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockIdentityServer) EXPECT() *MockIdentityServerMockRecorder { + return m.recorder +} + +// GetPluginCapabilities mocks base method +func (m *MockIdentityServer) GetPluginCapabilities(arg0 context.Context, arg1 *v0.GetPluginCapabilitiesRequest) (*v0.GetPluginCapabilitiesResponse, error) { + ret := m.ctrl.Call(m, "GetPluginCapabilities", arg0, arg1) + ret0, _ := ret[0].(*v0.GetPluginCapabilitiesResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPluginCapabilities indicates an expected call of GetPluginCapabilities +func (mr *MockIdentityServerMockRecorder) GetPluginCapabilities(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPluginCapabilities", reflect.TypeOf((*MockIdentityServer)(nil).GetPluginCapabilities), arg0, arg1) +} + +// GetPluginInfo mocks base method +func (m *MockIdentityServer) GetPluginInfo(arg0 context.Context, arg1 *v0.GetPluginInfoRequest) (*v0.GetPluginInfoResponse, error) { + ret := m.ctrl.Call(m, "GetPluginInfo", arg0, arg1) + ret0, _ := ret[0].(*v0.GetPluginInfoResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPluginInfo indicates an expected call of GetPluginInfo +func (mr *MockIdentityServerMockRecorder) GetPluginInfo(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPluginInfo", reflect.TypeOf((*MockIdentityServer)(nil).GetPluginInfo), arg0, arg1) +} + +// Probe mocks base method +func (m *MockIdentityServer) Probe(arg0 context.Context, arg1 *v0.ProbeRequest) (*v0.ProbeResponse, error) { + ret := m.ctrl.Call(m, "Probe", arg0, arg1) + ret0, _ := ret[0].(*v0.ProbeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Probe indicates an expected call of Probe +func (mr *MockIdentityServerMockRecorder) Probe(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Probe", reflect.TypeOf((*MockIdentityServer)(nil).Probe), arg0, arg1) +} + +// MockControllerServer is a mock of ControllerServer interface +type MockControllerServer struct { + ctrl *gomock.Controller + recorder *MockControllerServerMockRecorder +} + +// MockControllerServerMockRecorder is the mock recorder for MockControllerServer +type MockControllerServerMockRecorder struct { + mock *MockControllerServer +} + +// NewMockControllerServer creates a new mock instance +func NewMockControllerServer(ctrl *gomock.Controller) *MockControllerServer { + mock := &MockControllerServer{ctrl: ctrl} + mock.recorder = &MockControllerServerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockControllerServer) EXPECT() *MockControllerServerMockRecorder { + return m.recorder +} + +// ControllerGetCapabilities mocks base method +func (m *MockControllerServer) ControllerGetCapabilities(arg0 context.Context, arg1 *v0.ControllerGetCapabilitiesRequest) (*v0.ControllerGetCapabilitiesResponse, error) { + ret := m.ctrl.Call(m, "ControllerGetCapabilities", arg0, arg1) + ret0, _ := ret[0].(*v0.ControllerGetCapabilitiesResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ControllerGetCapabilities indicates an expected call of ControllerGetCapabilities +func (mr *MockControllerServerMockRecorder) ControllerGetCapabilities(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ControllerGetCapabilities", reflect.TypeOf((*MockControllerServer)(nil).ControllerGetCapabilities), arg0, arg1) +} + +// ControllerPublishVolume mocks base method +func (m *MockControllerServer) ControllerPublishVolume(arg0 context.Context, arg1 *v0.ControllerPublishVolumeRequest) (*v0.ControllerPublishVolumeResponse, error) { + ret := m.ctrl.Call(m, "ControllerPublishVolume", arg0, arg1) + ret0, _ := ret[0].(*v0.ControllerPublishVolumeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ControllerPublishVolume indicates an expected call of ControllerPublishVolume +func (mr *MockControllerServerMockRecorder) ControllerPublishVolume(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ControllerPublishVolume", reflect.TypeOf((*MockControllerServer)(nil).ControllerPublishVolume), arg0, arg1) +} + +// ControllerUnpublishVolume mocks base method +func (m *MockControllerServer) ControllerUnpublishVolume(arg0 context.Context, arg1 *v0.ControllerUnpublishVolumeRequest) (*v0.ControllerUnpublishVolumeResponse, error) { + ret := m.ctrl.Call(m, "ControllerUnpublishVolume", arg0, arg1) + ret0, _ := ret[0].(*v0.ControllerUnpublishVolumeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ControllerUnpublishVolume indicates an expected call of ControllerUnpublishVolume +func (mr *MockControllerServerMockRecorder) ControllerUnpublishVolume(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ControllerUnpublishVolume", reflect.TypeOf((*MockControllerServer)(nil).ControllerUnpublishVolume), arg0, arg1) +} + +// CreateSnapshot mocks base method +func (m *MockControllerServer) CreateSnapshot(arg0 context.Context, arg1 *v0.CreateSnapshotRequest) (*v0.CreateSnapshotResponse, error) { + ret := m.ctrl.Call(m, "CreateSnapshot", arg0, arg1) + ret0, _ := ret[0].(*v0.CreateSnapshotResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateSnapshot indicates an expected call of CreateSnapshot +func (mr *MockControllerServerMockRecorder) CreateSnapshot(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSnapshot", reflect.TypeOf((*MockControllerServer)(nil).CreateSnapshot), arg0, arg1) +} + +// CreateVolume mocks base method +func (m *MockControllerServer) CreateVolume(arg0 context.Context, arg1 *v0.CreateVolumeRequest) (*v0.CreateVolumeResponse, error) { + ret := m.ctrl.Call(m, "CreateVolume", arg0, arg1) + ret0, _ := ret[0].(*v0.CreateVolumeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateVolume indicates an expected call of CreateVolume +func (mr *MockControllerServerMockRecorder) CreateVolume(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateVolume", reflect.TypeOf((*MockControllerServer)(nil).CreateVolume), arg0, arg1) +} + +// DeleteSnapshot mocks base method +func (m *MockControllerServer) DeleteSnapshot(arg0 context.Context, arg1 *v0.DeleteSnapshotRequest) (*v0.DeleteSnapshotResponse, error) { + ret := m.ctrl.Call(m, "DeleteSnapshot", arg0, arg1) + ret0, _ := ret[0].(*v0.DeleteSnapshotResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteSnapshot indicates an expected call of DeleteSnapshot +func (mr *MockControllerServerMockRecorder) DeleteSnapshot(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSnapshot", reflect.TypeOf((*MockControllerServer)(nil).DeleteSnapshot), arg0, arg1) +} + +// DeleteVolume mocks base method +func (m *MockControllerServer) DeleteVolume(arg0 context.Context, arg1 *v0.DeleteVolumeRequest) (*v0.DeleteVolumeResponse, error) { + ret := m.ctrl.Call(m, "DeleteVolume", arg0, arg1) + ret0, _ := ret[0].(*v0.DeleteVolumeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteVolume indicates an expected call of DeleteVolume +func (mr *MockControllerServerMockRecorder) DeleteVolume(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteVolume", reflect.TypeOf((*MockControllerServer)(nil).DeleteVolume), arg0, arg1) +} + +// GetCapacity mocks base method +func (m *MockControllerServer) GetCapacity(arg0 context.Context, arg1 *v0.GetCapacityRequest) (*v0.GetCapacityResponse, error) { + ret := m.ctrl.Call(m, "GetCapacity", arg0, arg1) + ret0, _ := ret[0].(*v0.GetCapacityResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCapacity indicates an expected call of GetCapacity +func (mr *MockControllerServerMockRecorder) GetCapacity(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCapacity", reflect.TypeOf((*MockControllerServer)(nil).GetCapacity), arg0, arg1) +} + +// ListSnapshots mocks base method +func (m *MockControllerServer) ListSnapshots(arg0 context.Context, arg1 *v0.ListSnapshotsRequest) (*v0.ListSnapshotsResponse, error) { + ret := m.ctrl.Call(m, "ListSnapshots", arg0, arg1) + ret0, _ := ret[0].(*v0.ListSnapshotsResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListSnapshots indicates an expected call of ListSnapshots +func (mr *MockControllerServerMockRecorder) ListSnapshots(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSnapshots", reflect.TypeOf((*MockControllerServer)(nil).ListSnapshots), arg0, arg1) +} + +// ListVolumes mocks base method +func (m *MockControllerServer) ListVolumes(arg0 context.Context, arg1 *v0.ListVolumesRequest) (*v0.ListVolumesResponse, error) { + ret := m.ctrl.Call(m, "ListVolumes", arg0, arg1) + ret0, _ := ret[0].(*v0.ListVolumesResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListVolumes indicates an expected call of ListVolumes +func (mr *MockControllerServerMockRecorder) ListVolumes(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListVolumes", reflect.TypeOf((*MockControllerServer)(nil).ListVolumes), arg0, arg1) +} + +// ValidateVolumeCapabilities mocks base method +func (m *MockControllerServer) ValidateVolumeCapabilities(arg0 context.Context, arg1 *v0.ValidateVolumeCapabilitiesRequest) (*v0.ValidateVolumeCapabilitiesResponse, error) { + ret := m.ctrl.Call(m, "ValidateVolumeCapabilities", arg0, arg1) + ret0, _ := ret[0].(*v0.ValidateVolumeCapabilitiesResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ValidateVolumeCapabilities indicates an expected call of ValidateVolumeCapabilities +func (mr *MockControllerServerMockRecorder) ValidateVolumeCapabilities(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateVolumeCapabilities", reflect.TypeOf((*MockControllerServer)(nil).ValidateVolumeCapabilities), arg0, arg1) +} + +// MockNodeServer is a mock of NodeServer interface +type MockNodeServer struct { + ctrl *gomock.Controller + recorder *MockNodeServerMockRecorder +} + +// MockNodeServerMockRecorder is the mock recorder for MockNodeServer +type MockNodeServerMockRecorder struct { + mock *MockNodeServer +} + +// NewMockNodeServer creates a new mock instance +func NewMockNodeServer(ctrl *gomock.Controller) *MockNodeServer { + mock := &MockNodeServer{ctrl: ctrl} + mock.recorder = &MockNodeServerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockNodeServer) EXPECT() *MockNodeServerMockRecorder { + return m.recorder +} + +// NodeGetCapabilities mocks base method +func (m *MockNodeServer) NodeGetCapabilities(arg0 context.Context, arg1 *v0.NodeGetCapabilitiesRequest) (*v0.NodeGetCapabilitiesResponse, error) { + ret := m.ctrl.Call(m, "NodeGetCapabilities", arg0, arg1) + ret0, _ := ret[0].(*v0.NodeGetCapabilitiesResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NodeGetCapabilities indicates an expected call of NodeGetCapabilities +func (mr *MockNodeServerMockRecorder) NodeGetCapabilities(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeGetCapabilities", reflect.TypeOf((*MockNodeServer)(nil).NodeGetCapabilities), arg0, arg1) +} + +// NodeGetId mocks base method +func (m *MockNodeServer) NodeGetId(arg0 context.Context, arg1 *v0.NodeGetIdRequest) (*v0.NodeGetIdResponse, error) { + ret := m.ctrl.Call(m, "NodeGetId", arg0, arg1) + ret0, _ := ret[0].(*v0.NodeGetIdResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NodeGetId indicates an expected call of NodeGetId +func (mr *MockNodeServerMockRecorder) NodeGetId(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeGetId", reflect.TypeOf((*MockNodeServer)(nil).NodeGetId), arg0, arg1) +} + +// NodeGetInfo mocks base method +func (m *MockNodeServer) NodeGetInfo(arg0 context.Context, arg1 *v0.NodeGetInfoRequest) (*v0.NodeGetInfoResponse, error) { + ret := m.ctrl.Call(m, "NodeGetInfo", arg0, arg1) + ret0, _ := ret[0].(*v0.NodeGetInfoResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NodeGetInfo indicates an expected call of NodeGetInfo +func (mr *MockNodeServerMockRecorder) NodeGetInfo(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeGetInfo", reflect.TypeOf((*MockNodeServer)(nil).NodeGetInfo), arg0, arg1) +} + +// NodePublishVolume mocks base method +func (m *MockNodeServer) NodePublishVolume(arg0 context.Context, arg1 *v0.NodePublishVolumeRequest) (*v0.NodePublishVolumeResponse, error) { + ret := m.ctrl.Call(m, "NodePublishVolume", arg0, arg1) + ret0, _ := ret[0].(*v0.NodePublishVolumeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NodePublishVolume indicates an expected call of NodePublishVolume +func (mr *MockNodeServerMockRecorder) NodePublishVolume(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodePublishVolume", reflect.TypeOf((*MockNodeServer)(nil).NodePublishVolume), arg0, arg1) +} + +// NodeStageVolume mocks base method +func (m *MockNodeServer) NodeStageVolume(arg0 context.Context, arg1 *v0.NodeStageVolumeRequest) (*v0.NodeStageVolumeResponse, error) { + ret := m.ctrl.Call(m, "NodeStageVolume", arg0, arg1) + ret0, _ := ret[0].(*v0.NodeStageVolumeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NodeStageVolume indicates an expected call of NodeStageVolume +func (mr *MockNodeServerMockRecorder) NodeStageVolume(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeStageVolume", reflect.TypeOf((*MockNodeServer)(nil).NodeStageVolume), arg0, arg1) +} + +// NodeUnpublishVolume mocks base method +func (m *MockNodeServer) NodeUnpublishVolume(arg0 context.Context, arg1 *v0.NodeUnpublishVolumeRequest) (*v0.NodeUnpublishVolumeResponse, error) { + ret := m.ctrl.Call(m, "NodeUnpublishVolume", arg0, arg1) + ret0, _ := ret[0].(*v0.NodeUnpublishVolumeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NodeUnpublishVolume indicates an expected call of NodeUnpublishVolume +func (mr *MockNodeServerMockRecorder) NodeUnpublishVolume(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeUnpublishVolume", reflect.TypeOf((*MockNodeServer)(nil).NodeUnpublishVolume), arg0, arg1) +} + +// NodeUnstageVolume mocks base method +func (m *MockNodeServer) NodeUnstageVolume(arg0 context.Context, arg1 *v0.NodeUnstageVolumeRequest) (*v0.NodeUnstageVolumeResponse, error) { + ret := m.ctrl.Call(m, "NodeUnstageVolume", arg0, arg1) + ret0, _ := ret[0].(*v0.NodeUnstageVolumeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NodeUnstageVolume indicates an expected call of NodeUnstageVolume +func (mr *MockNodeServerMockRecorder) NodeUnstageVolume(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeUnstageVolume", reflect.TypeOf((*MockNodeServer)(nil).NodeUnstageVolume), arg0, arg1) +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/driver/mock.go b/vendor/github.com/kubernetes-csi/csi-test/driver/mock.go new file mode 100644 index 00000000..9b051eee --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/driver/mock.go @@ -0,0 +1,83 @@ +/* +Copyright 2017 Luis Pabón luis@portworx.com + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +import ( + "net" + + "github.com/kubernetes-csi/csi-test/utils" + "google.golang.org/grpc" +) + +type MockCSIDriverServers struct { + Controller *MockControllerServer + Identity *MockIdentityServer + Node *MockNodeServer +} + +type MockCSIDriver struct { + CSIDriver + conn *grpc.ClientConn +} + +func NewMockCSIDriver(servers *MockCSIDriverServers) *MockCSIDriver { + return &MockCSIDriver{ + CSIDriver: CSIDriver{ + servers: &CSIDriverServers{ + Controller: servers.Controller, + Node: servers.Node, + Identity: servers.Identity, + }, + }, + } +} + +func (m *MockCSIDriver) Start() error { + // Listen on a port assigned by the net package + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return err + } + + if err := m.CSIDriver.Start(l); err != nil { + l.Close() + return err + } + + return nil +} + +func (m *MockCSIDriver) Nexus() (*grpc.ClientConn, error) { + // Start server + err := m.Start() + if err != nil { + return nil, err + } + + // Create a client connection + m.conn, err = utils.Connect(m.Address()) + if err != nil { + return nil, err + } + + return m.conn, nil +} + +func (m *MockCSIDriver) Close() { + m.conn.Close() + m.server.Stop() +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/hack/e2e.sh b/vendor/github.com/kubernetes-csi/csi-test/hack/e2e.sh new file mode 100755 index 00000000..777250eb --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/hack/e2e.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +TESTARGS=$@ +UDS="/tmp/e2e-csi-sanity.sock" +CSI_ENDPOINTS="$CSI_ENDPOINTS ${UDS}" +CSI_MOCK_VERSION="master" + +# +# $1 - endpoint for mock. +# $2 - endpoint for csi-sanity in Grpc format. +# See https://github.com/grpc/grpc/blob/master/doc/naming.md +runTest() +{ + CSI_ENDPOINT=$1 ./bin/mock & + local pid=$! + + ./cmd/csi-sanity/csi-sanity $TESTARGS --csi.endpoint=$2; ret=$? + kill -9 $pid + + if [ $ret -ne 0 ] ; then + exit $ret + fi +} + +runTestWithCreds() +{ + CSI_ENDPOINT=$1 CSI_ENABLE_CREDS=true ./bin/mock & + local pid=$! + + ./cmd/csi-sanity/csi-sanity $TESTARGS --csi.endpoint=$2 --csi.secrets=mock/mocksecret.yaml; ret=$? + kill -9 $pid + + if [ $ret -ne 0 ] ; then + exit $ret + fi +} + +go build -o bin/mock ./mock || exit 1 + +cd cmd/csi-sanity + make clean install || exit 1 +cd ../.. + +runTest "${UDS}" "${UDS}" +rm -f $UDS + +runTestWithCreds "${UDS}" "${UDS}" +rm -f $UDS + +exit 0 diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/AUTHORS b/vendor/github.com/kubernetes-csi/csi-test/mock/AUTHORS new file mode 100644 index 00000000..23eabcd2 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/AUTHORS @@ -0,0 +1,2 @@ +TheCodeTeam +Kubernetes Authors diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/README.md b/vendor/github.com/kubernetes-csi/csi-test/mock/README.md new file mode 100644 index 00000000..d35e2d26 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/README.md @@ -0,0 +1,2 @@ +# Mock CSI Driver +Extremely simple mock driver used to test `csi-sanity` based on `rexray/gocsi/mock` diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/cache/SnapshotCache.go b/vendor/github.com/kubernetes-csi/csi-test/mock/cache/SnapshotCache.go new file mode 100644 index 00000000..14343d04 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/cache/SnapshotCache.go @@ -0,0 +1,89 @@ +package cache + +import ( + "strings" + "sync" + + "github.com/container-storage-interface/spec/lib/go/csi/v0" +) + +type SnapshotCache interface { + Add(snapshot Snapshot) + + Delete(i int) + + List(status csi.SnapshotStatus_Type) []csi.Snapshot + + FindSnapshot(k, v string) (int, Snapshot) +} + +type Snapshot struct { + Name string + Parameters map[string]string + SnapshotCSI csi.Snapshot +} + +type snapshotCache struct { + snapshotsRWL sync.RWMutex + snapshots []Snapshot +} + +func NewSnapshotCache() SnapshotCache { + return &snapshotCache{ + snapshots: make([]Snapshot, 0), + } +} + +func (snap *snapshotCache) Add(snapshot Snapshot) { + snap.snapshotsRWL.Lock() + defer snap.snapshotsRWL.Unlock() + + snap.snapshots = append(snap.snapshots, snapshot) +} + +func (snap *snapshotCache) Delete(i int) { + snap.snapshotsRWL.Lock() + defer snap.snapshotsRWL.Unlock() + + copy(snap.snapshots[i:], snap.snapshots[i+1:]) + snap.snapshots = snap.snapshots[:len(snap.snapshots)-1] +} + +func (snap *snapshotCache) List(status csi.SnapshotStatus_Type) []csi.Snapshot { + snap.snapshotsRWL.RLock() + defer snap.snapshotsRWL.RUnlock() + + snapshots := make([]csi.Snapshot, 0) + for _, v := range snap.snapshots { + if v.SnapshotCSI.GetStatus() != nil && v.SnapshotCSI.GetStatus().Type == status { + snapshots = append(snapshots, v.SnapshotCSI) + } + } + + return snapshots +} + +func (snap *snapshotCache) FindSnapshot(k, v string) (int, Snapshot) { + snap.snapshotsRWL.RLock() + defer snap.snapshotsRWL.RUnlock() + + snapshotIdx := -1 + for i, vi := range snap.snapshots { + switch k { + case "id": + if strings.EqualFold(v, vi.SnapshotCSI.Id) { + return i, vi + } + case "sourceVolumeId": + if strings.EqualFold(v, vi.SnapshotCSI.SourceVolumeId) { + return i, vi + } + case "name": + if vi.Name == v { + return i, vi + } + } + } + + return snapshotIdx, Snapshot{} +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/main.go b/vendor/github.com/kubernetes-csi/csi-test/mock/main.go new file mode 100644 index 00000000..d66d1881 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/main.go @@ -0,0 +1,88 @@ +/* +Copyright 2018 Kubernetes Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package main + +import ( + "fmt" + "net" + "os" + "os/signal" + "strings" + "syscall" + + "github.com/kubernetes-csi/csi-test/driver" + "github.com/kubernetes-csi/csi-test/mock/service" +) + +func main() { + endpoint := os.Getenv("CSI_ENDPOINT") + if len(endpoint) == 0 { + fmt.Println("CSI_ENDPOINT must be defined and must be a path") + os.Exit(1) + } + if strings.Contains(endpoint, ":") { + fmt.Println("CSI_ENDPOINT must be a unix path") + os.Exit(1) + } + + // Create mock driver + s := service.New() + servers := &driver.CSIDriverServers{ + Controller: s, + Identity: s, + Node: s, + } + d := driver.NewCSIDriver(servers) + + // If creds is enabled, set the default creds. + setCreds := os.Getenv("CSI_ENABLE_CREDS") + if len(setCreds) > 0 && setCreds == "true" { + d.SetDefaultCreds() + } + + // Listen + os.Remove(endpoint) + l, err := net.Listen("unix", endpoint) + if err != nil { + fmt.Printf("Error: Unable to listen on %s socket: %v\n", + endpoint, + err) + os.Exit(1) + } + defer os.Remove(endpoint) + + // Start server + if err := d.Start(l); err != nil { + fmt.Printf("Error: Unable to start mock CSI server: %v\n", + err) + os.Exit(1) + } + fmt.Println("mock driver started") + + // Wait for signal + sigc := make(chan os.Signal, 1) + sigs := []os.Signal{ + syscall.SIGTERM, + syscall.SIGHUP, + syscall.SIGINT, + syscall.SIGQUIT, + } + signal.Notify(sigc, sigs...) + + <-sigc + d.Stop() + fmt.Println("mock driver stopped") +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/mocksecret.yaml b/vendor/github.com/kubernetes-csi/csi-test/mock/mocksecret.yaml new file mode 100644 index 00000000..e7c9f20d --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/mocksecret.yaml @@ -0,0 +1,16 @@ +CreateVolumeSecret: + secretKey: secretval1 +DeleteVolumeSecret: + secretKey: secretval2 +ControllerPublishVolumeSecret: + secretKey: secretval3 +ControllerUnpublishVolumeSecret: + secretKey: secretval4 +NodeStageVolumeSecret: + secretKey: secretval5 +NodePublishVolumeSecret: + secretKey: secretval6 +CreateSnapshotSecret: + secretKey: secretval7 +DeleteSnapshotSecret: + secretKey: secretval8 diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/service/controller.go b/vendor/github.com/kubernetes-csi/csi-test/mock/service/controller.go new file mode 100644 index 00000000..39176bdd --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/service/controller.go @@ -0,0 +1,559 @@ +package service + +import ( + "fmt" + "math" + "path" + "reflect" + "strconv" + + log "github.com/sirupsen/logrus" + "golang.org/x/net/context" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/container-storage-interface/spec/lib/go/csi/v0" +) + +const ( + MaxStorageCapacity = tib + ReadOnlyKey = "readonly" +) + +func (s *service) CreateVolume( + ctx context.Context, + req *csi.CreateVolumeRequest) ( + *csi.CreateVolumeResponse, error) { + + if len(req.Name) == 0 { + return nil, status.Error(codes.InvalidArgument, "Volume Name cannot be empty") + } + if req.VolumeCapabilities == nil { + return nil, status.Error(codes.InvalidArgument, "Volume Capabilities cannot be empty") + } + + // Check to see if the volume already exists. + if i, v := s.findVolByName(ctx, req.Name); i >= 0 { + // Requested volume name already exists, need to check if the existing volume's + // capacity is more or equal to new request's capacity. + if v.GetCapacityBytes() < req.GetCapacityRange().GetRequiredBytes() { + return nil, status.Error(codes.AlreadyExists, + fmt.Sprintf("Volume with name %s already exists", req.GetName())) + } + return &csi.CreateVolumeResponse{Volume: &v}, nil + } + + // If no capacity is specified then use 100GiB + capacity := gib100 + if cr := req.CapacityRange; cr != nil { + if rb := cr.RequiredBytes; rb > 0 { + capacity = rb + } + if lb := cr.LimitBytes; lb > 0 { + capacity = lb + } + } + // Check for maximum available capacity + if capacity >= MaxStorageCapacity { + return nil, status.Errorf(codes.OutOfRange, "Requested capacity %d exceeds maximum allowed %d", capacity, MaxStorageCapacity) + } + // Create the volume and add it to the service's in-mem volume slice. + v := s.newVolume(req.Name, capacity) + s.volsRWL.Lock() + defer s.volsRWL.Unlock() + s.vols = append(s.vols, v) + MockVolumes[v.Id] = Volume{ + VolumeCSI: v, + NodeID: "", + ISStaged: false, + ISPublished: false, + StageTargetPath: "", + TargetPath: "", + } + + return &csi.CreateVolumeResponse{Volume: &v}, nil +} + +func (s *service) DeleteVolume( + ctx context.Context, + req *csi.DeleteVolumeRequest) ( + *csi.DeleteVolumeResponse, error) { + + s.volsRWL.Lock() + defer s.volsRWL.Unlock() + + // If the volume is not specified, return error + if len(req.VolumeId) == 0 { + return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty") + } + + // If the volume does not exist then return an idempotent response. + i, _ := s.findVolNoLock("id", req.VolumeId) + if i < 0 { + return &csi.DeleteVolumeResponse{}, nil + } + + // This delete logic preserves order and prevents potential memory + // leaks. The slice's elements may not be pointers, but the structs + // themselves have fields that are. + copy(s.vols[i:], s.vols[i+1:]) + s.vols[len(s.vols)-1] = csi.Volume{} + s.vols = s.vols[:len(s.vols)-1] + log.WithField("volumeID", req.VolumeId).Debug("mock delete volume") + return &csi.DeleteVolumeResponse{}, nil +} + +func (s *service) ControllerPublishVolume( + ctx context.Context, + req *csi.ControllerPublishVolumeRequest) ( + *csi.ControllerPublishVolumeResponse, error) { + + if len(req.VolumeId) == 0 { + return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty") + } + if len(req.NodeId) == 0 { + return nil, status.Error(codes.InvalidArgument, "Node ID cannot be empty") + } + if req.VolumeCapability == nil { + return nil, status.Error(codes.InvalidArgument, "Volume Capabilities cannot be empty") + } + + if req.NodeId != s.nodeID { + return nil, status.Errorf(codes.NotFound, "Not matching Node ID %s to Mock Node ID %s", req.NodeId, s.nodeID) + } + + s.volsRWL.Lock() + defer s.volsRWL.Unlock() + + i, v := s.findVolNoLock("id", req.VolumeId) + if i < 0 { + return nil, status.Error(codes.NotFound, req.VolumeId) + } + + // devPathKey is the key in the volume's attributes that is set to a + // mock device path if the volume has been published by the controller + // to the specified node. + devPathKey := path.Join(req.NodeId, "dev") + + // Check to see if the volume is already published. + if device := v.Attributes[devPathKey]; device != "" { + var volRo bool + var roVal string + if ro, ok := v.Attributes[ReadOnlyKey]; ok { + roVal = ro + } + + if roVal == "true" { + volRo = true + } else { + volRo = false + } + + // Check if readonly flag is compatible with the publish request. + if req.GetReadonly() != volRo { + return nil, status.Error(codes.AlreadyExists, "Volume published but has incompatible readonly flag") + } + + return &csi.ControllerPublishVolumeResponse{ + PublishInfo: map[string]string{ + "device": device, + "readonly": roVal, + }, + }, nil + } + + var roVal string + if req.GetReadonly() { + roVal = "true" + } else { + roVal = "false" + } + + // Publish the volume. + device := "/dev/mock" + v.Attributes[devPathKey] = device + v.Attributes[ReadOnlyKey] = roVal + s.vols[i] = v + + return &csi.ControllerPublishVolumeResponse{ + PublishInfo: map[string]string{ + "device": device, + "readonly": roVal, + }, + }, nil +} + +func (s *service) ControllerUnpublishVolume( + ctx context.Context, + req *csi.ControllerUnpublishVolumeRequest) ( + *csi.ControllerUnpublishVolumeResponse, error) { + + if len(req.VolumeId) == 0 { + return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty") + } + nodeID := req.NodeId + if len(nodeID) == 0 { + // If node id is empty, no failure as per Spec + nodeID = s.nodeID + } + + if req.NodeId != s.nodeID { + return nil, status.Errorf(codes.NotFound, "Node ID %s does not match to expected Node ID %s", req.NodeId, s.nodeID) + } + + s.volsRWL.Lock() + defer s.volsRWL.Unlock() + + i, v := s.findVolNoLock("id", req.VolumeId) + if i < 0 { + return nil, status.Error(codes.NotFound, req.VolumeId) + } + + // devPathKey is the key in the volume's attributes that is set to a + // mock device path if the volume has been published by the controller + // to the specified node. + devPathKey := path.Join(nodeID, "dev") + + // Check to see if the volume is already unpublished. + if v.Attributes[devPathKey] == "" { + return &csi.ControllerUnpublishVolumeResponse{}, nil + } + + // Unpublish the volume. + delete(v.Attributes, devPathKey) + delete(v.Attributes, ReadOnlyKey) + s.vols[i] = v + + return &csi.ControllerUnpublishVolumeResponse{}, nil +} + +func (s *service) ValidateVolumeCapabilities( + ctx context.Context, + req *csi.ValidateVolumeCapabilitiesRequest) ( + *csi.ValidateVolumeCapabilitiesResponse, error) { + + if len(req.GetVolumeId()) == 0 { + return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty") + } + if len(req.VolumeCapabilities) == 0 { + return nil, status.Error(codes.InvalidArgument, req.VolumeId) + } + i, _ := s.findVolNoLock("id", req.VolumeId) + if i < 0 { + return nil, status.Error(codes.NotFound, req.VolumeId) + } + + return &csi.ValidateVolumeCapabilitiesResponse{ + Supported: true, + }, nil +} + +func (s *service) ListVolumes( + ctx context.Context, + req *csi.ListVolumesRequest) ( + *csi.ListVolumesResponse, error) { + + // Copy the mock volumes into a new slice in order to avoid + // locking the service's volume slice for the duration of the + // ListVolumes RPC. + var vols []csi.Volume + func() { + s.volsRWL.RLock() + defer s.volsRWL.RUnlock() + vols = make([]csi.Volume, len(s.vols)) + copy(vols, s.vols) + }() + + var ( + ulenVols = int32(len(vols)) + maxEntries = req.MaxEntries + startingToken int32 + ) + + if v := req.StartingToken; v != "" { + i, err := strconv.ParseUint(v, 10, 32) + if err != nil { + return nil, status.Errorf( + codes.InvalidArgument, + "startingToken=%d !< int32=%d", + startingToken, math.MaxUint32) + } + startingToken = int32(i) + } + + if startingToken > ulenVols { + return nil, status.Errorf( + codes.InvalidArgument, + "startingToken=%d > len(vols)=%d", + startingToken, ulenVols) + } + + // Discern the number of remaining entries. + rem := ulenVols - startingToken + + // If maxEntries is 0 or greater than the number of remaining entries then + // set maxEntries to the number of remaining entries. + if maxEntries == 0 || maxEntries > rem { + maxEntries = rem + } + + var ( + i int + j = startingToken + entries = make( + []*csi.ListVolumesResponse_Entry, + maxEntries) + ) + + for i = 0; i < len(entries); i++ { + entries[i] = &csi.ListVolumesResponse_Entry{ + Volume: &vols[j], + } + j++ + } + + var nextToken string + if n := startingToken + int32(i); n < ulenVols { + nextToken = fmt.Sprintf("%d", n) + } + + return &csi.ListVolumesResponse{ + Entries: entries, + NextToken: nextToken, + }, nil +} + +func (s *service) GetCapacity( + ctx context.Context, + req *csi.GetCapacityRequest) ( + *csi.GetCapacityResponse, error) { + + return &csi.GetCapacityResponse{ + AvailableCapacity: MaxStorageCapacity, + }, nil +} + +func (s *service) ControllerGetCapabilities( + ctx context.Context, + req *csi.ControllerGetCapabilitiesRequest) ( + *csi.ControllerGetCapabilitiesResponse, error) { + + return &csi.ControllerGetCapabilitiesResponse{ + Capabilities: []*csi.ControllerServiceCapability{ + { + Type: &csi.ControllerServiceCapability_Rpc{ + Rpc: &csi.ControllerServiceCapability_RPC{ + Type: csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME, + }, + }, + }, + { + Type: &csi.ControllerServiceCapability_Rpc{ + Rpc: &csi.ControllerServiceCapability_RPC{ + Type: csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME, + }, + }, + }, + { + Type: &csi.ControllerServiceCapability_Rpc{ + Rpc: &csi.ControllerServiceCapability_RPC{ + Type: csi.ControllerServiceCapability_RPC_LIST_VOLUMES, + }, + }, + }, + { + Type: &csi.ControllerServiceCapability_Rpc{ + Rpc: &csi.ControllerServiceCapability_RPC{ + Type: csi.ControllerServiceCapability_RPC_GET_CAPACITY, + }, + }, + }, + { + Type: &csi.ControllerServiceCapability_Rpc{ + Rpc: &csi.ControllerServiceCapability_RPC{ + Type: csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS, + }, + }, + }, + { + Type: &csi.ControllerServiceCapability_Rpc{ + Rpc: &csi.ControllerServiceCapability_RPC{ + Type: csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT, + }, + }, + }, + }, + }, nil +} + +func (s *service) CreateSnapshot(ctx context.Context, + req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) { + // Check arguments + if len(req.GetName()) == 0 { + return nil, status.Error(codes.InvalidArgument, "Snapshot Name cannot be empty") + } + if len(req.GetSourceVolumeId()) == 0 { + return nil, status.Error(codes.InvalidArgument, "Snapshot SourceVolumeId cannot be empty") + } + + // Check to see if the snapshot already exists. + if i, v := s.snapshots.FindSnapshot("name", req.GetName()); i >= 0 { + // Requested snapshot name already exists + if v.SnapshotCSI.GetSourceVolumeId() != req.GetSourceVolumeId() || !reflect.DeepEqual(v.Parameters, req.GetParameters()) { + return nil, status.Error(codes.AlreadyExists, + fmt.Sprintf("Snapshot with name %s already exists", req.GetName())) + } + return &csi.CreateSnapshotResponse{Snapshot: &v.SnapshotCSI}, nil + } + + // Create the snapshot and add it to the service's in-mem snapshot slice. + snapshot := s.newSnapshot(req.GetName(), req.GetSourceVolumeId(), req.GetParameters()) + s.snapshots.Add(snapshot) + + return &csi.CreateSnapshotResponse{Snapshot: &snapshot.SnapshotCSI}, nil +} + +func (s *service) DeleteSnapshot(ctx context.Context, + req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) { + + // If the snapshot is not specified, return error + if len(req.SnapshotId) == 0 { + return nil, status.Error(codes.InvalidArgument, "Snapshot ID cannot be empty") + } + + // If the snapshot does not exist then return an idempotent response. + i, _ := s.snapshots.FindSnapshot("id", req.SnapshotId) + if i < 0 { + return &csi.DeleteSnapshotResponse{}, nil + } + + // This delete logic preserves order and prevents potential memory + // leaks. The slice's elements may not be pointers, but the structs + // themselves have fields that are. + s.snapshots.Delete(i) + log.WithField("SnapshotId", req.SnapshotId).Debug("mock delete snapshot") + return &csi.DeleteSnapshotResponse{}, nil +} + +func (s *service) ListSnapshots(ctx context.Context, + req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) { + + // case 1: SnapshotId is not empty, return snapshots that match the snapshot id. + if len(req.GetSnapshotId()) != 0 { + return getSnapshotById(s, req) + } + + // case 2: SourceVolumeId is not empty, return snapshots that match the source volume id. + if len(req.GetSourceVolumeId()) != 0 { + return getSnapshotByVolumeId(s, req) + } + + // case 3: no parameter is set, so we return all the snapshots. + return getAllSnapshots(s, req) +} + +func getSnapshotById(s *service, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) { + if len(req.GetSnapshotId()) != 0 { + i, snapshot := s.snapshots.FindSnapshot("id", req.GetSnapshotId()) + if i < 0 { + return &csi.ListSnapshotsResponse{}, nil + } + + if len(req.GetSourceVolumeId()) != 0 { + if snapshot.SnapshotCSI.GetSourceVolumeId() != req.GetSourceVolumeId() { + return &csi.ListSnapshotsResponse{}, nil + } + } + + return &csi.ListSnapshotsResponse{ + Entries: []*csi.ListSnapshotsResponse_Entry{ + { + Snapshot: &snapshot.SnapshotCSI, + }, + }, + }, nil + } + return nil, nil +} + +func getSnapshotByVolumeId(s *service, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) { + if len(req.GetSourceVolumeId()) != 0 { + i, snapshot := s.snapshots.FindSnapshot("sourceVolumeId", req.SourceVolumeId) + if i < 0 { + return &csi.ListSnapshotsResponse{}, nil + } + return &csi.ListSnapshotsResponse{ + Entries: []*csi.ListSnapshotsResponse_Entry{ + { + Snapshot: &snapshot.SnapshotCSI, + }, + }, + }, nil + } + return nil, nil +} + +func getAllSnapshots(s *service, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) { + // Copy the mock snapshots into a new slice in order to avoid + // locking the service's snapshot slice for the duration of the + // ListSnapshots RPC. + snapshots := s.snapshots.List(csi.SnapshotStatus_READY) + + var ( + ulenSnapshots = int32(len(snapshots)) + maxEntries = req.MaxEntries + startingToken int32 + ) + + if v := req.StartingToken; v != "" { + i, err := strconv.ParseUint(v, 10, 32) + if err != nil { + return nil, status.Errorf( + codes.Aborted, + "startingToken=%d !< int32=%d", + startingToken, math.MaxUint32) + } + startingToken = int32(i) + } + + if startingToken > ulenSnapshots { + return nil, status.Errorf( + codes.Aborted, + "startingToken=%d > len(snapshots)=%d", + startingToken, ulenSnapshots) + } + + // Discern the number of remaining entries. + rem := ulenSnapshots - startingToken + + // If maxEntries is 0 or greater than the number of remaining entries then + // set maxEntries to the number of remaining entries. + if maxEntries == 0 || maxEntries > rem { + maxEntries = rem + } + + var ( + i int + j = startingToken + entries = make( + []*csi.ListSnapshotsResponse_Entry, + maxEntries) + ) + + for i = 0; i < len(entries); i++ { + entries[i] = &csi.ListSnapshotsResponse_Entry{ + Snapshot: &snapshots[j], + } + j++ + } + + var nextToken string + if n := startingToken + int32(i); n < ulenSnapshots { + nextToken = fmt.Sprintf("%d", n) + } + + return &csi.ListSnapshotsResponse{ + Entries: entries, + NextToken: nextToken, + }, nil +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/service/identity.go b/vendor/github.com/kubernetes-csi/csi-test/mock/service/identity.go new file mode 100644 index 00000000..c66d3b62 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/service/identity.go @@ -0,0 +1,48 @@ +package service + +import ( + "golang.org/x/net/context" + + "github.com/container-storage-interface/spec/lib/go/csi/v0" + "github.com/golang/protobuf/ptypes/wrappers" +) + +func (s *service) GetPluginInfo( + ctx context.Context, + req *csi.GetPluginInfoRequest) ( + *csi.GetPluginInfoResponse, error) { + + return &csi.GetPluginInfoResponse{ + Name: Name, + VendorVersion: VendorVersion, + Manifest: Manifest, + }, nil +} + +func (s *service) Probe( + ctx context.Context, + req *csi.ProbeRequest) ( + *csi.ProbeResponse, error) { + + return &csi.ProbeResponse{ + Ready: &wrappers.BoolValue{Value: true}, + }, nil +} + +func (s *service) GetPluginCapabilities( + ctx context.Context, + req *csi.GetPluginCapabilitiesRequest) ( + *csi.GetPluginCapabilitiesResponse, error) { + + return &csi.GetPluginCapabilitiesResponse{ + Capabilities: []*csi.PluginCapability{ + { + Type: &csi.PluginCapability_Service_{ + Service: &csi.PluginCapability_Service{ + Type: csi.PluginCapability_Service_CONTROLLER_SERVICE, + }, + }, + }, + }, + }, nil +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/service/node.go b/vendor/github.com/kubernetes-csi/csi-test/mock/service/node.go new file mode 100644 index 00000000..0321c740 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/service/node.go @@ -0,0 +1,236 @@ +package service + +import ( + "path" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "golang.org/x/net/context" + + "github.com/container-storage-interface/spec/lib/go/csi/v0" +) + +func (s *service) NodeStageVolume( + ctx context.Context, + req *csi.NodeStageVolumeRequest) ( + *csi.NodeStageVolumeResponse, error) { + + device, ok := req.PublishInfo["device"] + if !ok { + return nil, status.Error( + codes.InvalidArgument, + "stage volume info 'device' key required") + } + + if len(req.GetVolumeId()) == 0 { + return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty") + } + + if len(req.GetStagingTargetPath()) == 0 { + return nil, status.Error(codes.InvalidArgument, "Staging Target Path cannot be empty") + } + + if req.GetVolumeCapability() == nil { + return nil, status.Error(codes.InvalidArgument, "Volume Capability cannot be empty") + } + + s.volsRWL.Lock() + defer s.volsRWL.Unlock() + + i, v := s.findVolNoLock("id", req.VolumeId) + if i < 0 { + return nil, status.Error(codes.NotFound, req.VolumeId) + } + + // nodeStgPathKey is the key in the volume's attributes that is set to a + // mock stage path if the volume has been published by the node + nodeStgPathKey := path.Join(s.nodeID, req.StagingTargetPath) + + // Check to see if the volume has already been staged. + if v.Attributes[nodeStgPathKey] != "" { + // TODO: Check for the capabilities to be equal. Return "ALREADY_EXISTS" + // if the capabilities don't match. + return &csi.NodeStageVolumeResponse{}, nil + } + + // Stage the volume. + v.Attributes[nodeStgPathKey] = device + s.vols[i] = v + + return &csi.NodeStageVolumeResponse{}, nil +} + +func (s *service) NodeUnstageVolume( + ctx context.Context, + req *csi.NodeUnstageVolumeRequest) ( + *csi.NodeUnstageVolumeResponse, error) { + + if len(req.GetVolumeId()) == 0 { + return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty") + } + + if len(req.GetStagingTargetPath()) == 0 { + return nil, status.Error(codes.InvalidArgument, "Staging Target Path cannot be empty") + } + + s.volsRWL.Lock() + defer s.volsRWL.Unlock() + + i, v := s.findVolNoLock("id", req.VolumeId) + if i < 0 { + return nil, status.Error(codes.NotFound, req.VolumeId) + } + + // nodeStgPathKey is the key in the volume's attributes that is set to a + // mock stage path if the volume has been published by the node + nodeStgPathKey := path.Join(s.nodeID, req.StagingTargetPath) + + // Check to see if the volume has already been unstaged. + if v.Attributes[nodeStgPathKey] == "" { + return &csi.NodeUnstageVolumeResponse{}, nil + } + + // Unpublish the volume. + delete(v.Attributes, nodeStgPathKey) + s.vols[i] = v + + return &csi.NodeUnstageVolumeResponse{}, nil +} + +func (s *service) NodePublishVolume( + ctx context.Context, + req *csi.NodePublishVolumeRequest) ( + *csi.NodePublishVolumeResponse, error) { + + device, ok := req.PublishInfo["device"] + if !ok { + return nil, status.Error( + codes.InvalidArgument, + "publish volume info 'device' key required") + } + + if len(req.GetVolumeId()) == 0 { + return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty") + } + + if len(req.GetTargetPath()) == 0 { + return nil, status.Error(codes.InvalidArgument, "Target Path cannot be empty") + } + + if req.GetVolumeCapability() == nil { + return nil, status.Error(codes.InvalidArgument, "Volume Capability cannot be empty") + } + + s.volsRWL.Lock() + defer s.volsRWL.Unlock() + + i, v := s.findVolNoLock("id", req.VolumeId) + if i < 0 { + return nil, status.Error(codes.NotFound, req.VolumeId) + } + + // nodeMntPathKey is the key in the volume's attributes that is set to a + // mock mount path if the volume has been published by the node + nodeMntPathKey := path.Join(s.nodeID, req.TargetPath) + + // Check to see if the volume has already been published. + if v.Attributes[nodeMntPathKey] != "" { + + // Requests marked Readonly fail due to volumes published by + // the Mock driver supporting only RW mode. + if req.Readonly { + return nil, status.Error(codes.AlreadyExists, req.VolumeId) + } + + return &csi.NodePublishVolumeResponse{}, nil + } + + // Publish the volume. + if req.GetStagingTargetPath() != "" { + v.Attributes[nodeMntPathKey] = req.GetStagingTargetPath() + } else { + v.Attributes[nodeMntPathKey] = device + } + s.vols[i] = v + + return &csi.NodePublishVolumeResponse{}, nil +} + +func (s *service) NodeUnpublishVolume( + ctx context.Context, + req *csi.NodeUnpublishVolumeRequest) ( + *csi.NodeUnpublishVolumeResponse, error) { + + if len(req.GetVolumeId()) == 0 { + return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty") + } + if len(req.GetTargetPath()) == 0 { + return nil, status.Error(codes.InvalidArgument, "Target Path cannot be empty") + } + + s.volsRWL.Lock() + defer s.volsRWL.Unlock() + + i, v := s.findVolNoLock("id", req.VolumeId) + if i < 0 { + return nil, status.Error(codes.NotFound, req.VolumeId) + } + + // nodeMntPathKey is the key in the volume's attributes that is set to a + // mock mount path if the volume has been published by the node + nodeMntPathKey := path.Join(s.nodeID, req.TargetPath) + + // Check to see if the volume has already been unpublished. + if v.Attributes[nodeMntPathKey] == "" { + return &csi.NodeUnpublishVolumeResponse{}, nil + } + + // Unpublish the volume. + delete(v.Attributes, nodeMntPathKey) + s.vols[i] = v + + return &csi.NodeUnpublishVolumeResponse{}, nil +} + +func (s *service) NodeGetId( + ctx context.Context, + req *csi.NodeGetIdRequest) ( + *csi.NodeGetIdResponse, error) { + + return &csi.NodeGetIdResponse{ + NodeId: s.nodeID, + }, nil +} + +func (s *service) NodeGetCapabilities( + ctx context.Context, + req *csi.NodeGetCapabilitiesRequest) ( + *csi.NodeGetCapabilitiesResponse, error) { + + return &csi.NodeGetCapabilitiesResponse{ + Capabilities: []*csi.NodeServiceCapability{ + { + Type: &csi.NodeServiceCapability_Rpc{ + Rpc: &csi.NodeServiceCapability_RPC{ + Type: csi.NodeServiceCapability_RPC_UNKNOWN, + }, + }, + }, + { + Type: &csi.NodeServiceCapability_Rpc{ + Rpc: &csi.NodeServiceCapability_RPC{ + Type: csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME, + }, + }, + }, + }, + }, nil +} + +func (s *service) NodeGetInfo(ctx context.Context, + req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) { + return &csi.NodeGetInfoResponse{ + NodeId: s.nodeID, + }, nil +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/service/service.go b/vendor/github.com/kubernetes-csi/csi-test/mock/service/service.go new file mode 100644 index 00000000..c9f4f7b2 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/service/service.go @@ -0,0 +1,137 @@ +package service + +import ( + "fmt" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/container-storage-interface/spec/lib/go/csi/v0" + "github.com/kubernetes-csi/csi-test/mock/cache" + "golang.org/x/net/context" +) + +const ( + // Name is the name of the CSI plug-in. + Name = "io.kubernetes.storage.mock" + + // VendorVersion is the version returned by GetPluginInfo. + VendorVersion = "0.3.0" +) + +// Manifest is the SP's manifest. +var Manifest = map[string]string{ + "url": "https://github.com/kubernetes-csi/csi-test/mock", +} + +// Service is the CSI Mock service provider. +type Service interface { + csi.ControllerServer + csi.IdentityServer + csi.NodeServer +} + +type service struct { + sync.Mutex + nodeID string + vols []csi.Volume + volsRWL sync.RWMutex + volsNID uint64 + snapshots cache.SnapshotCache + snapshotsNID uint64 +} + +type Volume struct { + sync.Mutex + VolumeCSI csi.Volume + NodeID string + ISStaged bool + ISPublished bool + StageTargetPath string + TargetPath string +} + +var MockVolumes map[string]Volume + +// New returns a new Service. +func New() Service { + s := &service{nodeID: Name} + s.snapshots = cache.NewSnapshotCache() + s.vols = []csi.Volume{ + s.newVolume("Mock Volume 1", gib100), + s.newVolume("Mock Volume 2", gib100), + s.newVolume("Mock Volume 3", gib100), + } + MockVolumes = map[string]Volume{} + + s.snapshots.Add(s.newSnapshot("Mock Snapshot 1", "1", map[string]string{"Description": "snapshot 1"})) + s.snapshots.Add(s.newSnapshot("Mock Snapshot 2", "2", map[string]string{"Description": "snapshot 2"})) + s.snapshots.Add(s.newSnapshot("Mock Snapshot 3", "3", map[string]string{"Description": "snapshot 3"})) + + return s +} + +const ( + kib int64 = 1024 + mib int64 = kib * 1024 + gib int64 = mib * 1024 + gib100 int64 = gib * 100 + tib int64 = gib * 1024 + tib100 int64 = tib * 100 +) + +func (s *service) newVolume(name string, capcity int64) csi.Volume { + return csi.Volume{ + Id: fmt.Sprintf("%d", atomic.AddUint64(&s.volsNID, 1)), + Attributes: map[string]string{"name": name}, + CapacityBytes: capcity, + } +} + +func (s *service) findVol(k, v string) (volIdx int, volInfo csi.Volume) { + s.volsRWL.RLock() + defer s.volsRWL.RUnlock() + return s.findVolNoLock(k, v) +} + +func (s *service) findVolNoLock(k, v string) (volIdx int, volInfo csi.Volume) { + volIdx = -1 + + for i, vi := range s.vols { + switch k { + case "id": + if strings.EqualFold(v, vi.Id) { + return i, vi + } + case "name": + if n, ok := vi.Attributes["name"]; ok && strings.EqualFold(v, n) { + return i, vi + } + } + } + + return +} + +func (s *service) findVolByName( + ctx context.Context, name string) (int, csi.Volume) { + + return s.findVol("name", name) +} + +func (s *service) newSnapshot(name, sourceVolumeId string, parameters map[string]string) cache.Snapshot { + return cache.Snapshot{ + Name: name, + Parameters: parameters, + SnapshotCSI: csi.Snapshot{ + Id: fmt.Sprintf("%d", atomic.AddUint64(&s.snapshotsNID, 1)), + CreatedAt: time.Now().UnixNano(), + SourceVolumeId: sourceVolumeId, + Status: &csi.SnapshotStatus{ + Type: csi.SnapshotStatus_READY, + Details: "snapshot ready", + }, + }, + } +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/README.md b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/README.md new file mode 100644 index 00000000..de4ae501 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/README.md @@ -0,0 +1,62 @@ +# CSI Driver Sanity Tester + +This library provides a simple way to ensure that a CSI driver conforms to +the CSI specification. There are two ways to leverage this testing framework. +For CSI drivers written in Golang, the framework provides a simple API function +to call to test the driver. Another way to run the test suite is to use the +command line program [csi-sanity](https://github.com/kubernetes-csi/csi-test/tree/master/cmd/csi-sanity). + +## For Golang CSI Drivers +This framework leverages the Ginkgo BDD testing framework to deliver a descriptive +test suite for your driver. To test your driver, simply call the API in one of your +Golang `TestXXX` functions. For example: + +```go +func TestMyDriver(t *testing.T) { + // Setup the full driver and its environment + ... setup driver ... + config := &sanity.Config{ + TargetPath: ... + StagingPath: ... + Address: endpoint, + } + + + // Now call the test suite + sanity.Test(t, config) +} +``` + +Only one such test function is supported because under the hood a +Ginkgo test suite gets constructed and executed by the call. + +Alternatively, the tests can also be embedded inside a Ginkgo test +suite. In that case it is possible to define multiple tests with +different configurations: + +```go +var _ = Describe("MyCSIDriver", func () { + Context("Config A", func () { + var config &sanity.Config + + BeforeEach() { + ... setup driver and config... + } + + AfterEach() { + ...tear down driver... + } + + Describe("CSI sanity", func() { + sanity.GinkgoTest(config) + }) + }) + + Context("Config B", func () { + ... + }) +}) +``` + +## Command line program +Please see [csi-sanity](https://github.com/kubernetes-csi/csi-test/tree/master/cmd/csi-sanity) diff --git a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/cleanup.go b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/cleanup.go new file mode 100644 index 00000000..699efe7b --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/cleanup.go @@ -0,0 +1,134 @@ +/* +Copyright 2018 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sanity + +import ( + "context" + "log" + + "github.com/container-storage-interface/spec/lib/go/csi/v0" + + . "github.com/onsi/ginkgo" +) + +// VolumeInfo keeps track of the information needed to delete a volume. +type VolumeInfo struct { + // Node on which the volume was published, empty if none + // or publishing is not supported. + NodeID string + + // Volume ID assigned by CreateVolume. + VolumeID string +} + +// Cleanup keeps track of resources, in particular volumes, which need +// to be freed when testing is done. +type Cleanup struct { + Context *SanityContext + ControllerClient csi.ControllerClient + NodeClient csi.NodeClient + ControllerPublishSupported bool + NodeStageSupported bool + + // Maps from volume name to the node ID for which the volume + // is published and the volume ID. + volumes map[string]VolumeInfo +} + +// RegisterVolume adds or updates an entry for the volume with the +// given name. +func (cl *Cleanup) RegisterVolume(name string, info VolumeInfo) { + if cl.volumes == nil { + cl.volumes = make(map[string]VolumeInfo) + } + cl.volumes[name] = info +} + +// MaybeRegisterVolume adds or updates an entry for the volume with +// the given name if CreateVolume was successful. +func (cl *Cleanup) MaybeRegisterVolume(name string, vol *csi.CreateVolumeResponse, err error) { + if err == nil && vol.GetVolume().GetId() != "" { + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + } +} + +// UnregisterVolume removes the entry for the volume with the +// given name, thus preventing all cleanup operations for it. +func (cl *Cleanup) UnregisterVolume(name string) { + if cl.volumes != nil { + delete(cl.volumes, name) + } +} + +// DeleteVolumes stops using the registered volumes and tries to delete all of them. +func (cl *Cleanup) DeleteVolumes() { + if cl.volumes == nil { + return + } + logger := log.New(GinkgoWriter, "cleanup: ", 0) + ctx := context.Background() + + for name, info := range cl.volumes { + logger.Printf("deleting %s = %s", name, info.VolumeID) + if _, err := cl.NodeClient.NodeUnpublishVolume( + ctx, + &csi.NodeUnpublishVolumeRequest{ + VolumeId: info.VolumeID, + TargetPath: cl.Context.Config.TargetPath, + }, + ); err != nil { + logger.Printf("warning: NodeUnpublishVolume: %s", err) + } + + if cl.NodeStageSupported { + if _, err := cl.NodeClient.NodeUnstageVolume( + ctx, + &csi.NodeUnstageVolumeRequest{ + VolumeId: info.VolumeID, + StagingTargetPath: cl.Context.Config.StagingPath, + }, + ); err != nil { + logger.Printf("warning: NodeUnstageVolume: %s", err) + } + } + + if cl.ControllerPublishSupported && info.NodeID != "" { + if _, err := cl.ControllerClient.ControllerUnpublishVolume( + ctx, + &csi.ControllerUnpublishVolumeRequest{ + VolumeId: info.VolumeID, + NodeId: info.NodeID, + ControllerUnpublishSecrets: cl.Context.Secrets.ControllerUnpublishVolumeSecret, + }, + ); err != nil { + logger.Printf("warning: ControllerUnpublishVolume: %s", err) + } + } + + if _, err := cl.ControllerClient.DeleteVolume( + ctx, + &csi.DeleteVolumeRequest{ + VolumeId: info.VolumeID, + ControllerDeleteSecrets: cl.Context.Secrets.DeleteVolumeSecret, + }, + ); err != nil { + logger.Printf("error: DeleteVolume: %s", err) + } + + cl.UnregisterVolume(name) + } +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/controller.go b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/controller.go new file mode 100644 index 00000000..294a1e0d --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/controller.go @@ -0,0 +1,1626 @@ +/* +Copyright 2017 Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sanity + +import ( + "context" + "fmt" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/container-storage-interface/spec/lib/go/csi/v0" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "strconv" +) + +const ( + // DefTestVolumeSize defines the base size of dynamically + // provisioned volumes. 10GB by default, can be overridden by + // setting Config.TestVolumeSize. + DefTestVolumeSize int64 = 10 * 1024 * 1024 * 1024 +) + +func TestVolumeSize(sc *SanityContext) int64 { + if sc.Config.TestVolumeSize > 0 { + return sc.Config.TestVolumeSize + } + return DefTestVolumeSize +} + +func verifyVolumeInfo(v *csi.Volume) { + Expect(v).NotTo(BeNil()) + Expect(v.GetId()).NotTo(BeEmpty()) +} + +func verifySnapshotInfo(snapshot *csi.Snapshot) { + Expect(snapshot).NotTo(BeNil()) + Expect(snapshot.GetId()).NotTo(BeEmpty()) + Expect(snapshot.GetSourceVolumeId()).NotTo(BeEmpty()) + Expect(snapshot.GetCreatedAt()).NotTo(BeZero()) +} + +func isControllerCapabilitySupported( + c csi.ControllerClient, + capType csi.ControllerServiceCapability_RPC_Type, +) bool { + + caps, err := c.ControllerGetCapabilities( + context.Background(), + &csi.ControllerGetCapabilitiesRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(caps).NotTo(BeNil()) + Expect(caps.GetCapabilities()).NotTo(BeNil()) + + for _, cap := range caps.GetCapabilities() { + Expect(cap.GetRpc()).NotTo(BeNil()) + if cap.GetRpc().GetType() == capType { + return true + } + } + return false +} + +var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { + var ( + c csi.ControllerClient + n csi.NodeClient + + cl *Cleanup + ) + + BeforeEach(func() { + c = csi.NewControllerClient(sc.Conn) + n = csi.NewNodeClient(sc.Conn) + + cl = &Cleanup{ + NodeClient: n, + ControllerClient: c, + Context: sc, + } + }) + + AfterEach(func() { + cl.DeleteVolumes() + }) + + Describe("ControllerGetCapabilities", func() { + It("should return appropriate capabilities", func() { + caps, err := c.ControllerGetCapabilities( + context.Background(), + &csi.ControllerGetCapabilitiesRequest{}) + + By("checking successful response") + Expect(err).NotTo(HaveOccurred()) + Expect(caps).NotTo(BeNil()) + Expect(caps.GetCapabilities()).NotTo(BeNil()) + + for _, cap := range caps.GetCapabilities() { + Expect(cap.GetRpc()).NotTo(BeNil()) + + switch cap.GetRpc().GetType() { + case csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME: + case csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME: + case csi.ControllerServiceCapability_RPC_LIST_VOLUMES: + case csi.ControllerServiceCapability_RPC_GET_CAPACITY: + case csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT: + case csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS: + default: + Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetRpc().GetType())) + } + } + }) + }) + + Describe("GetCapacity", func() { + BeforeEach(func() { + if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_GET_CAPACITY) { + Skip("GetCapacity not supported") + } + }) + + It("should return capacity (no optional values added)", func() { + _, err := c.GetCapacity( + context.Background(), + &csi.GetCapacityRequest{}) + Expect(err).NotTo(HaveOccurred()) + + // Since capacity is int64 we will not be checking it + // The value of zero is a possible value. + }) + }) + + Describe("ListVolumes", func() { + BeforeEach(func() { + if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_LIST_VOLUMES) { + Skip("ListVolumes not supported") + } + }) + + It("should return appropriate values (no optional values added)", func() { + vols, err := c.ListVolumes( + context.Background(), + &csi.ListVolumesRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(vols).NotTo(BeNil()) + + for _, vol := range vols.GetEntries() { + verifyVolumeInfo(vol.GetVolume()) + } + }) + + // TODO: Add test to test for tokens + + // TODO: Add test which checks list of volume is there when created, + // and not there when deleted. + }) + + Describe("CreateVolume", func() { + BeforeEach(func() { + if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME) { + Skip("CreateVolume not supported") + } + }) + + It("should fail when no name is provided", func() { + vol, err := c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + cl.MaybeRegisterVolume("", vol, err) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should fail when no volume capabilities are provided", func() { + name := uniqueString("sanity-controller-create-no-volume-capabilities") + vol, err := c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + cl.MaybeRegisterVolume(name, vol, err) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should return appropriate values SingleNodeWriter NoCapacity Type:Mount", func() { + + By("creating a volume") + name := uniqueString("sanity-controller-create-single-no-capacity") + + vol, err := c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(vol).NotTo(BeNil()) + Expect(vol.GetVolume()).NotTo(BeNil()) + Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + + By("cleaning up deleting the volume") + + _, err = c.DeleteVolume( + context.Background(), + &csi.DeleteVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + cl.UnregisterVolume(name) + }) + + It("should return appropriate values SingleNodeWriter WithCapacity 1Gi Type:Mount", func() { + + By("creating a volume") + name := uniqueString("sanity-controller-create-single-with-capacity") + + vol, err := c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + CapacityRange: &csi.CapacityRange{ + RequiredBytes: TestVolumeSize(sc), + }, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + if serverError, ok := status.FromError(err); ok && + (serverError.Code() == codes.OutOfRange || serverError.Code() == codes.Unimplemented) { + Skip("Required bytes not supported") + } + Expect(err).NotTo(HaveOccurred()) + Expect(vol).NotTo(BeNil()) + Expect(vol.GetVolume()).NotTo(BeNil()) + Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + Expect(vol.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", TestVolumeSize(sc))) + + By("cleaning up deleting the volume") + + _, err = c.DeleteVolume( + context.Background(), + &csi.DeleteVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + cl.UnregisterVolume(name) + }) + It("should not fail when requesting to create a volume with already exisiting name and same capacity.", func() { + + By("creating a volume") + name := uniqueString("sanity-controller-create-twice") + size := TestVolumeSize(sc) + + vol1, err := c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + CapacityRange: &csi.CapacityRange{ + RequiredBytes: size, + }, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(vol1).NotTo(BeNil()) + Expect(vol1.GetVolume()).NotTo(BeNil()) + Expect(vol1.GetVolume().GetId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetId()}) + Expect(vol1.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", size)) + + vol2, err := c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + CapacityRange: &csi.CapacityRange{ + RequiredBytes: size, + }, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(vol2).NotTo(BeNil()) + Expect(vol2.GetVolume()).NotTo(BeNil()) + Expect(vol2.GetVolume().GetId()).NotTo(BeEmpty()) + Expect(vol2.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", size)) + Expect(vol1.GetVolume().GetId()).To(Equal(vol2.GetVolume().GetId())) + + By("cleaning up deleting the volume") + + _, err = c.DeleteVolume( + context.Background(), + &csi.DeleteVolumeRequest{ + VolumeId: vol1.GetVolume().GetId(), + ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + cl.UnregisterVolume(name) + }) + It("should fail when requesting to create a volume with already exisiting name and different capacity.", func() { + + By("creating a volume") + name := uniqueString("sanity-controller-create-twice-different") + size1 := TestVolumeSize(sc) + + vol1, err := c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + CapacityRange: &csi.CapacityRange{ + RequiredBytes: size1, + LimitBytes: size1, + }, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + Expect(err).ToNot(HaveOccurred()) + Expect(vol1).NotTo(BeNil()) + Expect(vol1.GetVolume()).NotTo(BeNil()) + Expect(vol1.GetVolume().GetId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetId()}) + size2 := 2 * TestVolumeSize(sc) + + _, err = c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + CapacityRange: &csi.CapacityRange{ + RequiredBytes: size2, + LimitBytes: size2, + }, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.AlreadyExists)) + + By("cleaning up deleting the volume") + + _, err = c.DeleteVolume( + context.Background(), + &csi.DeleteVolumeRequest{ + VolumeId: vol1.GetVolume().GetId(), + ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + cl.UnregisterVolume(name) + }) + }) + + Describe("DeleteVolume", func() { + BeforeEach(func() { + if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME) { + Skip("DeleteVolume not supported") + } + }) + + It("should fail when no volume id is provided", func() { + + _, err := c.DeleteVolume( + context.Background(), + &csi.DeleteVolumeRequest{ + ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should succeed when an invalid volume id is used", func() { + + _, err := c.DeleteVolume( + context.Background(), + &csi.DeleteVolumeRequest{ + VolumeId: "reallyfakevolumeid", + ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should return appropriate values (no optional values added)", func() { + + // Create Volume First + By("creating a volume") + name := uniqueString("sanity-controller-create-appropriate") + + vol, err := c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(vol).NotTo(BeNil()) + Expect(vol.GetVolume()).NotTo(BeNil()) + Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + + // Delete Volume + By("deleting a volume") + + _, err = c.DeleteVolume( + context.Background(), + &csi.DeleteVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + cl.UnregisterVolume(name) + }) + }) + + Describe("ValidateVolumeCapabilities", func() { + It("should fail when no volume id is provided", func() { + + _, err := c.ValidateVolumeCapabilities( + context.Background(), + &csi.ValidateVolumeCapabilitiesRequest{}) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should fail when no volume capabilities are provided", func() { + + _, err := c.ValidateVolumeCapabilities( + context.Background(), + &csi.ValidateVolumeCapabilitiesRequest{ + VolumeId: "id", + }) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should return appropriate values (no optional values added)", func() { + + // Create Volume First + By("creating a single node writer volume") + name := uniqueString("sanity-controller-validate") + + vol, err := c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(vol).NotTo(BeNil()) + Expect(vol.GetVolume()).NotTo(BeNil()) + Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + + // ValidateVolumeCapabilities + By("validating volume capabilities") + valivolcap, err := c.ValidateVolumeCapabilities( + context.Background(), + &csi.ValidateVolumeCapabilitiesRequest{ + VolumeId: vol.GetVolume().GetId(), + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + }) + Expect(err).NotTo(HaveOccurred()) + Expect(valivolcap).NotTo(BeNil()) + Expect(valivolcap.GetSupported()).To(BeTrue()) + + By("cleaning up deleting the volume") + + _, err = c.DeleteVolume( + context.Background(), + &csi.DeleteVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + cl.UnregisterVolume(name) + }) + + It("should fail when the requested volume does not exist", func() { + + _, err := c.ValidateVolumeCapabilities( + context.Background(), + &csi.ValidateVolumeCapabilitiesRequest{ + VolumeId: "some-vol-id", + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + }, + ) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.NotFound)) + }) + }) + + Describe("ControllerPublishVolume", func() { + BeforeEach(func() { + if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME) { + Skip("ControllerPublishVolume not supported") + } + }) + + It("should fail when no volume id is provided", func() { + + _, err := c.ControllerPublishVolume( + context.Background(), + &csi.ControllerPublishVolumeRequest{ + ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should fail when no node id is provided", func() { + + _, err := c.ControllerPublishVolume( + context.Background(), + &csi.ControllerPublishVolumeRequest{ + VolumeId: "id", + ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should fail when no volume capability is provided", func() { + + _, err := c.ControllerPublishVolume( + context.Background(), + &csi.ControllerPublishVolumeRequest{ + VolumeId: "id", + NodeId: "fakenode", + ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should return appropriate values (no optional values added)", func() { + + // Create Volume First + By("creating a single node writer volume") + name := uniqueString("sanity-controller-publish") + + vol, err := c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(vol).NotTo(BeNil()) + Expect(vol.GetVolume()).NotTo(BeNil()) + Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + + By("getting a node id") + nid, err := n.NodeGetId( + context.Background(), + &csi.NodeGetIdRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(nid).NotTo(BeNil()) + Expect(nid.GetNodeId()).NotTo(BeEmpty()) + + // ControllerPublishVolume + By("calling controllerpublish on that volume") + + conpubvol, err := c.ControllerPublishVolume( + context.Background(), + &csi.ControllerPublishVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + NodeId: nid.GetNodeId(), + VolumeCapability: &csi.VolumeCapability{ + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + Readonly: false, + ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId(), NodeID: nid.GetNodeId()}) + Expect(conpubvol).NotTo(BeNil()) + + By("cleaning up unpublishing the volume") + + conunpubvol, err := c.ControllerUnpublishVolume( + context.Background(), + &csi.ControllerUnpublishVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + // NodeID is optional in ControllerUnpublishVolume + NodeId: nid.GetNodeId(), + ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(conunpubvol).NotTo(BeNil()) + + By("cleaning up deleting the volume") + + _, err = c.DeleteVolume( + context.Background(), + &csi.DeleteVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + cl.UnregisterVolume(name) + }) + + It("should fail when the volume does not exist", func() { + + By("calling controller publish on a non-existent volume") + + conpubvol, err := c.ControllerPublishVolume( + context.Background(), + &csi.ControllerPublishVolumeRequest{ + VolumeId: "some-vol-id", + NodeId: "some-node-id", + VolumeCapability: &csi.VolumeCapability{ + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + Readonly: false, + ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + Expect(conpubvol).To(BeNil()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.NotFound)) + }) + + It("should fail when the node does not exist", func() { + + // Create Volume First + By("creating a single node writer volume") + name := uniqueString("sanity-controller-wrong-node") + + vol, err := c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(vol).NotTo(BeNil()) + Expect(vol.GetVolume()).NotTo(BeNil()) + Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + + // ControllerPublishVolume + By("calling controllerpublish on that volume") + + conpubvol, err := c.ControllerPublishVolume( + context.Background(), + &csi.ControllerPublishVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + NodeId: "some-fake-node-id", + VolumeCapability: &csi.VolumeCapability{ + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + Readonly: false, + ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + Expect(conpubvol).To(BeNil()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.NotFound)) + + By("cleaning up deleting the volume") + + _, err = c.DeleteVolume( + context.Background(), + &csi.DeleteVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + cl.UnregisterVolume(name) + }) + + It("should fail when the volume is already published but is incompatible", func() { + + // Create Volume First + By("creating a single node writer volume") + name := uniqueString("sanity-controller-published-incompatible") + + vol, err := c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(vol).NotTo(BeNil()) + Expect(vol.GetVolume()).NotTo(BeNil()) + Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + + By("getting a node id") + nid, err := n.NodeGetId( + context.Background(), + &csi.NodeGetIdRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(nid).NotTo(BeNil()) + Expect(nid.GetNodeId()).NotTo(BeEmpty()) + + // ControllerPublishVolume + By("calling controllerpublish on that volume") + + pubReq := &csi.ControllerPublishVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + NodeId: nid.GetNodeId(), + VolumeCapability: &csi.VolumeCapability{ + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + Readonly: false, + ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + } + + conpubvol, err := c.ControllerPublishVolume(context.Background(), pubReq) + Expect(err).NotTo(HaveOccurred()) + Expect(conpubvol).NotTo(BeNil()) + + // Publish again with different attributes. + pubReq.Readonly = true + + conpubvol, err = c.ControllerPublishVolume(context.Background(), pubReq) + Expect(err).To(HaveOccurred()) + Expect(conpubvol).To(BeNil()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.AlreadyExists)) + + By("cleaning up unpublishing the volume") + + conunpubvol, err := c.ControllerUnpublishVolume( + context.Background(), + &csi.ControllerUnpublishVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + // NodeID is optional in ControllerUnpublishVolume + NodeId: nid.GetNodeId(), + ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, + }, + ) + + Expect(err).NotTo(HaveOccurred()) + Expect(conunpubvol).NotTo(BeNil()) + + By("cleaning up deleting the volume") + + _, err = c.DeleteVolume( + context.Background(), + &csi.DeleteVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + cl.UnregisterVolume(name) + }) + }) + + Describe("ControllerUnpublishVolume", func() { + BeforeEach(func() { + if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME) { + Skip("ControllerUnpublishVolume not supported") + } + }) + + It("should fail when no volume id is provided", func() { + + _, err := c.ControllerUnpublishVolume( + context.Background(), + &csi.ControllerUnpublishVolumeRequest{ + ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should return appropriate values (no optional values added)", func() { + + // Create Volume First + By("creating a single node writer volume") + name := uniqueString("sanity-controller-unpublish") + + vol, err := c.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(vol).NotTo(BeNil()) + Expect(vol.GetVolume()).NotTo(BeNil()) + Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + + By("getting a node id") + nid, err := n.NodeGetId( + context.Background(), + &csi.NodeGetIdRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(nid).NotTo(BeNil()) + Expect(nid.GetNodeId()).NotTo(BeEmpty()) + + // ControllerPublishVolume + By("calling controllerpublish on that volume") + + conpubvol, err := c.ControllerPublishVolume( + context.Background(), + &csi.ControllerPublishVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + NodeId: nid.GetNodeId(), + VolumeCapability: &csi.VolumeCapability{ + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + Readonly: false, + ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId(), NodeID: nid.GetNodeId()}) + Expect(conpubvol).NotTo(BeNil()) + + // ControllerUnpublishVolume + By("calling controllerunpublish on that volume") + + conunpubvol, err := c.ControllerUnpublishVolume( + context.Background(), + &csi.ControllerUnpublishVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + // NodeID is optional in ControllerUnpublishVolume + NodeId: nid.GetNodeId(), + ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(conunpubvol).NotTo(BeNil()) + + By("cleaning up deleting the volume") + + _, err = c.DeleteVolume( + context.Background(), + &csi.DeleteVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + cl.UnregisterVolume(name) + }) + }) +}) + +var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityContext) { + var ( + c csi.ControllerClient + ) + + BeforeEach(func() { + c = csi.NewControllerClient(sc.Conn) + + if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS) { + Skip("ListSnapshots not supported") + } + }) + + It("should return appropriate values (no optional values added)", func() { + snapshots, err := c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshots).NotTo(BeNil()) + + for _, snapshot := range snapshots.GetEntries() { + verifySnapshotInfo(snapshot.GetSnapshot()) + } + }) + + It("should return snapshots that match the specify snapshot id", func() { + + By("creating a volume") + volReq := MakeCreateVolumeReq(sc, "listSnapshots-volume-1") + volume, err := c.CreateVolume(context.Background(), volReq) + Expect(err).NotTo(HaveOccurred()) + + By("creating a snapshot") + snapshotReq := MakeCreateSnapshotReq(sc, "listSnapshots-snapshot-1", volume.GetVolume().GetId(), nil) + snapshot, err := c.CreateSnapshot(context.Background(), snapshotReq) + Expect(err).NotTo(HaveOccurred()) + + snapshots, err := c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{SnapshotId: snapshot.GetSnapshot().GetId()}) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshots).NotTo(BeNil()) + Expect(len(snapshots.GetEntries())).To(BeNumerically("==", 1)) + verifySnapshotInfo(snapshots.GetEntries()[0].GetSnapshot()) + Expect(snapshots.GetEntries()[0].GetSnapshot().GetId()).To(Equal(snapshot.GetSnapshot().GetId())) + + By("cleaning up deleting the volume") + delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetId()) + _, err = c.DeleteVolume(context.Background(), delVolReq) + Expect(err).NotTo(HaveOccurred()) + + By("cleaning up deleting the snapshot") + delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetId()) + _, err = c.DeleteSnapshot(context.Background(), delSnapReq) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should return empty when the specify snapshot id is not exist", func() { + + snapshots, err := c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{SnapshotId: "none-exist-id"}) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshots).NotTo(BeNil()) + Expect(snapshots.GetEntries()).To(BeEmpty()) + }) + + It("should return snapshots that match the specify source volume id)", func() { + + By("creating a volume") + volReq := MakeCreateVolumeReq(sc, "listSnapshots-volume-2") + volume, err := c.CreateVolume(context.Background(), volReq) + Expect(err).NotTo(HaveOccurred()) + + By("creating a snapshot") + snapshotReq := MakeCreateSnapshotReq(sc, "listSnapshots-snapshot-2", volume.GetVolume().GetId(), nil) + snapshot, err := c.CreateSnapshot(context.Background(), snapshotReq) + Expect(err).NotTo(HaveOccurred()) + + snapshots, err := c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{SourceVolumeId: snapshot.GetSnapshot().GetSourceVolumeId()}) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshots).NotTo(BeNil()) + for _, snap := range snapshots.GetEntries() { + verifySnapshotInfo(snap.GetSnapshot()) + Expect(snap.GetSnapshot().GetSourceVolumeId()).To(Equal(snapshot.GetSnapshot().GetSourceVolumeId())) + } + + By("cleaning up deleting the snapshot") + delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetId()) + _, err = c.DeleteSnapshot(context.Background(), delSnapReq) + Expect(err).NotTo(HaveOccurred()) + + By("cleaning up deleting the volume") + delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetId()) + _, err = c.DeleteVolume(context.Background(), delVolReq) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should return empty when the specify source volume id is not exist", func() { + + snapshots, err := c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{SourceVolumeId: "none-exist-volume-id"}) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshots).NotTo(BeNil()) + Expect(snapshots.GetEntries()).To(BeEmpty()) + }) + + It("should fail when an invalid starting_token is passed", func() { + vols, err := c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{ + StartingToken: "invalid-token", + }, + ) + Expect(err).To(HaveOccurred()) + Expect(vols).To(BeNil()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.Aborted)) + }) + + It("should fail when the starting_token is greater than total number of snapshots", func() { + // Get total number of snapshots. + snapshots, err := c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshots).NotTo(BeNil()) + + totalSnapshots := len(snapshots.GetEntries()) + + // Send starting_token that is greater than the total number of snapshots. + snapshots, err = c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{ + StartingToken: strconv.Itoa(totalSnapshots + 5), + }, + ) + Expect(err).To(HaveOccurred()) + Expect(snapshots).To(BeNil()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.Aborted)) + }) + + It("check the presence of new snapshots in the snapshot list", func() { + // List Snapshots before creating new snapshots. + snapshots, err := c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshots).NotTo(BeNil()) + + totalSnapshots := len(snapshots.GetEntries()) + + By("creating a volume") + volReq := MakeCreateVolumeReq(sc, "listSnapshots-volume-3") + volume, err := c.CreateVolume(context.Background(), volReq) + Expect(err).NotTo(HaveOccurred()) + + By("creating a snapshot") + snapReq := MakeCreateSnapshotReq(sc, "listSnapshots-snapshot-3", volume.GetVolume().GetId(), nil) + snapshot, err := c.CreateSnapshot(context.Background(), snapReq) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshot).NotTo(BeNil()) + verifySnapshotInfo(snapshot.GetSnapshot()) + + snapshots, err = c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshots).NotTo(BeNil()) + Expect(len(snapshots.GetEntries())).To(Equal(totalSnapshots + 1)) + + By("cleaning up deleting the snapshot") + delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetId()) + _, err = c.DeleteSnapshot(context.Background(), delSnapReq) + Expect(err).NotTo(HaveOccurred()) + + By("cleaning up deleting the volume") + delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetId()) + _, err = c.DeleteVolume(context.Background(), delVolReq) + Expect(err).NotTo(HaveOccurred()) + + // List snapshots and check if the deleted snapshot exists in the snapshot list. + snapshots, err = c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshots).NotTo(BeNil()) + Expect(len(snapshots.GetEntries())).To(Equal(totalSnapshots)) + }) + + It("should return next token when a limited number of entries are requested", func() { + // minSnapshotCount is the minimum number of snapshots expected to exist, + // based on which paginated snapshot listing is performed. + minSnapshotCount := 5 + // maxEntried is the maximum entries in list snapshot request. + maxEntries := 2 + // currentTotalVols is the total number of volumes at a given time. It + // is used to verify that all the snapshots have been listed. + currentTotalSnapshots := 0 + + // Get the number of existing volumes. + snapshots, err := c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshots).NotTo(BeNil()) + + initialTotalSnapshots := len(snapshots.GetEntries()) + currentTotalSnapshots = initialTotalSnapshots + + createVols := make([]*csi.Volume, 0) + createSnapshots := make([]*csi.Snapshot, 0) + + // Ensure minimum minVolCount volumes exist. + if initialTotalSnapshots < minSnapshotCount { + + By("creating required new volumes") + requiredSnapshots := minSnapshotCount - initialTotalSnapshots + + for i := 1; i <= requiredSnapshots; i++ { + volReq := MakeCreateVolumeReq(sc, "volume"+strconv.Itoa(i)) + volume, err := c.CreateVolume(context.Background(), volReq) + Expect(err).NotTo(HaveOccurred()) + Expect(volume).NotTo(BeNil()) + createVols = append(createVols, volume.GetVolume()) + + snapReq := MakeCreateSnapshotReq(sc, "snapshot"+strconv.Itoa(i), volume.GetVolume().GetId(), nil) + snapshot, err := c.CreateSnapshot(context.Background(), snapReq) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshot).NotTo(BeNil()) + verifySnapshotInfo(snapshot.GetSnapshot()) + createSnapshots = append(createSnapshots, snapshot.GetSnapshot()) + } + + // Update the current total snapshots count. + currentTotalSnapshots += requiredSnapshots + } + + // Request list snapshots with max entries maxEntries. + snapshots, err = c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{ + MaxEntries: int32(maxEntries), + }) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshots).NotTo(BeNil()) + + nextToken := snapshots.GetNextToken() + + Expect(nextToken).To(Equal(strconv.Itoa(maxEntries))) + Expect(len(snapshots.GetEntries())).To(Equal(maxEntries)) + + // Request list snapshots with starting_token and no max entries. + snapshots, err = c.ListSnapshots( + context.Background(), + &csi.ListSnapshotsRequest{ + StartingToken: nextToken, + }) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshots).NotTo(BeNil()) + + // Ensure that all the remaining entries are returned at once. + Expect(len(snapshots.GetEntries())).To(Equal(currentTotalSnapshots - maxEntries)) + + if initialTotalSnapshots < minSnapshotCount { + + By("cleaning up deleting the snapshots") + + for _, snap := range createSnapshots { + delSnapReq := MakeDeleteSnapshotReq(sc, snap.GetId()) + _, err = c.DeleteSnapshot(context.Background(), delSnapReq) + Expect(err).NotTo(HaveOccurred()) + } + + By("cleaning up deleting the volumes") + + for _, vol := range createVols { + delVolReq := MakeDeleteVolumeReq(sc, vol.GetId()) + _, err = c.DeleteVolume(context.Background(), delVolReq) + Expect(err).NotTo(HaveOccurred()) + } + } + }) + +}) + +var _ = DescribeSanity("DeleteSnapshot [Controller Server]", func(sc *SanityContext) { + var ( + c csi.ControllerClient + ) + + BeforeEach(func() { + c = csi.NewControllerClient(sc.Conn) + + if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT) { + Skip("DeleteSnapshot not supported") + } + }) + + It("should fail when no snapshot id is provided", func() { + + req := &csi.DeleteSnapshotRequest{} + + if sc.Secrets != nil { + req.DeleteSnapshotSecrets = sc.Secrets.DeleteSnapshotSecret + } + + _, err := c.DeleteSnapshot(context.Background(), req) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should succeed when an invalid snapshot id is used", func() { + + req := MakeDeleteSnapshotReq(sc, "reallyfakesnapshotid") + _, err := c.DeleteSnapshot(context.Background(), req) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should return appropriate values (no optional values added)", func() { + + By("creating a volume") + volReq := MakeCreateVolumeReq(sc, "DeleteSnapshot-volume-1") + volume, err := c.CreateVolume(context.Background(), volReq) + Expect(err).NotTo(HaveOccurred()) + + // Create Snapshot First + By("creating a snapshot") + snapshotReq := MakeCreateSnapshotReq(sc, "DeleteSnapshot-snapshot-1", volume.GetVolume().GetId(), nil) + snapshot, err := c.CreateSnapshot(context.Background(), snapshotReq) + Expect(err).NotTo(HaveOccurred()) + Expect(snapshot).NotTo(BeNil()) + verifySnapshotInfo(snapshot.GetSnapshot()) + + By("cleaning up deleting the snapshot") + delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetId()) + _, err = c.DeleteSnapshot(context.Background(), delSnapReq) + Expect(err).NotTo(HaveOccurred()) + + By("cleaning up deleting the volume") + delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetId()) + _, err = c.DeleteVolume(context.Background(), delVolReq) + Expect(err).NotTo(HaveOccurred()) + }) +}) + +var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityContext) { + var ( + c csi.ControllerClient + ) + + BeforeEach(func() { + c = csi.NewControllerClient(sc.Conn) + + if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT) { + Skip("CreateSnapshot not supported") + } + }) + + It("should fail when no name is provided", func() { + + req := &csi.CreateSnapshotRequest{ + SourceVolumeId: "testId", + } + + if sc.Secrets != nil { + req.CreateSnapshotSecrets = sc.Secrets.CreateSnapshotSecret + } + + _, err := c.CreateSnapshot(context.Background(), req) + Expect(err).To(HaveOccurred()) + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should fail when no source volume id is provided", func() { + + req := &csi.CreateSnapshotRequest{ + Name: "name", + } + + if sc.Secrets != nil { + req.CreateSnapshotSecrets = sc.Secrets.CreateSnapshotSecret + } + + _, err := c.CreateSnapshot(context.Background(), req) + Expect(err).To(HaveOccurred()) + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should not fail when requesting to create a snapshot with already existing name and same SourceVolumeId.", func() { + + By("creating a volume") + volReq := MakeCreateVolumeReq(sc, "CreateSnapshot-volume-1") + volume, err := c.CreateVolume(context.Background(), volReq) + Expect(err).NotTo(HaveOccurred()) + + By("creating a snapshot") + snapReq1 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-1", volume.GetVolume().GetId(), nil) + snap1, err := c.CreateSnapshot(context.Background(), snapReq1) + Expect(err).NotTo(HaveOccurred()) + Expect(snap1).NotTo(BeNil()) + verifySnapshotInfo(snap1.GetSnapshot()) + + snap2, err := c.CreateSnapshot(context.Background(), snapReq1) + Expect(err).NotTo(HaveOccurred()) + Expect(snap2).NotTo(BeNil()) + verifySnapshotInfo(snap2.GetSnapshot()) + + By("cleaning up deleting the snapshot") + delSnapReq := MakeDeleteSnapshotReq(sc, snap1.GetSnapshot().GetId()) + _, err = c.DeleteSnapshot(context.Background(), delSnapReq) + Expect(err).NotTo(HaveOccurred()) + + By("cleaning up deleting the volume") + delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetId()) + _, err = c.DeleteVolume(context.Background(), delVolReq) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should fail when requesting to create a snapshot with already existing name and different SourceVolumeId.", func() { + + By("creating a volume") + volume, err := c.CreateVolume(context.Background(), MakeCreateVolumeReq(sc, "CreateSnapshot-volume-2")) + Expect(err).ToNot(HaveOccurred()) + + By("creating a snapshot with the created volume source id") + req1 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-2", volume.GetVolume().GetId(), nil) + snap1, err := c.CreateSnapshot(context.Background(), req1) + Expect(err).NotTo(HaveOccurred()) + Expect(snap1).NotTo(BeNil()) + verifySnapshotInfo(snap1.GetSnapshot()) + + By("creating a snapshot with the same name but different volume source id") + req2 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-2", "test001", nil) + _, err = c.CreateSnapshot(context.Background(), req2) + Expect(err).To(HaveOccurred()) + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.AlreadyExists)) + + By("cleaning up deleting the snapshot") + delSnapReq := MakeDeleteSnapshotReq(sc, snap1.GetSnapshot().GetId()) + _, err = c.DeleteSnapshot(context.Background(), delSnapReq) + Expect(err).NotTo(HaveOccurred()) + + By("cleaning up deleting the volume") + delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetId()) + _, err = c.DeleteVolume(context.Background(), delVolReq) + Expect(err).NotTo(HaveOccurred()) + }) +}) + +func MakeCreateVolumeReq(sc *SanityContext, name string) *csi.CreateVolumeRequest { + size1 := TestVolumeSize(sc) + + req := &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + CapacityRange: &csi.CapacityRange{ + RequiredBytes: size1, + LimitBytes: size1, + }, + } + + if sc.Secrets != nil { + req.ControllerCreateSecrets = sc.Secrets.CreateVolumeSecret + } + + return req +} + +func MakeCreateSnapshotReq(sc *SanityContext, name, sourceVolumeId string, parameters map[string]string) *csi.CreateSnapshotRequest { + req := &csi.CreateSnapshotRequest{ + Name: name, + SourceVolumeId: sourceVolumeId, + Parameters: parameters, + } + + if sc.Secrets != nil { + req.CreateSnapshotSecrets = sc.Secrets.CreateSnapshotSecret + } + + return req +} + +func MakeDeleteSnapshotReq(sc *SanityContext, id string) *csi.DeleteSnapshotRequest { + delSnapReq := &csi.DeleteSnapshotRequest{ + SnapshotId: id, + } + + if sc.Secrets != nil { + delSnapReq.DeleteSnapshotSecrets = sc.Secrets.DeleteSnapshotSecret + } + + return delSnapReq +} + +func MakeDeleteVolumeReq(sc *SanityContext, id string) *csi.DeleteVolumeRequest { + delVolReq := &csi.DeleteVolumeRequest{ + VolumeId: id, + } + + if sc.Secrets != nil { + delVolReq.ControllerDeleteSecrets = sc.Secrets.DeleteVolumeSecret + } + + return delVolReq +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/identity.go b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/identity.go new file mode 100644 index 00000000..e60439b3 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/identity.go @@ -0,0 +1,99 @@ +/* +Copyright 2017 Luis Pabón luis@portworx.com + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sanity + +import ( + "context" + "fmt" + "regexp" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/container-storage-interface/spec/lib/go/csi/v0" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = DescribeSanity("Identity Service", func(sc *SanityContext) { + var ( + c csi.IdentityClient + ) + + BeforeEach(func() { + c = csi.NewIdentityClient(sc.Conn) + }) + + Describe("GetPluginCapabilities", func() { + It("should return appropriate capabilities", func() { + req := &csi.GetPluginCapabilitiesRequest{} + res, err := c.GetPluginCapabilities(context.Background(), req) + Expect(err).NotTo(HaveOccurred()) + Expect(res).NotTo(BeNil()) + + By("checking successful response") + Expect(res.GetCapabilities()).NotTo(BeNil()) + for _, cap := range res.GetCapabilities() { + switch cap.GetService().GetType() { + case csi.PluginCapability_Service_CONTROLLER_SERVICE: + case csi.PluginCapability_Service_ACCESSIBILITY_CONSTRAINTS: + default: + Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetService().GetType())) + } + } + + }) + + }) + + Describe("Probe", func() { + It("should return appropriate information", func() { + req := &csi.ProbeRequest{} + res, err := c.Probe(context.Background(), req) + Expect(err).NotTo(HaveOccurred()) + Expect(res).NotTo(BeNil()) + + By("verifying return status") + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code() == codes.FailedPrecondition || + serverError.Code() == codes.OK).To(BeTrue()) + + if res.GetReady() != nil { + Expect(res.GetReady().GetValue() == true || + res.GetReady().GetValue() == false).To(BeTrue()) + } + }) + }) + + Describe("GetPluginInfo", func() { + It("should return appropriate information", func() { + req := &csi.GetPluginInfoRequest{} + res, err := c.GetPluginInfo(context.Background(), req) + Expect(err).NotTo(HaveOccurred()) + Expect(res).NotTo(BeNil()) + + By("verifying name size and characters") + Expect(res.GetName()).ToNot(HaveLen(0)) + Expect(len(res.GetName())).To(BeNumerically("<=", 63)) + Expect(regexp. + MustCompile("^[a-zA-Z][A-Za-z0-9-\\.\\_]{0,61}[a-zA-Z]$"). + MatchString(res.GetName())).To(BeTrue()) + }) + }) +}) diff --git a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/node.go b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/node.go new file mode 100644 index 00000000..a98f5151 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/node.go @@ -0,0 +1,528 @@ +/* +Copyright 2017 Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sanity + +import ( + "context" + "fmt" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/container-storage-interface/spec/lib/go/csi/v0" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func isNodeCapabilitySupported(c csi.NodeClient, + capType csi.NodeServiceCapability_RPC_Type, +) bool { + + caps, err := c.NodeGetCapabilities( + context.Background(), + &csi.NodeGetCapabilitiesRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(caps).NotTo(BeNil()) + + for _, cap := range caps.GetCapabilities() { + Expect(cap.GetRpc()).NotTo(BeNil()) + if cap.GetRpc().GetType() == capType { + return true + } + } + return false +} + +func isPluginCapabilitySupported(c csi.IdentityClient, + capType csi.PluginCapability_Service_Type, +) bool { + + caps, err := c.GetPluginCapabilities( + context.Background(), + &csi.GetPluginCapabilitiesRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(caps).NotTo(BeNil()) + Expect(caps.GetCapabilities()).NotTo(BeNil()) + + for _, cap := range caps.GetCapabilities() { + Expect(cap.GetService()).NotTo(BeNil()) + if cap.GetService().GetType() == capType { + return true + } + } + return false +} + +var _ = DescribeSanity("Node Service", func(sc *SanityContext) { + var ( + cl *Cleanup + c csi.NodeClient + s csi.ControllerClient + + controllerPublishSupported bool + nodeStageSupported bool + ) + + BeforeEach(func() { + c = csi.NewNodeClient(sc.Conn) + s = csi.NewControllerClient(sc.Conn) + + controllerPublishSupported = isControllerCapabilitySupported( + s, + csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME) + nodeStageSupported = isNodeCapabilitySupported(c, csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME) + if nodeStageSupported { + err := createMountTargetLocation(sc.Config.StagingPath) + Expect(err).NotTo(HaveOccurred()) + } + cl = &Cleanup{ + Context: sc, + NodeClient: c, + ControllerClient: s, + ControllerPublishSupported: controllerPublishSupported, + NodeStageSupported: nodeStageSupported, + } + }) + + AfterEach(func() { + cl.DeleteVolumes() + }) + + Describe("NodeGetCapabilities", func() { + It("should return appropriate capabilities", func() { + caps, err := c.NodeGetCapabilities( + context.Background(), + &csi.NodeGetCapabilitiesRequest{}) + + By("checking successful response") + Expect(err).NotTo(HaveOccurred()) + Expect(caps).NotTo(BeNil()) + + for _, cap := range caps.GetCapabilities() { + Expect(cap.GetRpc()).NotTo(BeNil()) + + switch cap.GetRpc().GetType() { + case csi.NodeServiceCapability_RPC_UNKNOWN: + case csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME: + default: + Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetRpc().GetType())) + } + } + }) + }) + + Describe("NodeGetId", func() { + It("should return appropriate values", func() { + nid, err := c.NodeGetId( + context.Background(), + &csi.NodeGetIdRequest{}) + + Expect(err).NotTo(HaveOccurred()) + Expect(nid).NotTo(BeNil()) + Expect(nid.GetNodeId()).NotTo(BeEmpty()) + }) + }) + + Describe("NodeGetInfo", func() { + var ( + i csi.IdentityClient + accessibilityConstraintSupported bool + ) + + BeforeEach(func() { + i = csi.NewIdentityClient(sc.Conn) + accessibilityConstraintSupported = isPluginCapabilitySupported(i, csi.PluginCapability_Service_ACCESSIBILITY_CONSTRAINTS) + }) + + It("should return approproate values", func() { + ninfo, err := c.NodeGetInfo( + context.Background(), + &csi.NodeGetInfoRequest{}) + + Expect(err).NotTo(HaveOccurred()) + Expect(ninfo).NotTo(BeNil()) + Expect(ninfo.GetNodeId()).NotTo(BeEmpty()) + Expect(ninfo.GetMaxVolumesPerNode()).NotTo(BeNumerically("<", 0)) + + if accessibilityConstraintSupported { + Expect(ninfo.GetAccessibleTopology()).NotTo(BeNil()) + } + }) + }) + + Describe("NodePublishVolume", func() { + It("should fail when no volume id is provided", func() { + _, err := c.NodePublishVolume( + context.Background(), + &csi.NodePublishVolumeRequest{ + NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should fail when no target path is provided", func() { + _, err := c.NodePublishVolume( + context.Background(), + &csi.NodePublishVolumeRequest{ + VolumeId: "id", + NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should fail when no volume capability is provided", func() { + _, err := c.NodePublishVolume( + context.Background(), + &csi.NodePublishVolumeRequest{ + VolumeId: "id", + TargetPath: sc.Config.TargetPath, + NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + }) + + Describe("NodeUnpublishVolume", func() { + It("should fail when no volume id is provided", func() { + + _, err := c.NodeUnpublishVolume( + context.Background(), + &csi.NodeUnpublishVolumeRequest{}) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should fail when no target path is provided", func() { + + _, err := c.NodeUnpublishVolume( + context.Background(), + &csi.NodeUnpublishVolumeRequest{ + VolumeId: "id", + }) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + }) + + Describe("NodeStageVolume", func() { + var ( + device string + ) + + BeforeEach(func() { + if !nodeStageSupported { + Skip("NodeStageVolume not supported") + } + + device = "/dev/mock" + }) + + It("should fail when no volume id is provided", func() { + _, err := c.NodeStageVolume( + context.Background(), + &csi.NodeStageVolumeRequest{ + StagingTargetPath: sc.Config.StagingPath, + VolumeCapability: &csi.VolumeCapability{ + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + PublishInfo: map[string]string{ + "device": device, + }, + NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should fail when no staging target path is provided", func() { + _, err := c.NodeStageVolume( + context.Background(), + &csi.NodeStageVolumeRequest{ + VolumeId: "id", + VolumeCapability: &csi.VolumeCapability{ + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + PublishInfo: map[string]string{ + "device": device, + }, + NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should fail when no volume capability is provided", func() { + _, err := c.NodeStageVolume( + context.Background(), + &csi.NodeStageVolumeRequest{ + VolumeId: "id", + StagingTargetPath: sc.Config.StagingPath, + PublishInfo: map[string]string{ + "device": device, + }, + NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret, + }, + ) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + }) + + Describe("NodeUnstageVolume", func() { + BeforeEach(func() { + if !nodeStageSupported { + Skip("NodeUnstageVolume not supported") + } + }) + + It("should fail when no volume id is provided", func() { + + _, err := c.NodeUnstageVolume( + context.Background(), + &csi.NodeUnstageVolumeRequest{ + StagingTargetPath: sc.Config.StagingPath, + }) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + + It("should fail when no staging target path is provided", func() { + + _, err := c.NodeUnstageVolume( + context.Background(), + &csi.NodeUnstageVolumeRequest{ + VolumeId: "id", + }) + Expect(err).To(HaveOccurred()) + + serverError, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(serverError.Code()).To(Equal(codes.InvalidArgument)) + }) + }) + + It("should work", func() { + name := uniqueString("sanity-node-full") + + // Create Volume First + By("creating a single node writer volume") + vol, err := s.CreateVolume( + context.Background(), + &csi.CreateVolumeRequest{ + Name: name, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + }, + ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(vol).NotTo(BeNil()) + Expect(vol.GetVolume()).NotTo(BeNil()) + Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + + By("getting a node id") + nid, err := c.NodeGetId( + context.Background(), + &csi.NodeGetIdRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(nid).NotTo(BeNil()) + Expect(nid.GetNodeId()).NotTo(BeEmpty()) + + var conpubvol *csi.ControllerPublishVolumeResponse + if controllerPublishSupported { + By("controller publishing volume") + + conpubvol, err = s.ControllerPublishVolume( + context.Background(), + &csi.ControllerPublishVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + NodeId: nid.GetNodeId(), + VolumeCapability: &csi.VolumeCapability{ + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + VolumeAttributes: vol.GetVolume().GetAttributes(), + Readonly: false, + ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId(), NodeID: nid.GetNodeId()}) + Expect(conpubvol).NotTo(BeNil()) + } + // NodeStageVolume + if nodeStageSupported { + By("node staging volume") + nodestagevol, err := c.NodeStageVolume( + context.Background(), + &csi.NodeStageVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + VolumeCapability: &csi.VolumeCapability{ + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + StagingTargetPath: sc.Config.StagingPath, + VolumeAttributes: vol.GetVolume().GetAttributes(), + PublishInfo: conpubvol.GetPublishInfo(), + NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(nodestagevol).NotTo(BeNil()) + } + // NodePublishVolume + By("publishing the volume on a node") + var stagingPath string + if nodeStageSupported { + stagingPath = sc.Config.StagingPath + } + nodepubvol, err := c.NodePublishVolume( + context.Background(), + &csi.NodePublishVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + TargetPath: sc.Config.TargetPath, + StagingTargetPath: stagingPath, + VolumeCapability: &csi.VolumeCapability{ + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, + }, + }, + VolumeAttributes: vol.GetVolume().GetAttributes(), + PublishInfo: conpubvol.GetPublishInfo(), + NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(nodepubvol).NotTo(BeNil()) + + // NodeUnpublishVolume + By("cleaning up calling nodeunpublish") + nodeunpubvol, err := c.NodeUnpublishVolume( + context.Background(), + &csi.NodeUnpublishVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + TargetPath: sc.Config.TargetPath, + }) + Expect(err).NotTo(HaveOccurred()) + Expect(nodeunpubvol).NotTo(BeNil()) + + if nodeStageSupported { + By("cleaning up calling nodeunstage") + nodeunstagevol, err := c.NodeUnstageVolume( + context.Background(), + &csi.NodeUnstageVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + StagingTargetPath: sc.Config.StagingPath, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(nodeunstagevol).NotTo(BeNil()) + } + + if controllerPublishSupported { + By("cleaning up calling controllerunpublishing") + + controllerunpubvol, err := s.ControllerUnpublishVolume( + context.Background(), + &csi.ControllerUnpublishVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + NodeId: nid.GetNodeId(), + ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + Expect(controllerunpubvol).NotTo(BeNil()) + } + + By("cleaning up deleting the volume") + + _, err = s.DeleteVolume( + context.Background(), + &csi.DeleteVolumeRequest{ + VolumeId: vol.GetVolume().GetId(), + ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + }, + ) + Expect(err).NotTo(HaveOccurred()) + }) +}) diff --git a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/sanity.go b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/sanity.go new file mode 100644 index 00000000..9a4de8be --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/sanity.go @@ -0,0 +1,163 @@ +/* +Copyright 2017 Luis Pabón luis@portworx.com + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sanity + +import ( + "crypto/rand" + "fmt" + "io/ioutil" + "os" + "testing" + + "github.com/kubernetes-csi/csi-test/utils" + yaml "gopkg.in/yaml.v2" + + "google.golang.org/grpc" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +// CSISecrets consists of secrets used in CSI credentials. +type CSISecrets struct { + CreateVolumeSecret map[string]string `yaml:"CreateVolumeSecret"` + DeleteVolumeSecret map[string]string `yaml:"DeleteVolumeSecret"` + ControllerPublishVolumeSecret map[string]string `yaml:"ControllerPublishVolumeSecret"` + ControllerUnpublishVolumeSecret map[string]string `yaml:"ControllerUnpublishVolumeSecret"` + NodeStageVolumeSecret map[string]string `yaml:"NodeStageVolumeSecret"` + NodePublishVolumeSecret map[string]string `yaml:"NodePublishVolumeSecret"` + CreateSnapshotSecret map[string]string `yaml:"CreateSnapshotSecret"` + DeleteSnapshotSecret map[string]string `yaml:"DeleteSnapshotSecret"` +} + +// Config provides the configuration for the sanity tests. It +// needs to be initialized by the user of the sanity package. +type Config struct { + TargetPath string + StagingPath string + Address string + SecretsFile string + TestVolumeSize int64 +} + +// SanityContext holds the variables that each test can depend on. It +// gets initialized before each test block runs. +type SanityContext struct { + Config *Config + Conn *grpc.ClientConn + Secrets *CSISecrets +} + +// Test will test the CSI driver at the specified address by +// setting up a Ginkgo suite and running it. +func Test(t *testing.T, reqConfig *Config) { + sc := &SanityContext{ + Config: reqConfig, + } + + registerTestsInGinkgo(sc) + RegisterFailHandler(Fail) + RunSpecs(t, "CSI Driver Test Suite") +} + +func GinkgoTest(reqConfig *Config) { + sc := &SanityContext{ + Config: reqConfig, + } + + registerTestsInGinkgo(sc) +} + +func (sc *SanityContext) setup() { + var err error + + if len(sc.Config.SecretsFile) > 0 { + sc.Secrets, err = loadSecrets(sc.Config.SecretsFile) + Expect(err).NotTo(HaveOccurred()) + } else { + sc.Secrets = &CSISecrets{} + } + + By("connecting to CSI driver") + sc.Conn, err = utils.Connect(sc.Config.Address) + Expect(err).NotTo(HaveOccurred()) + + By("creating mount and staging directories") + err = createMountTargetLocation(sc.Config.TargetPath) + Expect(err).NotTo(HaveOccurred()) + if len(sc.Config.StagingPath) > 0 { + err = createMountTargetLocation(sc.Config.StagingPath) + Expect(err).NotTo(HaveOccurred()) + } +} + +func (sc *SanityContext) teardown() { + if sc.Conn != nil { + sc.Conn.Close() + sc.Conn = nil + } +} + +func createMountTargetLocation(targetPath string) error { + fileInfo, err := os.Stat(targetPath) + if err != nil && os.IsNotExist(err) { + return os.MkdirAll(targetPath, 0755) + } else if err != nil { + return err + } + if !fileInfo.IsDir() { + return fmt.Errorf("Target location %s is not a directory", targetPath) + } + + return nil +} + +func loadSecrets(path string) (*CSISecrets, error) { + var creds CSISecrets + + yamlFile, err := ioutil.ReadFile(path) + if err != nil { + return &creds, fmt.Errorf("failed to read file %q: #%v", path, err) + } + + err = yaml.Unmarshal(yamlFile, &creds) + if err != nil { + return &creds, fmt.Errorf("error unmarshaling yaml: #%v", err) + } + + return &creds, nil +} + +var uniqueSuffix = "-" + pseudoUUID() + +// pseudoUUID returns a unique string generated from random +// bytes, empty string in case of error. +func pseudoUUID() string { + b := make([]byte, 8) + if _, err := rand.Read(b); err != nil { + // Shouldn't happen?! + return "" + } + return fmt.Sprintf("%08X-%08X", b[0:4], b[4:8]) +} + +// uniqueString returns a unique string by appending a random +// number. In case of an error, just the prefix is returned, so it +// alone should already be fairly unique. +func uniqueString(prefix string) string { + return prefix + uniqueSuffix +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/tests.go b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/tests.go new file mode 100644 index 00000000..47763b75 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/tests.go @@ -0,0 +1,56 @@ +/* +Copyright 2018 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sanity + +import ( + . "github.com/onsi/ginkgo" +) + +type test struct { + text string + body func(*SanityContext) +} + +var tests []test + +// DescribeSanity must be used instead of the usual Ginkgo Describe to +// register a test block. The difference is that the body function +// will be called multiple times with the right context (when +// setting up a Ginkgo suite or a testing.T test, with the right +// configuration). +func DescribeSanity(text string, body func(*SanityContext)) bool { + tests = append(tests, test{text, body}) + return true +} + +// registerTestsInGinkgo invokes the actual Gingko Describe +// for the tests registered earlier with DescribeSanity. +func registerTestsInGinkgo(sc *SanityContext) { + for _, test := range tests { + Describe(test.text, func() { + BeforeEach(func() { + sc.setup() + }) + + test.body(sc) + + AfterEach(func() { + sc.teardown() + }) + }) + } +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/test/co_test.go b/vendor/github.com/kubernetes-csi/csi-test/test/co_test.go new file mode 100644 index 00000000..5a2bbe27 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/test/co_test.go @@ -0,0 +1,188 @@ +/* +Copyright 2017 Luis Pabón luis@portworx.com + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package test + +import ( + "context" + "fmt" + "reflect" + "testing" + + "github.com/container-storage-interface/spec/lib/go/csi/v0" + "github.com/golang/mock/gomock" + "github.com/golang/protobuf/proto" + mock_driver "github.com/kubernetes-csi/csi-test/driver" + mock_utils "github.com/kubernetes-csi/csi-test/utils" +) + +func TestPluginInfoResponse(t *testing.T) { + + // Setup mock + m := gomock.NewController(t) + defer m.Finish() + driver := mock_driver.NewMockIdentityServer(m) + + // Setup input + in := &csi.GetPluginInfoRequest{} + + // Setup mock outout + out := &csi.GetPluginInfoResponse{ + Name: "mock", + VendorVersion: "0.1.1", + Manifest: map[string]string{ + "hello": "world", + }, + } + + // Setup expectation + driver.EXPECT().GetPluginInfo(nil, in).Return(out, nil).Times(1) + + // Actual call + r, err := driver.GetPluginInfo(nil, in) + name := r.GetName() + if err != nil { + t.Errorf("Error: %s", err.Error()) + } + if name != "mock" { + t.Errorf("Unknown name: %s\n", name) + } +} + +type pbMatcher struct { + x proto.Message +} + +func (p pbMatcher) Matches(x interface{}) bool { + y := x.(proto.Message) + return proto.Equal(p.x, y) +} + +func (p pbMatcher) String() string { + return fmt.Sprintf("pb equal to %v", p.x) +} + +func pbMatch(x interface{}) gomock.Matcher { + v := x.(proto.Message) + return &pbMatcher{v} +} + +func TestGRPCGetPluginInfoReponse(t *testing.T) { + + // Setup mock + m := gomock.NewController(&mock_utils.SafeGoroutineTester{}) + defer m.Finish() + driver := mock_driver.NewMockIdentityServer(m) + + // Setup input + in := &csi.GetPluginInfoRequest{} + + // Setup mock outout + out := &csi.GetPluginInfoResponse{ + Name: "mock", + VendorVersion: "0.1.1", + Manifest: map[string]string{ + "hello": "world", + }, + } + + // Setup expectation + // !IMPORTANT!: Must set context expected value to gomock.Any() to match any value + driver.EXPECT().GetPluginInfo(gomock.Any(), pbMatch(in)).Return(out, nil).Times(1) + + // Create a new RPC + server := mock_driver.NewMockCSIDriver(&mock_driver.MockCSIDriverServers{ + Identity: driver, + }) + conn, err := server.Nexus() + if err != nil { + t.Errorf("Error: %s", err.Error()) + } + defer server.Close() + + // Make call + c := csi.NewIdentityClient(conn) + r, err := c.GetPluginInfo(context.Background(), in) + if err != nil { + t.Errorf("Error: %s", err.Error()) + } + + name := r.GetName() + if name != "mock" { + t.Errorf("Unknown name: %s\n", name) + } +} + +func TestGRPCAttach(t *testing.T) { + + // Setup mock + m := gomock.NewController(&mock_utils.SafeGoroutineTester{}) + defer m.Finish() + driver := mock_driver.NewMockControllerServer(m) + + // Setup input + defaultVolumeID := "myname" + defaultNodeID := "MyNodeID" + defaultCaps := &csi.VolumeCapability{ + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER, + }, + } + publishVolumeInfo := map[string]string{ + "first": "foo", + "second": "bar", + "third": "baz", + } + defaultRequest := &csi.ControllerPublishVolumeRequest{ + VolumeId: defaultVolumeID, + NodeId: defaultNodeID, + VolumeCapability: defaultCaps, + Readonly: false, + } + + // Setup mock outout + out := &csi.ControllerPublishVolumeResponse{ + PublishInfo: publishVolumeInfo, + } + + // Setup expectation + // !IMPORTANT!: Must set context expected value to gomock.Any() to match any value + driver.EXPECT().ControllerPublishVolume(gomock.Any(), pbMatch(defaultRequest)).Return(out, nil).Times(1) + + // Create a new RPC + server := mock_driver.NewMockCSIDriver(&mock_driver.MockCSIDriverServers{ + Controller: driver, + }) + conn, err := server.Nexus() + if err != nil { + t.Errorf("Error: %s", err.Error()) + } + defer server.Close() + + // Make call + c := csi.NewControllerClient(conn) + r, err := c.ControllerPublishVolume(context.Background(), defaultRequest) + if err != nil { + t.Errorf("Error: %s", err.Error()) + } + + info := r.GetPublishInfo() + if !reflect.DeepEqual(info, publishVolumeInfo) { + t.Errorf("Invalid publish info: %v", info) + } +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/test/driver_test.go b/vendor/github.com/kubernetes-csi/csi-test/test/driver_test.go new file mode 100644 index 00000000..82080eb3 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/test/driver_test.go @@ -0,0 +1,127 @@ +/* +Copyright 2017 Luis Pabón luis@portworx.com + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package test + +import ( + "context" + "net" + "sync" + "testing" + + "github.com/container-storage-interface/spec/lib/go/csi/v0" + "github.com/kubernetes-csi/csi-test/utils" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +// Example simple driver +// This example assumes that your driver will create the server and listen on +// some unix domain socket or port for tests. +type simpleDriver struct { + listener net.Listener + server *grpc.Server + wg sync.WaitGroup +} + +func (s *simpleDriver) GetPluginCapabilities(context.Context, *csi.GetPluginCapabilitiesRequest) (*csi.GetPluginCapabilitiesResponse, error) { + // TODO: Return some simple Plugin Capabilities + return &csi.GetPluginCapabilitiesResponse{}, nil +} + +func (s *simpleDriver) Probe(context.Context, *csi.ProbeRequest) (*csi.ProbeResponse, error) { + return &csi.ProbeResponse{}, nil +} + +func (s *simpleDriver) GetPluginInfo( + context.Context, *csi.GetPluginInfoRequest) (*csi.GetPluginInfoResponse, error) { + return &csi.GetPluginInfoResponse{ + Name: "simpleDriver", + VendorVersion: "0.1.1", + Manifest: map[string]string{ + "hello": "world", + }, + }, nil +} + +func (s *simpleDriver) goServe() { + s.wg.Add(1) + go func() { + defer s.wg.Done() + s.server.Serve(s.listener) + }() +} + +func (s *simpleDriver) Address() string { + return s.listener.Addr().String() +} + +func (s *simpleDriver) Start() error { + // Listen on a port assigned by the net package + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return err + } + s.listener = l + + // Create a new grpc server + s.server = grpc.NewServer() + + csi.RegisterIdentityServer(s.server, s) + reflection.Register(s.server) + + // Start listening for requests + s.goServe() + return nil +} + +func (s *simpleDriver) Stop() { + s.server.Stop() + s.wg.Wait() +} + +// +// Tests +// +func TestSimpleDriver(t *testing.T) { + + // Setup simple driver + s := &simpleDriver{} + err := s.Start() + if err != nil { + t.Errorf("Error: %s", err.Error()) + } + defer s.Stop() + + // Setup a connection to the driver + conn, err := utils.Connect(s.Address()) + if err != nil { + t.Errorf("Error: %s", err.Error()) + } + defer conn.Close() + + // Make a call + c := csi.NewIdentityClient(conn) + r, err := c.GetPluginInfo(context.Background(), &csi.GetPluginInfoRequest{}) + if err != nil { + t.Errorf("Error: %s", err.Error()) + } + + // Verify + name := r.GetName() + if name != "simpleDriver" { + t.Errorf("Unknown name: %s\n", name) + } +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/utils/grpcutil.go b/vendor/github.com/kubernetes-csi/csi-test/utils/grpcutil.go new file mode 100644 index 00000000..20eebbc8 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/utils/grpcutil.go @@ -0,0 +1,59 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package utils + +import ( + "context" + "fmt" + "net" + "net/url" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/connectivity" +) + +// Connect address by grpc +func Connect(address string) (*grpc.ClientConn, error) { + dialOptions := []grpc.DialOption{ + grpc.WithInsecure(), + } + u, err := url.Parse(address) + if err == nil && (!u.IsAbs() || u.Scheme == "unix") { + dialOptions = append(dialOptions, + grpc.WithDialer( + func(addr string, timeout time.Duration) (net.Conn, error) { + return net.DialTimeout("unix", u.Path, timeout) + })) + } + + conn, err := grpc.Dial(address, dialOptions...) + if err != nil { + return nil, err + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + for { + if !conn.WaitForStateChange(ctx, conn.GetState()) { + return conn, fmt.Errorf("Connection timed out") + } + if conn.GetState() == connectivity.Ready { + return conn, nil + } + } +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/utils/safegoroutinetester.go b/vendor/github.com/kubernetes-csi/csi-test/utils/safegoroutinetester.go new file mode 100644 index 00000000..c89a5cf1 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/utils/safegoroutinetester.go @@ -0,0 +1,40 @@ +/* +Copyright 2017 Luis Pabón luis@portworx.com + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package utils + +import "fmt" + +// SafeGoroutineTester is an implementation of the mock ... interface +// which can be used to use the mock functions in another go routine. +// +// The major issue is that the golang mock framework uses t.Fatalf() +// which causes a deadlock when called in another goroutine. To avoid +// this issue, this simple implementation prints the error then panics, +// which avoids the deadlock. +type SafeGoroutineTester struct{} + +// Errorf prints the error to the screen then panics +func (s *SafeGoroutineTester) Errorf(format string, args ...interface{}) { + fmt.Printf(format, args) + panic("MOCK TEST ERROR") +} + +// Fatalf prints the error to the screen then panics +func (s *SafeGoroutineTester) Fatalf(format string, args ...interface{}) { + fmt.Printf(format+"\n", args...) + panic("MOCK TEST FATAL FAILURE") +}